1.IAT hook原理:

IAT(Import Address Table)Hook 的原理主要是通过修改可执行文件在运行时的导入地址表,以便拦截对特定函数的调用并将其重定向到自定义的函数。这种技术常用于实现日志记录、函数替换和监控等目的。

原理步骤

  1. 了解 IAT
    • 在 Windows PE 文件中,IAT 是用于存储程序所需的外部函数地址的表。每当程序调用某个外部函数时,它实际上是通过 IAT 查找该函数的地址。
  2. 获取 IAT 地址
    • 程序加载时,操作系统会根据 PE 文件的导入表初始化 IAT。你可以通过解析 PE 文件结构,找到 IAT 的位置。
  3. 定位要 Hook 的函数
    • 通过遍历 IAT,找到需要 Hook 的函数的地址。例如,可以通过函数名找到对应的函数地址。
  4. 修改 IAT 中的地址
    • 将 IAT 中存储的函数地址替换为你自己的 Hook 函数的地址。这需要修改内存中的内容,因此通常需要更改内存保护属性(使用 VirtualProtect 函数)以允许写入。
  5. 实现 Hook 函数
    • 创建一个自定义的 Hook 函数,该函数在被调用时可以执行自定义逻辑。通常,Hook 函数会调用原始函数,以保证程序的正常运行。
  6. 调用原始函数
    • 在 Hook 函数中,如果需要,可以调用原始的被 Hook 函数,通常通过在 Hook 函数中保存原始函数的地址来实现。

示例流程

  • 假设我们要 Hook MessageBoxA 函数:
    1. 获取当前模块的 IAT 地址。
    2. 遍历 IAT,找到 MessageBoxA 的地址。
    3. 将 IAT 中的地址替换为自定义的 Hook 函数地址。
    4. 自定义 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;
// 注意都是RVA地址,所以计算地址时要加上基址
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
// NT 头
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); // 修改为+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;
}