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; } } } } }