C++如何在运行时修改已加载DLL内外部函数的返回值
实现方案(Windows原生API,无第三方依赖)
核心原理
我们可以通过**inline hook(内存指令修改)**实现需求,不需要修改DLL源文件,也不需要引入任何外部库,全程使用Windows系统自带的API完成。核心逻辑是直接修改numberOfMoney函数在内存中的入口指令,让它直接返回1000。
具体实现步骤
- 拿到目标函数的内存地址(你已经通过
GetProcAddress拿到了gotFunc) - 修改函数所在内存页的保护属性,默认代码段是只读不可写的,需要用
VirtualProtect改成可写权限 - 向函数入口写入我们构造的汇编指令,实现直接返回1000的逻辑
- 恢复内存页的原有保护属性,避免触发内存访问异常
完整代码示例
#include <windows.h> #include <stdio.h> #include <string.h> int main() { HMODULE handle = LoadLibraryA("/myDll.dll"); if (!handle) { printf("加载DLL失败\n"); return 1; } auto gotFunc = GetProcAddress(handle, "numberOfMoney"); if (!gotFunc) { printf("获取函数地址失败\n"); FreeLibrary(handle); return 1; } // 构造返回1000的指令,x86和x64下int类型返回值1000通用 // 指令对应逻辑: mov eax, 1000(1000的十六进制为0x3E8)→ ret BYTE newCode[] = {0xB8, 0xE8, 0x03, 0x00, 0x00, 0xC3}; DWORD oldProtect; // 修改内存权限为可执行可读写 if (!VirtualProtect(gotFunc, sizeof(newCode), PAGE_EXECUTE_READWRITE, &oldProtect)) { printf("修改内存权限失败\n"); FreeLibrary(handle); return 1; } // 写入新的指令 memcpy(gotFunc, newCode, sizeof(newCode)); // 恢复内存原有保护属性 VirtualProtect(gotFunc, sizeof(newCode), oldProtect, &oldProtect); // 测试调用,此时返回值为1000 int result = ((int(*)())gotFunc)(); printf("函数返回值: %d\n", result); FreeLibrary(handle); return 0; }
注意事项
- 该修改仅生效于当前运行的进程,不会修改硬盘上的DLL源文件,进程退出后修改自动失效
- 依赖的
VirtualProtect、memcpy都是系统自带的标准API/库函数,不需要引入任何第三方依赖 - 如果目标函数已经被其他Hook逻辑修改过开头指令,该方案会和原有Hook冲突
- 如果需要返回超过int范围的大数,x64下需要把指令调整为
mov rax, 目标数值对应的机器码即可
内容的提问来源于stack exchange,提问作者Donald C. Spencer
相关产品推荐
相关产品推荐

