.NET笔记:挂钩JIT获取编译的方法句柄、本机代码地址和部分方法名称
本帖最后由 鲲鹏 于 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`虚表等多种方式实现,这里不再赘述。目标方法为非托管。
#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`方法。
#pragma managed(push, on)
void FuncInternal(void *ptr)
{
IntPtr methodHandleValue = IntPtr(ptr);
ClassLibrary1::Class1::Func(methodHandleValue);
}
#pragma managed(pop)
C#代码如下。`GetRuntimeMethodHandle`将方法句柄原始数据转为`RuntimeMethodHandle`。`Func`输出方法名称。
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
{
// 需要注意的是,仅符合条件的部分方法可以完成转换。如泛型等会引发异常。
}
}
}
}
感谢分享思路 每个字都认识,连起来一起读就闷逼了https://cdn.jsdelivr.net/gh/master-of-forums/master-of-forums/public/images/patch.gif 楼主厉害,向你学习 楼主厉害 楼主厉害
感谢发布原创作品,PYG有你更精彩! 学习了,感谢提供分享! PYG有你更精彩!
页:
[1]