iathook是Windows API Hook技術中的一種,它通過修改導入表中的dll導入函數地址,使得被Hook的函數在實際調用時會轉而調用Hook函數。iathook的實現方法有多種,本文將從iathook原理、iathook易語言、iathook缺點、iathook運行遠程線程等方面對它進行詳細的分析和闡述。
一、iathook原理
在程序載入時,Windows會讀取程序的導入表,來確定程序需要依賴哪些dll庫,並會將這些函數的地址填充到相應的位置。在導入表中,每個dll庫都會對應一個導入描述符(Import Descriptor),它包含了被目標dll庫導出的函數的一份名單,順序排列在該描述符中。每個此類函數都對應一個導入名稱表(Import Name Table),其用於存儲導入描述符中每個函數的名稱與地址。
iathook實際上就是通過修改目標dll庫的導入名稱表中的函數地址,從而將被Hook函數重定向到Hook函數。其原理如下所示:
1. 找到Windows API函數所在的dll庫,例如kernel32.dll; 2. 在該dll庫的導入描述符中,找到被Hook函數的導入名稱表,並獲取其地址; 3. 運行時修改該導入名稱表的相關函數地址,使其指向Hook函數地址; 4. 當被Hook函數被調用時,實際會轉而調用Hook函數;
下面是iathook原理的代碼實現:
PIMAGE_IMPORT_DESCRIPTOR iid = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData( hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size ); while (iid->Name) { PIMAGE_THUNK_DATA pNameTable = (PIMAGE_THUNK_DATA)(rva2ptr(hModule, iid->FirstThunk)); PIMAGE_THUNK_DATA pAddrTable = (iid->OriginalFirstThunk) ? (PIMAGE_THUNK_DATA)(rva2ptr(hModule, iid->OriginalFirstThunk)) : pNameTable; for (; pAddrTable->u1.Function != NULL; pAddrTable++, pNameTable++) { if (pAddrTable->u1.Function == fpHookedFunction) { DWORD dwOldProtect, dwNewProtect; VirtualProtect((LPVOID)&pNameTable->u1.Function, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect); pNameTable->u1.Function = (DWORD)fpHookFunction; VirtualProtect((LPVOID)&pNameTable->u1.Function, sizeof(DWORD), dwOldProtect, &dwNewProtect); } } iid++; }
二、iathook易語言
iathook在易語言中也是可以實現的,易語言中的關鍵函數有:
- memory.LoadPEFile:用於載入dll文件到內存中;
- memory.GetPEFileBase:獲取dll文件在內存中的基地址;
- memory.GetVirtualAddress:獲取導入表中函數的地址;
- memory.WriteDWord:用於修改導入表中函數的地址;
下面是在易語言中實現iathook的代碼示例:
//聲明iathook函數指針類型 typedef void (*fpIATHook)(void); fpIATHook pfnOldFunc = NULL; //調用memory函數以獲取目標dll的句柄和基地址 HMODULE hModule = memory.LoadPEFile("TargetDLL.dll"); DWORD dwBaseAddr = memory.GetPEFileBase(hModule); //獲取需要Hook的函數地址以及導入表地址 LPSTR szHookFuncName = "TargetFunction"; LPSTR szImportDllName = "TargetDLL.dll"; LPSTR szImportFuncName = "TargetFunction"; DWORD dwIATBase = memory.GetVirtualAddress(dwBaseAddr, szImportDllName, szImportFuncName); DWORD *pdwOrgIATEntry = (DWORD*)memory.GetVirtualAddress(dwBaseAddr, szImportDllName, szHookFuncName); //備份原函數地址,並修改導入表中函數的地址 pfnOldFunc = (fpIATHook)(*pdwOrgIATEntry); memory.WriteDWord((DWORD)(&pdwOrgIATEntry[0]), (DWORD)(&HookFunction)); //Hook完成,可以調用目標函數時,實際上會調用自定義的Hook函數 TargetFunction(Param1, Param2, ...); //取消Hook,將原函數地址恢復到導入表中 memory.WriteDWord((DWORD)(&pdwOrgIATEntry[0]), (DWORD)(pfnOldFunc));
三、iathook缺點
iathook雖然實現簡單,但是在安全性上存在很大的漏洞和缺點,下面是一些iathook的缺點:
- 易受反Hook,因為其僅是修改導入表中函數的地址,所以易受到反Hook,從而直接執行原本的函數,導致Hook失效;
- 無法Hook外部函數,如果被Hook的函數在導入表中沒有,而在外部dll庫中,那麼iathook也將無法Hook該函數;
- 無法HookGetProcAddress,因為GetProcAddress函數返回的地址是動態的,而不是固定的地址,iathook無法修改其地址,因此無法Hook該函數
- 修改導入表可能引起程序崩潰,特別是在多線程環境下,修改導入表可能會導致程序崩潰,所以在iathook的應用中,需要特別小心處理。
四、iathook運行遠程線程
iathook也能夠直接運行遠程線程,僅需要將需要Hook的函數引入模塊裝載入遠程線程的地址空間,並讀取和修改導入表中的地址。下面是iathook運行遠程線程的代碼示例:
LPSTR szTargetDllName = "TargetModule.dll"; LPSTR szTargetFuncName = "TargetFunction"; LPSTR szHookFuncName = "HookFunction"; //獲取遠程進程句柄和主模塊句柄 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); HMODULE hModule = GetModuleHandle(NULL); //獲取遠程目標dll句柄和大小 HMODULE hModRemote = NULL; DWORD dwModSize = 0; GetRemoteModuleHandle(hProcess, szTargetDllName, &hModRemote, &dwModSize); //將目標dll模塊裝載入遠程線程地址空間 LPVOID pRemoteBase = VirtualAllocEx(hProcess, NULL, dwModSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); BOOL bWritten = WriteProcessMemory(hProcess, pRemoteBase, lpData, dwModSize, NULL); if (bWritten) { DWORD dwRemoteThreadId = 0; //運行遠程線程,執行iathook HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnLoadDll, pRemoteBase, 0, &dwRemoteThreadId); WaitForSingleObject(hRemoteThread, INFINITE); VirtualFreeEx(hProcess, pRemoteBase, 0, MEM_RELEASE); //查找導入表中函數地址並Hook DWORD dwRemoteBase = (DWORD)hModRemote; DWORD dwRemoteFunction = (DWORD)GetProcAddress(hModRemote, szTargetFuncName); DWORD dwImportAddrTable = GetIATAddress(dwRemoteBase, hModule, szTargetDllName); DWORD dwOldProtect = 0; VirtualProtectEx(hProcess, (LPVOID)dwImportAddrTable, 4, PAGE_READWRITE, &dwOldProtect); WriteProcessMemory(hProcess, (LPVOID)dwImportAddrTable, &dwRemoteFunction, sizeof(DWORD), NULL); VirtualProtectEx(hProcess, (LPVOID)dwImportAddrTable, 4, dwOldProtect, &dwOldProtect); } //done......
以上就是iathook的詳解,iathook雖然在實現上簡單,但是在實踐應用時,需要特別注意到其應用場景,了解其中的缺陷和漏洞,以便更好地利用它。
原創文章,作者:NWDN,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/148261.html