Detours是Windows下API Hook最稳妥方案,需按DetourTransactionBegin→UpdateThread→Attach三步调用,Hook NTAPI需驱动或LdrLoadDll劫持,卸载须严格配对Detach并处理线程同步。

Windows下用Detours实现API Hook最省事
直接上结论:微软官方的 Detours 库是C++做底层API Hook最稳妥的选择,尤其拦截Win32 API(如 CreateFileA、Send、VirtualAlloc)时,它封装了x86/x64指令修补、跳转桩生成、线程安全等细节,比手写Inline Hook少踩90%的坑。
常见错误现象包括:进程崩溃(跳转地址错/没修复重定位)、Hook失效(只Hook了当前模块未处理延迟加载)、多线程下竞态(未加锁导致原函数指针被覆盖)。这些在Detours里基本由 DetourAttach 和 DetourTransactionBegin 自动处理。
- 必须用
DetourTransactionBegin+DetourUpdateThread(GetCurrentThread())+DetourAttach三步成套调用,漏掉任一环节都可能失败 - 拦截DLL导出函数时,要Hook的是目标DLL加载后的实际地址,不是静态导入表地址;Detours会自动解析,但你得确保DLL已加载(比如在
DllMain的DLL_PROCESS_ATTACH之后再Hook) - 64位程序必须用
Detours x64版本编译,且项目配置中禁用“增量链接”(/INCREMENTAL:NO),否则Link时会报LNK2019: unresolved external symbol _DetourAttach@8
自己写Inline Hook要注意指令边界和栈对齐
绕过Detours手动Hook,核心是改写目标函数开头几字节为跳转指令(jmp rel32 或 mov r11, imm64; jmp r11),但实际操作远不止“写5个字节”那么简单。
容易踩的坑集中在指令长度判断和上下文保存:比如Hook WriteFile 这类以 push ebp; mov esp, ebp 开头的函数,若只覆盖前6字节,可能切在一条指令中间,导致CPU解码错乱——必须用反汇编库(如 Capstone)或查MSDN确认函数入口的完整指令边界。
- 32位下优先用
jmp [rel32](5字节),64位必须用两指令组合(mov r10, imm64+jmp r10,共12字节),硬编码地址时注意符号扩展 - 被Hook函数若使用了
XMM寄存器或AVX指令,你的Hook桩必须显式保存/恢复对应寄存器(push xmm0等),否则下游调用会数据错乱 - Windows 10+ 启用CFG(Control Flow Guard)后,直接跳转到堆内存的Hook桩会被系统拦截,必须把桩代码分配在可执行页(
VirtualAlloc(..., PAGE_EXECUTE_READWRITE)),且调用SetProcessValidCallTarget注册地址(仅限特定场景)
拦截NTAPI(如NtCreateFile)需要驱动配合或LdrLoadDll劫持
用户态C++代码无法稳定Hook NtCreateFile 这类ntdll.dll导出的NTAPI:它们在进程启动时就被硬编码进PE导入表,且部分函数在内核模式下被直接调用(绕过用户态DLL),Detours默认Hook不到。
可行路径只有两条:要么写一个简单的KMDF驱动,在内核中用 MmGetSystemRoutineAddress 获取NTAPI地址并Inline Patch;要么在用户态用更底层的手段——Hook LdrLoadDll,等 ntdll.dll 加载完成后再动态解析其导出表,手动Patch内存。后者无需驱动,但稳定性差,容易被AMSI或EDR检测。
- 用
GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateFile")拿到地址后,仍需调用VirtualProtect改写内存属性为PAGE_EXECUTE_READWRITE才能写入跳转指令 - 某些安全软件会监控
ntdll.dll的内存页保护变更,触发STATUS_ACCESS_VIOLATION或主动杀进程,建议在Hook前后插入随机sleep或混淆写内存逻辑 - 不要试图Hook
Zw*函数名——它们只是Nt*的别名,实际指向同一地址,Hook一个就够了
释放Hook时忘记清理会导致后续调用崩溃
很多人只记得Hook,却忽略卸载。Detours提供 DetourDetach,但必须保证传入的仍是当初 DetourAttach 用的那一对指针(原函数地址 + 替换函数地址),顺序反了或指针错了,会导致跳转表损坏,后续任何调用该API的线程都会崩。
更隐蔽的问题是:如果Hook期间有其他线程正在执行被Hook的函数,此时卸载会引发“正在执行的代码被修改”,结果不可预测。Detours内部用SuspendThread同步,但仍有窗口期。
- 务必在
DLL_PROCESS_DETACH或程序退出前调用完整的Detour卸载流程:DetourTransactionBegin→DetourUpdateThread→DetourDetach→DetourTransactionCommit - 若用自定义Inline Hook,卸载时不仅要恢复原指令,还要确保恢复长度与Hook时完全一致(比如你写了12字节跳转,就得原样覆写回12字节原始机器码,不能只写前5字节)
- 多次重复Hook同一函数(比如插件热加载)极易导致指令覆盖混乱,建议用引用计数管理Hook状态,避免无脑Attach/Detach
真正难的从来不是怎么跳过去,而是怎么让跳回来的过程不被发现、不被干扰、不留下痕迹——尤其是跨模块、跨线程、跨权限层级时,每个内存页保护、每条指令对齐、每次线程挂起,都得拿捏到字节级。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











