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

使用push/retn方法Hook函数失败问题排查(VS2017+Win10)

排查Push/Retn Hook未生效问题(Win10 + VS2017环境)

我在Win10+VS2017环境里复现了你的代码,确实会出现编译运行正常但Hook未生效的情况,核心原因和解决方法如下:

问题根源分析

你的Hook思路本身是可行的:用push hookproc地址 + retn的指令替换原函数开头,让调用原函数时跳转到Hook函数。但VS2017的默认编译器优化会破坏这个逻辑:

  • 函数内联优化:因为main函数里直接调用func(),编译器默认会把func的代码内联到main中,导致你修改func地址处的指令根本不会被执行,程序实际跑的是内联后的MessageBox代码。
  • 另外,虽然你加了#pragma comment(linker, "/SECTION:.text,ERW")来设置.text段可写,但部分场景下编译器的额外处理可能让这个设置未完全生效,不过这不是本次问题的主因。

解决方法及修改后的代码

针对内联优化和内存保护问题,修改代码如下:

#include "pch.h"
#include <iostream>
#include<Windows.h>
#pragma comment(linker, "/SECTION:.text,ERW")

// 用__declspec(noinline)禁止编译器内联原函数
__declspec(noinline) void func() {
    MessageBox(0, L"not hook", L"info", MB_OK);
}

void hookproc() {
    MessageBox(0, L"hook success", L"info", MB_OK);
}

void hook_code() {
    BYTE* lpFunc1 = (BYTE*)func;
    DWORD oldProtect;

    // 手动修改内存保护属性,确保目标地址可写(双重保险)
    VirtualProtect(lpFunc1, 6, PAGE_EXECUTE_READWRITE, &oldProtect);

    // 写入Push+Retn指令
    lpFunc1[0] = 0x68; // push指令机器码
    *(ULONG_PTR*)&lpFunc1[1] = (ULONG_PTR)hookproc; // Hook函数地址
    lpFunc1[5] = 0xC3; // retn指令机器码

    // 恢复原内存保护属性(可选,但建议保持内存安全)
    VirtualProtect(lpFunc1, 6, oldProtect, &oldProtect);
}

int main() {
    hook_code();
    func();
    return 0;
}

关键修改点说明

  • __declspec(noinline):强制编译器不将func内联到main中,确保main里调用的是func的实际内存地址,这样你修改的指令才会被执行。
  • VirtualProtect:手动修改func所在内存页的保护属性为PAGE_EXECUTE_READWRITE,确保你能正常写入指令。虽然链接器选项已经尝试设置.text段可写,但手动调用VirtualProtect能避免编译器或系统的额外限制,更可靠。

验证方法

修改后编译运行,应该会弹出"hook success"对话框。如果还是有问题,可以用VS的调试器:

  1. 在hook_code函数末尾加断点,查看lpFunc1地址处的指令是否被成功修改为push 0xXXXXXXX(hookproc的地址)和retn。
  2. 在main里的func()调用处加断点,查看跳转地址是否是func的实际地址,而不是内联的代码。

内容的提问来源于stack exchange,提问作者赖敬之

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:27:23