iathook详解

发布时间:2023-05-17

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虽然在实现上简单,但是在实践应用时,需要特别注意到其应用场景,了解其中的缺陷和漏洞,以便更好地利用它。