如何从委托中获取函数内存地址
How to get a function memory address from a Delegate
我想从同一进程中加载的 DLL 挂钩一个函数,因此每次调用该函数时,我的自定义函数都会被执行。
为了做到这一点,我声明了一个虚拟函数,它将被执行以替换 DLL 中的原始函数:
public static bool hookFunc(string a, ulong b, string c, IntPtr d)
{
Console.WriteLine("hi");
return true;
}
之后,我声明了一个 Delegate
并生成了一个指向我的 hookFunc 函数的新实例,然后我使用 [= =14=]。我还生成了将用于修补原始函数内存的字节序列,并使用函数的内存地址 hookFunc(从新指针获得)完成此序列:
public delegate bool hookDel(string a, ulong b, string c, IntPtr d);
public void hookManager()
{
var a = new hookDel(hookFunc);
var hookPtr = Marshal.GetFunctionPointerForDelegate(a);
var hookPointerBytes = BitConverter.GetBytes(hookPtr.ToInt64());
newBytes = new byte[] { 0x49, 0xbb, hookPointerBytes[0], hookPointerBytes[1], hookPointerBytes[2], hookPointerBytes[3], hookPointerBytes[4], hookPointerBytes[5],
hookPointerBytes[6], hookPointerBytes[7], 0x41, 0xff, 0xe3 };
}
此时变量newBytes
翻译成汇编的内容应该是如下指令:
mov r11, [memory address of my hookFunc function]
jmp r11
最后,我使用 GetProcAddress 获取原始 DLL 的函数内存地址,并使用 WriteProcessMemory 修补第一个字节,使用变量 newBytes
的内容进行替换。在收到几个 Whosebug 错误后,我用 WinDbg 调试了代码,我发现变量 hookPointerBytes
不包含 hookFunc[=39= 的地址],因此当钩子被触发时,jmp
指令将代码执行流驱动到没有可执行代码的内存地址,这可能是我的程序崩溃的原因。
我已验证 DLL 的函数挂钩已成功完成并且正在执行 jmp
指令。我的问题是,为什么我不能使用从Delegate
获得的指针获得hookFunc的真实内存地址?在 C# 中还有其他方法可以获取我的 hookFunc 函数的内存地址吗?
我不确定您是否打算在没有不安全代码的情况下使它正常工作。
我认为您将需要一个非托管指针,您可以通过 IntPtr
.
上的 ToPointer
获得该指针
byte* pointer = (byte*) hookPtr.ToPointer();
for (int k = 0; k < 7; k++) {
newBytes[k+2] = *(pointer + k);
}
我自己没有尝试过,但是你可以在这里找到一个例子:https://github.com/wledfor2/PlayHooky
具体class:
https://github.com/wledfor2/PlayHooky/blob/master/HookManager.cs
我想从同一进程中加载的 DLL 挂钩一个函数,因此每次调用该函数时,我的自定义函数都会被执行。
为了做到这一点,我声明了一个虚拟函数,它将被执行以替换 DLL 中的原始函数:
public static bool hookFunc(string a, ulong b, string c, IntPtr d)
{
Console.WriteLine("hi");
return true;
}
之后,我声明了一个 Delegate
并生成了一个指向我的 hookFunc 函数的新实例,然后我使用 [= =14=]。我还生成了将用于修补原始函数内存的字节序列,并使用函数的内存地址 hookFunc(从新指针获得)完成此序列:
public delegate bool hookDel(string a, ulong b, string c, IntPtr d);
public void hookManager()
{
var a = new hookDel(hookFunc);
var hookPtr = Marshal.GetFunctionPointerForDelegate(a);
var hookPointerBytes = BitConverter.GetBytes(hookPtr.ToInt64());
newBytes = new byte[] { 0x49, 0xbb, hookPointerBytes[0], hookPointerBytes[1], hookPointerBytes[2], hookPointerBytes[3], hookPointerBytes[4], hookPointerBytes[5],
hookPointerBytes[6], hookPointerBytes[7], 0x41, 0xff, 0xe3 };
}
此时变量newBytes
翻译成汇编的内容应该是如下指令:
mov r11, [memory address of my hookFunc function]
jmp r11
最后,我使用 GetProcAddress 获取原始 DLL 的函数内存地址,并使用 WriteProcessMemory 修补第一个字节,使用变量 newBytes
的内容进行替换。在收到几个 Whosebug 错误后,我用 WinDbg 调试了代码,我发现变量 hookPointerBytes
不包含 hookFunc[=39= 的地址],因此当钩子被触发时,jmp
指令将代码执行流驱动到没有可执行代码的内存地址,这可能是我的程序崩溃的原因。
我已验证 DLL 的函数挂钩已成功完成并且正在执行 jmp
指令。我的问题是,为什么我不能使用从Delegate
获得的指针获得hookFunc的真实内存地址?在 C# 中还有其他方法可以获取我的 hookFunc 函数的内存地址吗?
我不确定您是否打算在没有不安全代码的情况下使它正常工作。
我认为您将需要一个非托管指针,您可以通过 IntPtr
.
ToPointer
获得该指针
byte* pointer = (byte*) hookPtr.ToPointer();
for (int k = 0; k < 7; k++) {
newBytes[k+2] = *(pointer + k);
}
我自己没有尝试过,但是你可以在这里找到一个例子:https://github.com/wledfor2/PlayHooky
具体class: https://github.com/wledfor2/PlayHooky/blob/master/HookManager.cs