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/n/148261.html
微信扫一扫
支付宝扫一扫