前言:
pe中的hook技术是指通过 DLL 注入(例如 CreateRemoteThread 注入、SetWindowsHookEx、frida-gadget 等实现方式)将代码注入目标进程,替换目标exe文件中的某个函数为自己的函数,而在这过程中我们没办法获得目标exe源码,只能用另一个进程去操作目标进程。本篇记录了IAT HOOK和inline hook。在日常生活中hook更多还是用frida的插桩技术实现(封装好了),不过底层hook的机制还是要了解,因为frida一旦被全方位检测拦截就没招了
注意:代码来自文末链接,但他讲的有问题,我把正确的代码改进后放在我的文章了
IAT hook
原理:
进程运行时IAT表里存储了我们函数的真实地址rva,我们如果用注入的dll更改IAT里的地址为我们dll里实现的函数地址,就实现了hook。相当于elf文件中的got表劫持
头文件:
1 |
|
1 |
|
我们可以随便写个主进程函数,然后把这个dll文件注入看能否hook成功。注入dll的方式有很多,可以看我注入dll的那篇。当然最简单是用github上别人造好的轮子来搞dll注入。这里放一个我觉得还不错的项目GitHub - Joe1sn/S-inject: 支持x86/x64的DLL和Shellcode 的Windows注入的免杀工具,支持图形化界面
主进程函数:
1 | // main.c |
复现成功了,我把复现过程的问题列下面:
可能出现问题1:
1 | int WINAPI hookMessageboxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) |
这里面hook时用的MessageBoxW,会导致循环调用,会卡死
定义hookMessageboxW时没加WINAPI ,这会导致调用约定不一致,会报错
可能出现问题2:
不要用他视频里的DWORD来一味声明,不然64位系统里地址是64位,会被截断导致地址错误
可能出现问题3:
1 | if (strcmp((char*)pIBN->Name, funcname) == 0) |
症状:函数查找失败(总找不到目标函数)。
原因:pIBN->Name == funcname 比较的是地址而非内容。
修复:用 _stricmp((char*)pIBN->Name, funcname) 或 strcmp(按是否区分大小写)。
inline hook
上面的IAT表有个问题,就是不在导入表里的函数你没办法hook啊,所以inline hook就是用来解决这个问题的。
- 原理:
直接修改目标函数的前几条机器指令(通常是函数入口),替换成跳转指令(如 b
- 优点:
可以 Hook 几乎任意函数(导出或非导出、静态或动态)
精细控制,适合保护/加壳/代码注入等底层用途
- 缺点:
对 CPU 架构高度依赖(ARM64、ARMv7)
对汇编、内存保护、缓存等有要求(必须关闭写保护)
稳定性较低,不当使用可能 crash
代码:
main.h
1 |
|
main.cpp
1 |
|
Reference:
【【保姆级教程】16 节吃透 Windows PE 文件格式!从解析到 Hook 攻防全覆盖】https://www.bilibili.com/video/BV1cXT4z7Etf?p=8&vd_source=ef1be23ebedc3f547905767af45d9f93