IAT HOOK
HOOK
1.监控
2.行为改变
改变执行流,让函数先到我这里,获得优先执行权
思路
导入表中有个IAT表,在导入表结构中的FirstThunk.在调用一些API时,只要是LoadLibrary的dll,其中的API都会在IAT表中,我们可以通过IAT表来寻找我们想要"了解"的函数,并对其进行操作,比如将这个API替换成自己的函数,但是注意参数要相同,不然栈平衡不了。
我这里用简单的MessageBox来说明IAT HOOK问题
SetHook
1 DWORD SetIATHook(DWORD OldAddr,DWORD NewAddr) //oldAddr是原地址,NewAddr是我们自己的函数 2 { 3 DWORD dwImageBase = 0; 4 PIMAGE_DOS_HEADER pDosHeader; 5 PIMAGE_NT_HEADERS pNTHeader = NULL; 6 PIMAGE_FILE_HEADER pPEHeader = NULL; 7 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 8 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 9 PIMAGE_IMPORT_DESCRIPTOR pImport = NULL; 10 PDWORD pIATThunk = NULL; 11 DWORD oldProtected = 0; 12 bool Flag = FALSE; 13 14 dwImageBase = (DWORD)::GetModuleHandle(NULL); //获取进程基址 15 pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase; 16 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew); 17 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); 18 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); 19 pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase); //定位导入表 20 //定位IAT表 21 22 while (pImport->FirstThunk != 0 && Flag == FALSE) 23 { 24 pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase); 25 printf("%s\n", dwImageBase + pImport->Name); 26 while (*pIATThunk) 27 { 28 if (*pIATThunk == OldAddr) 29 { 30 VirtualProtect(pIATThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected); 31 *pIATThunk = NewAddr; 32 Flag = TRUE; 33 printf("Hook成功!\n"); 34 break; 35 } 36 printf("%x\n", pIATThunk); 37 pIATThunk++; 38 } 39 pImport++; 40 } 41 42 return Flag; 43 }
大体就是获取基址,定位导入表,IAT表,找到目标API,用我们自己的函数地址替换原来API函数地址
有一个关键的地方,30行需要改变可写属性,因为31行那个位置是不能写入的(0xc0000005),VirtualProtect然后最后一个参数必须要有值,不能是NULL,主要这个细节卡了一下
获取OldAddr
DWORD OldFunc = (DWORD)::GetProcAddress(LoadLibrary(L"USER32.dll"), "MessageBoxW");
UnSetHook
1 DWORD UnSetIATHook(DWORD OldAddr, DWORD NewAddr) 2 { 3 DWORD dwImageBase = 0; 4 PIMAGE_DOS_HEADER pDosHeader; 5 PIMAGE_NT_HEADERS pNTHeader = NULL; 6 PIMAGE_FILE_HEADER pPEHeader = NULL; 7 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 8 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 9 PIMAGE_IMPORT_DESCRIPTOR pImport = NULL; 10 PDWORD pIATThunk = NULL; 11 bool Flag = FALSE; 12 13 dwImageBase = (DWORD)::GetModuleHandle(NULL); //获取进程基址 14 pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase; 15 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew); 16 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); 17 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); 18 pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase); //定位导入表 19 20 while (pImport->FirstThunk != 0 && Flag == FALSE) 21 { 22 pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase); 23 while (*pIATThunk) 24 { 25 if (*pIATThunk == NewAddr) 26 { 27 *pIATThunk = OldAddr; 28 Flag = TRUE; 29 break; 30 } 31 pIATThunk++; 32 } 33 pImport++; 34 } 35 36 return Flag; 37 }
达到目的后要恢复原来的函数
自己希望执行的函数
1 int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) 2 { 3 printf("%x %s %ws %x\n", hWnd, lpText, lpCaption, uType); 4 5 typedef int (WINAPI* pMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT); 6 7 //int ret = MessageBox(hWnd, lpText, lpCaption, uType); 8 int ret = ((pMessageBox)OldFunc)(hWnd, lpText, lpCaption, uType); 9 10 printf("返回值%x", ret); 11 12 return ret; 13 }
参数一传进来,我们就可以接收,其实还可以改变参数等等,这里必须要定义函数指针,因为原来的MessageBox那个地址已经被我们改了,如果又使用API MessageBox的话(像我注释的那行),会进入死循环,我们想得到参数又不想干扰原来的功能,所以定义一个函数指针来调用原来那个"OldAddr"即MessageBox的地址
测试代码
int TestIATHOOK() { SetIATHook(OldFunc, (DWORD)MyMessageBoxW); MessageBox(NULL, L"HELLO", L"HACKER", MB_OK); UnSetIATHook(OldFunc, (DWORD)MyMessageBoxW); return 1; }
测试结果
完整代码
// IATHOOK.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <windows.h> DWORD OldFunc = (DWORD)::GetProcAddress(LoadLibrary(L"USER32.dll"), "MessageBoxW"); DWORD SetIATHook(DWORD OldAddr,DWORD NewAddr) { DWORD dwImageBase = 0; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNTHeader = NULL; PIMAGE_FILE_HEADER pPEHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; PIMAGE_IMPORT_DESCRIPTOR pImport = NULL; PDWORD pIATThunk = NULL; DWORD oldProtected = 0; bool Flag = FALSE; dwImageBase = (DWORD)::GetModuleHandle(NULL); //获取进程基址 pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase); //定位导入表 //定位IAT表 while (pImport->FirstThunk != 0 && Flag == FALSE) { pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase); while (*pIATThunk) { if (*pIATThunk == OldAddr) { VirtualProtect(pIATThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected); *pIATThunk = NewAddr; Flag = TRUE; printf("Hook成功!\n"); break; } pIATThunk++; } pImport++; } return Flag; } DWORD UnSetIATHook(DWORD OldAddr, DWORD NewAddr) { DWORD dwImageBase = 0; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNTHeader = NULL; PIMAGE_FILE_HEADER pPEHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; PIMAGE_IMPORT_DESCRIPTOR pImport = NULL; PDWORD pIATThunk = NULL; bool Flag = FALSE; dwImageBase = (DWORD)::GetModuleHandle(NULL); //获取进程基址 pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pImport = (PIMAGE_IMPORT_DESCRIPTOR)(pOptionHeader->DataDirectory[1].VirtualAddress + dwImageBase); //定位导入表 while (pImport->FirstThunk != 0 && Flag == FALSE) { pIATThunk = (PDWORD)(pImport->FirstThunk + dwImageBase); while (*pIATThunk) { if (*pIATThunk == NewAddr) { *pIATThunk = OldAddr; Flag = TRUE; break; } pIATThunk++; } pImport++; } return Flag; } int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { printf("%x %s %ws %x\n", hWnd, lpText, lpCaption, uType); typedef int (WINAPI* pMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT); //int ret = MessageBox(hWnd, lpText, lpCaption, uType); int ret = ((pMessageBox)OldFunc)(hWnd, lpText, lpCaption, uType); printf("返回值%x", ret); return ret; } int TestIATHOOK() { SetIATHook(OldFunc, (DWORD)MyMessageBoxW); MessageBox(NULL, L"HELLO", L"HACKER", MB_OK); UnSetIATHook(OldFunc, (DWORD)MyMessageBoxW); return 1; } int main() { TestIATHOOK(); }