原文:http://blog.csdn.net/cstod/article/details/6262506
CLR Injection: Runtime Method Replacer
http://www.codeproject.com/Articles/37549/CLR-Injection-Runtime-Method-Replacer
http://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time
我之前发过一篇叫“托管函数的挂钩”的文章,实现了对MarshalByRefObject继承树下的实例函数的挂钩。
最近,在CodeProject上看到一个关于托管函数挂钩的文章,发现作者的方法很好用,但是正好不能用于MarshalByRefObject继承树下的实例函数(作者本人并没有发现这个问题),于是两种方法正好互补。
你也许要用,我为什么要强调MarshalByRefObject继承树呢?这是因为非常多的类都存在于该类的继承树下,比如很多人习惯把代码写在自己的窗体类中,而Form就在MarshalByRefObject树下,从我的实际经验来看,它比非MarshalByRefObject继承树的范围更广。
我对两种代码进行了封装,使用时只需调用ManagedReplacer.Replace方法即可。
说明:托管函数在第一次被调用时会被JIT成本地代码,之后会复用被JIT的本地代码,所以一定要在函数被JIT之前进行挂钩,否则将无效。
namespace ManagedHook { internal static class FrameworkVersions { internal static readonly Version Net35 = new Version(3, 5, 21022, 8); internal static readonly Version Net35SP1 = new Version(3, 5, 30729, 1); internal static readonly Version Net30 = new Version(3, 0, 4506, 30); internal static readonly Version Net30SP1 = new Version(3, 0, 4506, 648); internal static readonly Version Net30SP2 = new Version(3, 0, 4506, 2152); internal static readonly Version Net20 = new Version(2, 0, 50727, 42); internal static readonly Version Net20SP1 = new Version(2, 0, 50727, 1433); internal static readonly Version Net20SP2 = new Version(2, 0, 50727, 3053); } internal static class MethodUtil { internal static void ReplaceMethod(MethodBase source, MethodBase dest) { if (!MethodSignaturesEqual(source, dest)) { throw new ArgumentException("The method signatures are not the same.", "source"); } ReplaceMethod(GetMethodAddress(source), dest); } internal static void ReplaceMethod(IntPtr srcAdr, MethodBase dest) { IntPtr destAdr = GetMethodAddress(dest); unsafe { if (IntPtr.Size == 8) { ulong* d = (ulong*)destAdr.ToPointer(); *d = *((ulong*)srcAdr.ToPointer()); } else { uint* d = (uint*)destAdr.ToPointer(); *d = *((uint*)srcAdr.ToPointer()); } } } internal static IntPtr GetMethodAddress(MethodBase method) { if ((method is DynamicMethod)) { return GetDynamicMethodAddress(method); } RuntimeHelpers.PrepareMethod(method.MethodHandle); if (IsNet20Sp2OrGreater()) { return GetMethodAddress20SP2(method); } unsafe { const int skip = 10; UInt64* location = (UInt64*)(method.MethodHandle.Value.ToPointer()); int index = (int)(((*location) >> 32) & 0xFF); if (IntPtr.Size == 8) { ulong* classStart = (ulong*)method.DeclaringType.TypeHandle.Value.ToPointer(); ulong* address = classStart + index + skip; return new IntPtr(address); } else { uint* classStart = (uint*)method.DeclaringType.TypeHandle.Value.ToPointer(); uint* address = classStart + index + skip; return new IntPtr(address); } } } private static IntPtr GetDynamicMethodAddress(MethodBase method) { unsafe { RuntimeMethodHandle handle = GetDynamicMethodRuntimeHandle(method); byte* ptr = (byte*)handle.Value.ToPointer(); if (IsNet20Sp2OrGreater()) { RuntimeHelpers.PrepareMethod(handle); if (IntPtr.Size == 8) { ulong* address = (ulong*)ptr; address = (ulong*)*(address + 5); return new IntPtr(address + 12); } else { uint* address = (uint*)ptr; address = (uint*)*(address + 5); return new IntPtr(address + 12); } } else { if (IntPtr.Size == 8) { ulong* address = (ulong*)ptr; address += 6; return new IntPtr(address); } else { uint* address = (uint*)ptr; address += 6; return new IntPtr(address); } } } } private static RuntimeMethodHandle GetDynamicMethodRuntimeHandle(MethodBase method) { if (method is DynamicMethod) { FieldInfo fieldInfo = typeof(DynamicMethod).GetField("m_method", BindingFlags.NonPublic | BindingFlags.Instance); RuntimeMethodHandle handle = ((RuntimeMethodHandle)fieldInfo.GetValue(method)); return handle; } return method.MethodHandle; } private static IntPtr GetMethodAddress20SP2(MethodBase method) { unsafe { return new IntPtr(((int*)method.MethodHandle.Value.ToPointer() + 2)); } } private static bool MethodSignaturesEqual(MethodBase x, MethodBase y) { if (x.CallingConvention != y.CallingConvention) { return false; } Type returnX = GetMethodReturnType(x), returnY = GetMethodReturnType(y); if (returnX != returnY) { return false; } ParameterInfo[] xParams = x.GetParameters(), yParams = y.GetParameters(); if (xParams.Length != yParams.Length) { return false; } for (int i = 0; i < xParams.Length; i++) { if (xParams[i].ParameterType != yParams[i].ParameterType) { return false; } } return true; } private static Type GetMethodReturnType(MethodBase method) { MethodInfo methodInfo = method as MethodInfo; if (methodInfo == null) { throw new ArgumentException("Unsupported MethodBase : " + method.GetType().Name, "method"); } return methodInfo.ReturnType; } private static bool IsNet20Sp2OrGreater() { return Environment.Version.Major == FrameworkVersions.Net20SP2.Major && Environment.Version.MinorRevision >= FrameworkVersions.Net20SP2.MinorRevision; } } public class ManagedReplacer { private unsafe static void Hook(MethodBase oldMethod, MethodBase newMethod) { IntPtr oldAddress = oldMethod.MethodHandle.GetFunctionPointer(); IntPtr newAddress = newMethod.MethodHandle.GetFunctionPointer(); *(int*)oldAddress = *(int*)newAddress; } public static void Replace(MethodBase oldMethod, MethodBase newMethod) { Type mbroType = typeof(MarshalByRefObject); Type oldType = oldMethod.DeclaringType; Type newType = newMethod.DeclaringType; if ((oldMethod.IsStatic && newMethod.IsStatic) || (!mbroType.IsAssignableFrom(oldType) && !mbroType.IsAssignableFrom(newType))) MethodUtil.ReplaceMethod(newMethod, oldMethod); else if (mbroType.IsAssignableFrom(oldType) && mbroType.IsAssignableFrom(newType)) Hook(oldMethod, newMethod); else throw new Exception("函数不匹配"); } } }
.net framework 4.0使用以下代码:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace dev.crack { public class MagicHook { public static void ReplaceMethod(MethodBase method_old, MethodBase method_new) { if (!MethodSignaturesEqual(method_new, method_old)) throw new ArgumentException("The method signatures are not the same.", "source"); var srcAdr = GetMethodAddress(method_new); var destAdr = GetMethodAddress(method_old); unsafe { if (IntPtr.Size == 8) { ulong* d = (ulong*)destAdr.ToPointer(); *d = *((ulong*)srcAdr.ToPointer()); } else { uint* d = (uint*)destAdr.ToPointer(); *d = *((uint*)srcAdr.ToPointer()); } } } public static IntPtr GetMethodAddress(MethodBase method) { RuntimeHelpers.PrepareMethod(method.MethodHandle); unsafe { return new IntPtr(((int*)method.MethodHandle.Value.ToPointer() + 2)); } } private static bool MethodSignaturesEqual(MethodBase x, MethodBase y) { var xinfo = x as MethodInfo; var yinfo = y as MethodInfo; if (x.CallingConvention != y.CallingConvention) { return false; } if (xinfo.ReturnType != yinfo.ReturnType) { return false; } ParameterInfo[] xParams = x.GetParameters(), yParams = y.GetParameters(); if (xParams.Length != yParams.Length) { return false; } //for (int i = 0; i < xParams.Length; i++) //{ // if (xParams[i].ParameterType != yParams[i].ParameterType) // { // return false; // } //} return true; } } }