1.IAT hook原理:
IAT(Import Address Table)Hook 的原理主要是通过修改可执行文件在运行时的导入地址表,以便拦截对特定函数的调用并将其重定向到自定义的函数。这种技术常用于实现日志记录、函数替换和监控等目的。
原理步骤
- 了解 IAT:
- 在 Windows PE 文件中,IAT 是用于存储程序所需的外部函数地址的表。每当程序调用某个外部函数时,它实际上是通过 IAT 查找该函数的地址。
- 获取 IAT 地址:
- 程序加载时,操作系统会根据 PE 文件的导入表初始化 IAT。你可以通过解析 PE 文件结构,找到 IAT 的位置。
- 定位要 Hook 的函数:
- 通过遍历 IAT,找到需要 Hook 的函数的地址。例如,可以通过函数名找到对应的函数地址。
- 修改 IAT 中的地址:
- 将 IAT 中存储的函数地址替换为你自己的 Hook 函数的地址。这需要修改内存中的内容,因此通常需要更改内存保护属性(使用
VirtualProtect 函数)以允许写入。
- 实现 Hook 函数:
- 创建一个自定义的 Hook 函数,该函数在被调用时可以执行自定义逻辑。通常,Hook 函数会调用原始函数,以保证程序的正常运行。
- 调用原始函数:
- 在 Hook 函数中,如果需要,可以调用原始的被 Hook 函数,通常通过在 Hook 函数中保存原始函数的地址来实现。
示例流程
- 假设我们要 Hook
MessageBoxA 函数:
- 获取当前模块的 IAT 地址。
- 遍历 IAT,找到
MessageBoxA 的地址。
- 将 IAT 中的地址替换为自定义的 Hook 函数地址。
- 自定义 Hook 函数可以在调用原始
MessageBoxA 之前或之后执行自定义逻辑。
注意事项
- 保护内存:修改 IAT 时,必须确保适当地更改内存的保护属性,以允许写入。
- 安全性:Hook 技术可能被用于恶意目的,因此在使用时需要遵循相关法律法规。
- 兼容性:在不同的 Windows 版本和架构上,IAT Hook 的实现可能会有所不同。
总结
IAT Hook 是一种强大且灵活的技术,能够有效地拦截和重定向函数调用。理解其工作原理可以帮助开发者在进行系统监控、调试和逆向工程时更加得心应手。
2.x64下的IAT hook实现
[!NOTE]
程序实现函数的时候都会使用call address ,实现函数的调用,如果我们hook 这个地址,就能调用我们的hook 函数,我们有知道PE文件的结构,所以可以在IAT实现目标函数的地址修改
导入表的OriginalFirstThunK,FirstThunk分别指向INT和IAT
INT与IAT的每个条目都是一个4字节(32位下)的IMAGE_THUNK_DATA(它是一个union)
1 2 3 4 5 6
| typedef union _IMAGE_THUNK_DATA { ULONG ForwarderString; ULONG Function; ULONG Ordinal; PIMAGE_IMPORT_BY_NAME AddressOfData; } IMAGE_THUNK_DATA;
|
接下是实例:使用IAT hook 系统函数MessageBoxW
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <Windows.h> #include <iostream>
typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT); MessageBoxW_t OriginalMessageBoxW = nullptr;
int WINAPI HookMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { return OriginalMessageBoxW(hWnd, L"IAT HOOK success!", lpCaption, uType); }
bool InstallIATHook(const char* dllName, const char* funName, void* hookFuncAddr) { HMODULE hModule = GetModuleHandleA(NULL); if (!hModule) return false; PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; PIMAGE_NT_HEADERS64 ntHeaders = (PIMAGE_NT_HEADERS64)((BYTE*)dosHeader + dosHeader->e_lfanew); PIMAGE_OPTIONAL_HEADER64 optionalHeader = &ntHeaders->OptionalHeader; IMAGE_DATA_DIRECTORY directory = optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE*)hModule + directory.VirtualAddress);
while (importDescriptor->Name) { const char* iatDllName = (const char*)((BYTE*)hModule + importDescriptor->Name); if (_stricmp(dllName, iatDllName) == 0) { PIMAGE_THUNK_DATA64 pInt = (PIMAGE_THUNK_DATA64)((BYTE*)hModule + importDescriptor->OriginalFirstThunk); PIMAGE_THUNK_DATA64 pIat = (PIMAGE_THUNK_DATA64)((BYTE*)hModule + importDescriptor->FirstThunk);
while (pInt->u1.AddressOfData) { PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((BYTE*)hModule + pInt->u1.AddressOfData); if (strcmp((const char*)pImportByName->Name, funName) == 0) { OriginalMessageBoxW = (MessageBoxW_t)pIat->u1.Function;
DWORD oldProtect; VirtualProtect(&pIat->u1.Function, sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProtect); pIat->u1.Function = (DWORD_PTR)hookFuncAddr; VirtualProtect(&pIat->u1.Function, sizeof(void*), oldProtect, &oldProtect);
return true; } pInt++; pIat++; } } importDescriptor++; } return false; }
int main() { InstallIATHook("user32.dll", "MessageBoxW", HookMessageBoxW); MessageBoxW(NULL, L"hello,world", L"@Xhani", MB_OK); return 0; }
|
Todo1:请编程实现HOOK WriteFile 这个Windows API,实现每次调用这个函数的时候,在写入的数据后面增加一个字符串:Xhani!!!。然后程序里尝试打开一个文件,并写入一些数据,最后打开文件看看是否有这个字符串内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #include <windows.h> #include <stdio.h> #include <string.h> #include <stdlib.h>
typedef BOOL(WINAPI* HWriteFile)(_In_ HANDLE hFile, _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped);
HWriteFile targetaddress = nullptr;
BOOL HookWriteFile( _In_ HANDLE hFile, _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped ) { char str[] = "Xhani!!!"; size_t len = strlen(str) + nNumberOfBytesToWrite; char* buffer = (char*)malloc(len + 1); if (buffer == NULL) return FALSE;
memcpy(buffer, lpBuffer, nNumberOfBytesToWrite); memcpy(buffer + nNumberOfBytesToWrite, str, strlen(str) + 1);
BOOL result = targetaddress(hFile, buffer, len, lpNumberOfBytesWritten, lpOverlapped); free(buffer); return result; }
BOOL iathookWriteFile(const char* dllname, const char* function, void* hookaddress) { HMODULE hmodule = GetModuleHandle(NULL); PIMAGE_DOS_HEADER pDosheader = (PIMAGE_DOS_HEADER)hmodule; PIMAGE_NT_HEADERS64 pNtheader = (PIMAGE_NT_HEADERS64)(pDosheader->e_lfanew + (BYTE*)hmodule); PIMAGE_OPTIONAL_HEADER64 pOptionhead = &pNtheader->OptionalHeader; IMAGE_DATA_DIRECTORY directory = pOptionhead->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE*)hmodule + directory.VirtualAddress);
while (importDescriptor->Name) { const char* iatdllname = (const char*)((BYTE*)hmodule + importDescriptor->Name); if (_stricmp(iatdllname, dllname) == 0) { PIMAGE_THUNK_DATA64 pInt = (PIMAGE_THUNK_DATA64)((BYTE*)hmodule + importDescriptor->OriginalFirstThunk); PIMAGE_THUNK_DATA64 pIat = (PIMAGE_THUNK_DATA64)((BYTE*)hmodule + importDescriptor->FirstThunk); while (pInt->u1.AddressOfData) { PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((BYTE*)hmodule + pInt->u1.AddressOfData); if (_stricmp((const char*)pImportByName->Name, function) == 0) { targetaddress = (HWriteFile)pIat->u1.Function;
DWORD oldProtect; VirtualProtect(&pIat->u1.Function, sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProtect); pIat->u1.Function = (DWORD_PTR)hookaddress; VirtualProtect(&pIat->u1.Function, sizeof(void*), oldProtect, &oldProtect);
return true; } pInt++; pIat++; } importDescriptor++; } return FALSE; } }
int main() { HANDLE hFile = ::CreateFile("exp.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("Failed to create file.\n"); return 1; } char str[] = "hello_world"; DWORD byteswriten; if (iathookWriteFile("KERNEL32.dll", "WriteFile", HookWriteFile)) { WriteFile(hFile, str, strlen(str), &byteswriten, NULL); } else { printf("Failed to hook WriteFile.\n"); } return 0; }
|