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-hk/n/148261.html
微信掃一掃
支付寶掃一掃