DetourFindFunction()寻址失败及静态链接、内联函数Detour相关疑问
关于DetourFindFunction()及Microsoft Detours的常见问题解答
1. 为啥DetourFindFunction()找不到函数地址?
DetourFindFunction()主要靠解析目标模块的导出表,或者在有调试符号时通过符号查找来定位函数。找不到地址的常见原因有这些:
- 目标函数不是模块的导出函数:只有用
__declspec(dllexport)标记(或通过.def文件导出)的函数才会出现在导出表里,这是它优先查找的渠道。 - 目标函数是静态链接的私有函数(无导出、无调试符号):如果是模块内部的静态函数,又没生成PDB调试符号,DetourFindFunction()根本找不到它的踪迹。
- 模块被加壳/混淆了:加壳工具会篡改模块的导出表和内存布局,自然没法正常解析函数地址。
2. 微软FAQ说静态链接函数没法Detour,但我能Hook自己的静态库函数,这咋回事?
微软FAQ里的说法其实是针对系统级静态链接函数(比如CRT的malloc)的场景,而你能成功Hook自己的静态库函数,核心原因是场景差异:
- 你的静态库项目生成了完整的PDB调试符号:DetourFindFunction()在导出表里找不到目标时,会尝试加载目标模块的PDB查符号。你自己的静态库函数在PDB里有完整的符号信息,所以能被定位到。
- 你的静态库函数没被编译器优化“没影”:如果编译器没对静态函数做极端优化(比如完全内联、删除未引用函数),函数的地址会保留在PDB中,Detour就能正常识别。
微软强调的是“无法Hook静态链接的系统函数”——比如CRT的malloc如果是静态链接到程序中,会被嵌入到程序内部,没有导出符号,而且系统CRT的PDB一般不会被普通程序加载,所以Detour找不到。而你自己的静态库完全可控,符号齐全,自然能实现Hook。
3. 开了内联函数展开后,DetourFindFunction()就找不到地址了,为啥?
当Visual Studio启用**内联函数展开(/Ob1或/Ob2)**时,编译器会把符合条件的函数直接嵌入到调用它的代码中,不会在内存里保留独立的函数体:
- 内联后的函数没有独立的内存地址:编译器直接把函数指令替换到调用点,原函数的符号可能会从PDB里被移除(或标记为“已内联”),DetourFindFunction()总不能定位一个不存在的地址吧。
- 就算有些内联函数留了符号,那地址可能也只是个“调试桩函数”,不是实际执行的代码,Detour这类工具Hook桩函数根本起不到作用。
4. 还有啥别的方法找函数地址?
如果DetourFindFunction()不好使,试试这几个办法:
- 直接拿地址(自己的代码最靠谱):编译时直接用
&函数名获取地址,传给DetourAttach(),完全不依赖导出表或符号,稳得一批。 - 用DbgHelp API查符号:调用DbgHelp库的
SymInitialize()、SymFromName()等函数,手动加载目标模块的PDB查找符号地址,逻辑和DetourFindFunction()的符号查找类似,但更灵活。 - 特征码扫描:如果目标函数没导出也没符号,可以扫描内存里函数开头的特征指令序列来定位地址,但这方法容易受编译器优化、代码版本影响,稳定性差,迫不得已再用。
- 改编译配置导出函数:如果是自己的代码,把要Hook的函数标记成
__declspec(dllexport),让它出现在导出表里,这样DetourFindFunction()或者GetProcAddress()都能轻松找到。
内容的提问来源于stack exchange,提问作者SolidMercury
相关产品推荐
相关产品推荐

