托管函数的挂钩(完美版)

原文:http://blog.csdn.net/cstod/article/details/6262506

CLR Injection: Runtime Method Replacer

http://www.codeproject.com/Articles/37549/CLR-Injection-Runtime-Method-Replacer

CLR Injection: Modify IL Code during Run-time

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;

        }

    }

}

 

你可能感兴趣的:(函数)