You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++如何在运行时修改已加载DLL内外部函数的返回值

实现方案(Windows原生API,无第三方依赖)

核心原理

我们可以通过**inline hook(内存指令修改)**实现需求,不需要修改DLL源文件,也不需要引入任何外部库,全程使用Windows系统自带的API完成。核心逻辑是直接修改numberOfMoney函数在内存中的入口指令,让它直接返回1000。

具体实现步骤

  1. 拿到目标函数的内存地址(你已经通过GetProcAddress拿到了gotFunc)
  2. 修改函数所在内存页的保护属性,默认代码段是只读不可写的,需要用VirtualProtect改成可写权限
  3. 向函数入口写入我们构造的汇编指令,实现直接返回1000的逻辑
  4. 恢复内存页的原有保护属性,避免触发内存访问异常

完整代码示例

#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 06:27:04