HOOK专题
4、IATHook
一、课程目标
本节课主要学习IAT Hook技术,这是Windows平台上一种常见的Hook方法。通过本课的学习,你将能够:
- 理解IAT(Import Address Table)的基本概念和结构
- 掌握IAT Hook的实现原理和技术细节
- 实现一个完整的IAT Hook框架
- 理解IAT Hook在程序监控和安全防护中的应用
- 学习IAT Hook的检测和防护方法
二、名词解释表
| 名词 | 解释 |
|---|---|
| IAT | Import Address Table,导入地址表,存储程序导入函数的实际地址 |
| ILT | Import Lookup Table,导入查找表,存储导入函数的名称或序号 |
| PE文件 | Portable Executable,Windows平台上的可执行文件格式 |
| RVA | Relative Virtual Address,相对虚拟地址,相对于模块基址的偏移 |
| 导入函数 | 程序从其他DLL中引用的函数 |
| DLL注入 | 将DLL加载到目标进程地址空间的技术 |
| API监控 | 监控程序调用API函数的行为 |
三、技术原理
3.1 IAT概述
IAT(Import Address Table,导入地址表)是PE文件格式中的一个重要组成部分。当程序需要调用外部DLL中的函数时,Windows加载器会将这些函数的实际地址填入IAT中。程序在运行时通过IAT来调用这些导入函数。
3.2 IAT结构
在PE文件中,IAT相关的结构包括:
- IMAGE_IMPORT_DESCRIPTOR:导入表描述符,每个DLL对应一个
- FirstThunk:指向IAT的指针
- OriginalFirstThunk:指向ILT的指针(在绑定导入时可能为0)
3.3 IAT Hook原理
IAT Hook通过修改IAT中函数地址来实现Hook功能:
- 找到目标DLL和函数在IAT中的位置
- 备份原始函数地址
- 将IAT中的地址修改为我们自定义函数的地址
- 当程序调用该函数时,实际执行的是我们的Hook函数
3.4 IAT Hook的优势和劣势
优势:
- 实现相对简单
- 不修改目标函数代码
- 对目标程序影响小
- 可以Hook所有对该函数的调用
劣势:
- 只能Hook导入函数
- 容易被检测到
- 对于延迟加载的DLL无效
- 可能影响其他使用相同DLL的模块
四、代码实现
4.1 核心数据结构
#include <windows.h>
#include <stdio.h>
#include <imagehlp.h>
#pragma comment(lib, "imagehlp.lib")
// IAT Hook信息结构体
typedef struct _IAT_HOOK_INFO {
CHAR szModuleName[64]; // 模块名称
CHAR szFunctionName[64]; // 函数名称
PVOID pOriginalFunc; // 原始函数地址
PVOID pHookFunc; // Hook函数地址
PVOID* ppIATEntry; // IAT条目地址
BOOL bIsHooked; // 是否已Hook
} IAT_HOOK_INFO, * PIAT_HOOK_INFO;
// IAT Hook管理器
typedef struct _IAT_HOOK_MANAGER {
IAT_HOOK_INFO* pHooks; // Hook信息数组
INT nHookCount; // Hook数量
} IAT_HOOK_MANAGER, * PIAT_HOOK_MANAGER;
4.2 PE解析辅助函数
// 获取模块基址
HMODULE GetRemoteModuleHandle(HANDLE hProcess, LPCSTR lpModuleName) {
HMODULE hModules[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) {
for (UINT i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
CHAR szModName[MAX_PATH];
if (GetModuleFileNameExA(hProcess, hModules[i], szModName, sizeof(szModName))) {
// 检查模块名是否匹配
if (strstr(szModName, lpModuleName)) {
return hModules[i];
}
}
}
}
return NULL;
}
// 获取函数地址
FARPROC GetRemoteProcAddress(HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName) {
return GetProcAddress(hModule, lpProcName);
}
4.3 IAT Hook核心实现
// 查找IAT条目
PVOID* FindIATEntry(HMODULE hModule, LPCSTR lpModuleName, LPCSTR lpFunctionName) {
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((PBYTE)hModule + pDosHeader->e_lfanew);
// 获取导入表
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)hModule +
pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
// 遍历导入表
while (pImportDesc->Name) {
LPCSTR lpCurrModName = (LPCSTR)((PBYTE)hModule + pImportDesc->Name);
// 检查模块名是否匹配(不区分大小写)
if (_stricmp(lpCurrModName, lpModuleName) == 0) {
// 获取IAT和ILT
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDesc->FirstThunk);
PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDesc->OriginalFirstThunk);
// 遍历导入函数
while (pOrigThunk->u1.AddressOfData) {
// 获取函数名称
if (!(pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)) {
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hModule + pOrigThunk->u1.AddressOfData);
// 检查函数名是否匹配
if (strcmp(pImportByName->Name, lpFunctionName) == 0) {
return (PVOID*)&pThunk->u1.Function;
}
}
pThunk++;
pOrigThunk++;
}
}
pImportDesc++;
}
return NULL;
}
// 安装IAT Hook
BOOL InstallIATHook(PIAT_HOOK_INFO pHookInfo) {
if (!pHookInfo || !pHookInfo->szModuleName[0] || !pHookInfo->szFunctionName[0] || !pHookInfo->pHookFunc) {
return FALSE;
}
HMODULE hModule = GetModuleHandle(NULL); // 当前模块
if (!hModule) {
return FALSE;
}
// 查找IAT条目
pHookInfo->ppIATEntry = FindIATEntry(hModule, pHookInfo->szModuleName, pHookInfo->szFunctionName);
if (!pHookInfo->ppIATEntry) {
printf("Failed to find IAT entry for %s!%s\n", pHookInfo->szModuleName, pHookInfo->szFunctionName);
return FALSE;
}
// 备份原始函数地址
pHookInfo->pOriginalFunc = *pHookInfo->ppIATEntry;
// 修改内存保护属性
DWORD oldProtect;
if (!VirtualProtect(pHookInfo->ppIATEntry, sizeof(PVOID), PAGE_READWRITE, &oldProtect)) {
return FALSE;
}
// 修改IAT条目
*pHookInfo->ppIATEntry = pHookInfo->pHookFunc;
// 恢复内存保护属性
VirtualProtect(pHookInfo->ppIATEntry, sizeof(PVOID), oldProtect, &oldProtect);
pHookInfo->bIsHooked = TRUE;
return TRUE;
}
// 卸载IAT Hook
BOOL UninstallIATHook(PIAT_HOOK_INFO pHookInfo) {
if (!pHookInfo || !pHookInfo->bIsHooked) {
return FALSE;
}
// 修改内存保护属性
DWORD oldProtect;
if (!VirtualProtect(pHookInfo->ppIATEntry, sizeof(PVOID), PAGE_READWRITE, &oldProtect)) {
return FALSE;
}
// 恢复原始函数地址
*pHookInfo->ppIATEntry = pHookInfo->pOriginalFunc;
// 恢复内存保护属性
VirtualProtect(pHookInfo->ppIATEntry, sizeof(PVOID), oldProtect, &oldProtect);
pHookInfo->bIsHooked = FALSE;
return TRUE;
}
4.4 IAT Hook管理器
// 初始化IAT Hook管理器
PIAT_HOOK_MANAGER InitIATHookManager() {
PIAT_HOOK_MANAGER pManager = (PIAT_HOOK_MANAGER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAT_HOOK_MANAGER));
if (!pManager) {
return NULL;
}
return pManager;
}
// 添加Hook
BOOL AddIATHook(PIAT_HOOK_MANAGER pManager, LPCSTR lpModuleName, LPCSTR lpFunctionName, PVOID pHookFunc) {
// 重新分配内存
PIAT_HOOK_INFO pNewHooks = (PIAT_HOOK_INFO)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
pManager->pHooks, sizeof(IAT_HOOK_INFO) * (pManager->nHookCount + 1));
if (!pNewHooks) {
return FALSE;
}
pManager->pHooks = pNewHooks;
// 填充Hook信息
PIAT_HOOK_INFO pHook = &pManager->pHooks[pManager->nHookCount];
strcpy_s(pHook->szModuleName, sizeof(pHook->szModuleName), lpModuleName);
strcpy_s(pHook->szFunctionName, sizeof(pHook->szFunctionName), lpFunctionName);
pHook->pHookFunc = pHookFunc;
pHook->bIsHooked = FALSE;
// 安装Hook
if (!InstallIATHook(pHook)) {
return FALSE;
}
pManager->nHookCount++;
return TRUE;
}
// 移除所有Hook
VOID RemoveAllIATHooks(PIAT_HOOK_MANAGER pManager) {
if (!pManager) {
return;
}
// 卸载所有Hook
for (INT i = 0; i < pManager->nHookCount; i++) {
UninstallIATHook(&pManager->pHooks[i]);
}
// 释放内存
if (pManager->pHooks) {
HeapFree(GetProcessHeap(), 0, pManager->pHooks);
}
HeapFree(GetProcessHeap(), 0, pManager);
}
4.5 示例Hook函数
// 示例:Hook MessageBoxW函数
typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT);
MessageBoxW_t g_pOriginalMessageBoxW = NULL;
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
// 记录调用信息
wprintf(L"[IAT Hook] MessageBoxW called: %s\n", lpText);
// 可以修改参数
return g_pOriginalMessageBoxW(hWnd, L"[Hooked] Modified Text", lpCaption, uType);
}
// 示例:Hook Sleep函数
typedef void (WINAPI* Sleep_t)(DWORD);
Sleep_t g_pOriginalSleep = NULL;
void WINAPI MySleep(DWORD dwMilliseconds) {
// 记录调用信息
printf("[IAT Hook] Sleep called for %lu milliseconds\n", dwMilliseconds);
// 可以修改行为,例如缩短睡眠时间
g_pOriginalSleep(dwMilliseconds / 2);
}
// 使用示例
VOID DemoIATHook() {
// 初始化Hook管理器
PIAT_HOOK_MANAGER pManager = InitIATHookManager();
if (!pManager) {
printf("Failed to initialize IAT Hook manager.\n");
return;
}
// 添加MessageBoxW Hook
if (AddIATHook(pManager, "user32.dll", "MessageBoxW", (PVOID)MyMessageBoxW)) {
printf("MessageBoxW IAT Hook installed successfully.\n");
// 保存原始函数地址
// 注意:在实际实现中,我们需要通过Hook信息结构获取原始地址
}
// 添加Sleep Hook
if (AddIATHook(pManager, "kernel32.dll", "Sleep", (PVOID)MySleep)) {
printf("Sleep IAT Hook installed successfully.\n");
}
// 测试Hook效果
MessageBoxW(NULL, L"Original Message", L"Test", MB_OK);
Sleep(2000); // 睡眠2秒,但实际只会睡1秒
// 清理Hook
RemoveAllIATHooks(pManager);
printf("All IAT Hooks removed.\n");
}
4.6 远程进程IAT Hook
// 在远程进程中安装IAT Hook
BOOL InstallRemoteIATHook(HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpFunctionName, PVOID pHookFunc, PVOID* ppOriginalFunc) {
// 获取目标进程模块句柄
HMODULE hTargetModule = GetRemoteModuleHandle(hProcess, lpModuleName);
if (!hTargetModule) {
return FALSE;
}
// 获取目标进程中函数地址
FARPROC pTargetFunc = GetRemoteProcAddress(hProcess, hTargetModule, lpFunctionName);
if (!pTargetFunc) {
return FALSE;
}
// 在目标进程中查找IAT条目
// 注意:这需要在目标进程中执行,或者使用更复杂的解析方法
// 此处为简化实现,仅展示思路
// 修改目标进程内存
SIZE_T bytesWritten;
return WriteProcessMemory(hProcess, /* IAT条目地址 */, &pHookFunc, sizeof(PVOID), &bytesWritten);
}
// DLL注入实现IAT Hook
BOOL InjectDLLForIATHook(LPCSTR lpProcessName, LPCSTR lpDllPath) {
// 1. 获取目标进程句柄
HWND hwnd = FindWindowA(NULL, lpProcessName);
if (!hwnd) {
return FALSE;
}
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) {
return FALSE;
}
// 2. 在目标进程中分配内存
SIZE_T dllPathLen = strlen(lpDllPath) + 1;
PVOID pRemoteDllPath = VirtualAllocEx(hProcess, NULL, dllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!pRemoteDllPath) {
CloseHandle(hProcess);
return FALSE;
}
// 3. 写入DLL路径
SIZE_T bytesWritten;
if (!WriteProcessMemory(hProcess, pRemoteDllPath, lpDllPath, dllPathLen, &bytesWritten)) {
VirtualFreeEx(hProcess, pRemoteDllPath, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
// 4. 获取LoadLibrary地址
HMODULE hKernel32 = GetModuleHandle(L"kernel32.dll");
FARPROC pLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");
// 5. 创建远程线程执行LoadLibrary
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pRemoteDllPath, 0, NULL);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
// 6. 清理
VirtualFreeEx(hProcess, pRemoteDllPath, 0, MEM_RELEASE);
CloseHandle(hProcess);
return TRUE;
}
五、课后作业
-
基础练习:
- 编写一个程序,使用IAT Hook技术Hook
CreateFileW函数,记录所有文件访问操作 - 实现Hook
WriteFile函数,监控程序的写文件行为
- 编写一个程序,使用IAT Hook技术Hook
-
进阶练习:
- 实现支持远程进程的IAT Hook框架
- 添加对延迟加载DLL的支持
- 实现批量Hook多个函数的功能
-
思考题:
- IAT Hook与Inline Hook相比有哪些优缺点?
- 如何检测和防范IAT Hook攻击?
- 现代Windows系统提供了哪些机制来阻止IAT Hook?
-
扩展阅读:
- 研究Microsoft Detours库中的IAT Hook实现
- 了解Import Address Table Filtering技术
- 学习Control Flow Guard (CFG) 对IAT Hook的影响