using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace MethodHookSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Target target = new Target();
            var methodAdd = typeof(Target).GetMethod("Add", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            var methodMinus = typeof(Target).GetMethod("Minus", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            MethodHooker.HookMethod(methodAdd, methodMinus);
            var result = target.Add(5, 4);
            Console.Write("5 + 4 = " + result);
            Console.Read();
        }
    }

    public class Target
    {
        [MethodImpl(MethodImplOptions.NoInlining)]
        public int Add(int a, int b)
        {
            return a + b;
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public int Minus(int a, int b)
        {
            return a - b;
        }
    }

    public class MethodHooker
    {
        public static void HookMethod(MethodInfo sourceMethod, MethodInfo destinationMethod)
        {
            RuntimeHelpers.PrepareMethod(sourceMethod.MethodHandle);
            RuntimeHelpers.PrepareMethod(destinationMethod.MethodHandle);

            if (sourceMethod.IsVirtual)
            {
                HookVirtualMethod(sourceMethod, destinationMethod);
                return;
            }

            unsafe
            {
                if (IntPtr.Size == 4)
                {
                    int* inj = (int*)destinationMethod.MethodHandle.Value.ToPointer() + 2;
                    int* tar = (int*)sourceMethod.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
                    Console.WriteLine("\nVersion x86 Debug\n");

                    byte* injInst = (byte*)*inj;
                    byte* tarInst = (byte*)*tar;

                    int* injSrc = (int*)(injInst + 1);
                    int* tarSrc = (int*)(tarInst + 1);

                    *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
                    Console.WriteLine("\nVersion x86 Release\n");
                    *tar = *inj;
#endif
                }
                else
                {
                    long* inj = (long*)destinationMethod.MethodHandle.Value.ToPointer() + 1;
                    long* tar = (long*)sourceMethod.MethodHandle.Value.ToPointer() + 1;
                    Console.WriteLine("\nVersion x64 Release\n");
                    *tar = *inj;
                }
            }
        }

        static void HookVirtualMethod(MethodInfo sourceMethod, MethodInfo destinationMethod)
        {
            unsafe
            {
                UInt64* methodDesc = (UInt64*)(sourceMethod.MethodHandle.Value.ToPointer());
                int index = (int)(((*methodDesc) >> 32) & 0xFF);
                if (IntPtr.Size == 4)
                {
                    uint* classStart = (uint*)sourceMethod.DeclaringType.TypeHandle.Value.ToPointer();
                    classStart += 10;
                    classStart = (uint*)*classStart;
                    uint* tar = classStart + index;
                    uint* inj = (uint*)destinationMethod.MethodHandle.Value.ToPointer() + 2;
                    *tar = *inj;
                }
                else
                {
                    ulong* classStart = (ulong*)sourceMethod.DeclaringType.TypeHandle.Value.ToPointer();
                    classStart += 8;
                    classStart = (ulong*)*classStart;
                    ulong* tar = classStart + index;
                    ulong* inj = (ulong*)destinationMethod.MethodHandle.Value.ToPointer() + 1;
                    *tar = *inj;
                }
            }
        }
    }
}
12-14 00:01