| 本帖最后由 鲲鹏 于 2024-12-30 21:32 编辑 
 流程如下。
 
 1. 挂钩JIT,获取`methodInfo`结构体中的`ftn`成员,该成员有关方法句柄原始数据。获取`entryAddress`参数,该参数有关本机代码地址。
 2. 将方法句柄原始数据转为`RuntimeMethodHandle`。需要注意的是,仅符合条件的部分方法可以完成转换。如泛型等会引发异常。
 3. 根据`RuntimeMethodHandle`得到`MethodBase`。此时已经可以通过`Name`属性获取方法名称。
 4. (可选)使用`dnlib`获取更为详细的方法名称。
 
 不妨使用C++/CLI和C#混合编程。首先使用C++/CLI编写挂钩JIT。我们选取`compileMethod`位置进行挂钩,定位该位置可通过符号文件或`getJit`虚表等多种方式实现,这里不再赘述。目标方法为非托管。
 
 [C++] 纯文本查看 复制代码 #pragma managed(push, off)
int __stdcall Hook_compileMethod(void *self, void *compHnd, void *methodInfo, unsigned int flags,
                                 unsigned char **entryAddress, unsigned long *nativeSizeOfCode)
{
    thread_local int recursionFlag = 0;
    int retval = Orig_compileMethod(self, compHnd, methodInfo, flags, entryAddress, nativeSizeOfCode);
    if (recursionFlag)
        return retval;
    if (retval == 0)
    {
        // 获取`methodInfo`结构体中的`ftn`成员,该成员有关方法句柄原始数据。
        void *methodInfo_ftn = *(void **)methodInfo;
        // 获取`entryAddress`参数,该参数有关本机代码地址。
        printf("%p\n", *entryAddress);
        recursionFlag++;
        FuncInternal(methodInfo_ftn);
        recursionFlag--;
    }
    return retval;
}
#pragma managed(pop)
其中,`FuncInternal`完成方法名称输出工作。该方法为托管。为了演示C++/CLI和C#混合编程的便捷性,我们调用了C#编写的`Func`方法。
 
 [C++] 纯文本查看 复制代码 #pragma managed(push, on)
void FuncInternal(void *ptr)
{
    IntPtr methodHandleValue = IntPtr(ptr);
    ClassLibrary1::Class1::Func(methodHandleValue);
}
#pragma managed(pop)
C#代码如下。`GetRuntimeMethodHandle`将方法句柄原始数据转为`RuntimeMethodHandle`。`Func`输出方法名称。
 
 [C#] 纯文本查看 复制代码 namespace ClassLibrary1
{
    public class Class1
    {
        public static RuntimeMethodHandle GetRuntimeMethodHandle(IntPtr methodHandleValue)
        {
            var asm = typeof(RuntimeMethodHandle).Assembly;
            var method = asm.CreateInstance("System.RuntimeMethodInfoStub",
                                            false,
                                            BindingFlags.Instance | BindingFlags.Public,
                                            null,
                                            new object[] { methodHandleValue, null },
                                            null,
                                            null);
            var handle = (RuntimeMethodHandle)asm.CreateInstance("System.RuntimeMethodHandle",
                                                                 false,
                                                                 BindingFlags.Instance | BindingFlags.NonPublic,
                                                                 null,
                                                                 new object[] { method },
                                                                 null,
                                                                 null);
            return handle;
        }
        public static void Func(IntPtr methodHandleValue)
        {
            try
            {
                // 将方法句柄原始数据转为`RuntimeMethodHandle`。
                var handle = GetRuntimeMethodHandle(methodHandleValue);
                var mb = MethodBase.GetMethodFromHandle(handle);
                // 通过`Name`属性获取方法名称。
                Console.WriteLine(mb.Name);
                // (可选)使用`dnlib`获取更为详细的方法名称。
                ModuleDefMD moduleDefMD = ModuleDefMD.Load(mb.Module);
                MethodDef methodDef = (MethodDef)moduleDefMD.ResolveToken(mb.MetadataToken);
                Console.WriteLine(methodDef.FullName);
            }
            catch
            {
                // 需要注意的是,仅符合条件的部分方法可以完成转换。如泛型等会引发异常。
            }
        }
    }
}
 
 
 |