1、IAT钩取工作原理
进程的IAT中保存着程序中调用的API的地址,IAT钩取通过修改IAT中保存的API地址来钩取某个API。
图中描述的是计算器(calc.exe)进程正常调用user32.SetWindowTextW()API的情形。地址01001110属于IAT区域,程序开始运行时,PE装载器会将user32.SetWindowTextW()API地址(77D0960E)记录到该地址(01001110)。01002628地址处的CALL DWORD PTR [01001110]指令最终会调用保存在01001110地址(77D0960E)处的函数,直接等同于CALL 77D0960E命令。
执行完地址01002628处的CALL命令后,运行将转移到user32.SetWindowTextW()函数的起始地址(77D0960E)处,执行完user32.SetWindowTextW()后返回。
下图是IAT被钩取后计算器进程的运行过程。
hookiat.dll文件中通过了了名为MySetWindowTextW()的钩取函数(10001000)。地址01002628处的CALL指令执行后,会跟踪进入10001000,而不是01001110。经过一系列的处理后,执行1000107D处的CALL命令,转到原user32.SetWindowTextW()函数的起始地址。user32.SetWindowTextW()API执行完毕后,执行会返回到hookiat.dll的1000107D地址的下雨天指令,然后返回到01002628地址的下一条指令继续执行。
2、演示示例
(1)calc.exe
(2)hookiat.dll
(3)InjectDll.exe
1 | InjectDll.exe i pID hookiat.dll //钩取命令 |
钩取后程序运行的样子:
3、源代码分析
1、DllMain()
1 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) |
2、MySetWindowTextW()
1 | BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString) |
SetWindowTextW()API定义如下:
1 | BOOL SetWindowTextW( |
它有两个参数,第一个为窗口句柄(hWnd),第二个参数为字符串指针(lpString)。
阿拉伯数字字符串转换为中文数字字符串情形如下:
3、hook_iat()
1 | BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew) |
hook_iat()函数的前半部分用来读取PE文件头信息,并查找IAT的位置。
1 | hMod = GetModuleHandle(NULL); // hMod = ImageBase |
找到IMAGE_IMPORT_DESCRIPTOR表后,用for循环遍历,查找user32.dll的IAT。pImportDesc->FirstThunk成员所指的就是IAT。然后再循环遍历,查找SetWindowTextW的位置。找到后,修改为MySetWindowTextW的地址。
1 | pThunk->u1.Function = (DWORD)pfnNew; |
这样,计算器代码调用user32.SetWindowTextW()API时,实际会先调用hookiat.MySetWindowTextW()函数。