IAT_Hook

IAT HOOK

原理是通过替换IAT表中的函数的原始地址从而实现HOOK的,IAT Hook 需要充分理解PE文件的结构才能完成Hook,这里就简单讲一下代码实现了

[IAT_HOOK]: https://www.cnblogs.com/LyShark/p/11766620.html “ IAT_Hook”
[代码实现]: https://github.com/SHangwendada/CodeRepo

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <windows.h>
#include <iostream>
typedef int(__cdecl* PMemcmp)(const void* buf1, const void* buf2, size_t count);
DWORD GetMemcmpAddressFromIAT() {
//通过 GetModuleHandle(NULL) 获取当前程序的模块句柄(即 EXE 在内存中的起始地址
HMODULE hModule = GetModuleHandle(NULL);
if (!hModule) {
printf("Failed to get handle of current module\n");
return 0;
}

//hModule 指向 EXE 文件的起始地址,转换为 IMAGE_DOS_HEADER 结构指针
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;

//e_lfanew 是一个偏移量,指向 IMAGE_NT_HEADERS 结构,该结构包含 PE 头信息
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + pDosHeader->e_lfanew);

//获取 PE 文件的可选头,进而访问 DataDirectory 数组中的导入表的虚拟地址
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32) & (pNTHeader->OptionalHeader);

//通过导入表的虚拟地址获取到导入描述符,它描述了程序的导入信息
PIMAGE_IMPORT_DESCRIPTOR pIMPORT_DESCRIPTOR = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hModule + pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

//遍历导入表 遍历所有 DLL,直到 FirstThunk == 0,表示导入表结束
while (pIMPORT_DESCRIPTOR->FirstThunk) {
//FirstThunk 指向 IAT,存储函数的实际调用地址
PDWORD FirstThunk = (PDWORD)((DWORD)hModule + pIMPORT_DESCRIPTOR->FirstThunk);

//OriginalFirstThunk 存储原始的导入名称数组(INT)
PDWORD OriginalFirstThunk = (PDWORD)((DWORD)hModule + pIMPORT_DESCRIPTOR->OriginalFirstThunk);

/*OriginalFirstThunk 指向 IMAGE_IMPORT_BY_NAME 结构
+ 2 跳过 WORD 大小的 Hint 字段,指向函数名称字符串*/
while (*FirstThunk) {
char* functionName = (char*)((*OriginalFirstThunk) + (DWORD)hModule + 2);

//如果 functionName 是 "memcmp",返回它在 IAT 中的地址
if (strcmp(functionName, "memcmp") == 0) {
return (DWORD)FirstThunk;
}
FirstThunk++;
OriginalFirstThunk++;
}
pIMPORT_DESCRIPTOR++;
}
printf("Failed to find memcmp in IAT.\n");
return 0;
}
//自定义memcpy
int __cdecl MyMemcmp(const void* buf1, const void* buf2, size_t count) {
printf("Hooked memcmp Param: buf1: %p, buf2: %p, count: %zu\n", buf1, buf2, count);

//通过 GetProcAddress 获取 ucrtbase.dll(通用 C 运行时库)中的 memcmp
PMemcmp OriginalMemcmp = (PMemcmp)GetProcAddress(GetModuleHandleA("ntdll.dll"), "memcmp");

//检查 OriginalMemcmp 是否成功获取,否则返回 -1
if (!OriginalMemcmp) {
printf("Failed to call original memcmp.\n");
return -1;
}
printf("oh babg girl 终于成功啦.\n");
printf("接下来将会是一个加密flag的地方.\n");
//调用真正的 memcmp,输出比较结果,并返回该结果
//int result = OriginalMemcmp(buf1, buf2, count);
//printf("Original memcmp result:%d\n", result);
return 0;
}
// IAT Hook:修改导入表 pdwOldFunction 指向 IAT 中 memcmp 的地址 dwNewFunction 是 MyMemcmp 的地址
void InstallIatHook(DWORD* pdwOldFunction, DWORD dwNewFunction) {
DWORD dwOldProtect;
if (VirtualProtect(pdwOldFunction, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect)) {
//将 memcmp 的地址替换为 MyMemcmp。
*pdwOldFunction = dwNewFunction;

VirtualProtect(pdwOldFunction, sizeof(DWORD), dwOldProtect, &dwOldProtect);
printf("Function hooked successfully");
}
else {
printf("Failed to change protection of IAT.\n");
}
}
int main() {
//获取 memcmp 在 IAT 中的地址,并检查是否成功获取
DWORD* dwMemcmp = (DWORD*)GetMemcmpAddressFromIAT();
if (dwMemcmp == 0) {
printf("Failed to get memcmp address from IAT.\n");
return -1;
}
printf("memcmp address in IAT: %p\n", (void*)*dwMemcmp);

//安装 Hook,将 IAT 中的 memcmp 替换为 MyMemcmp
InstallIatHook(dwMemcmp, (DWORD)MyMemcmp);
char buf1[] = "test1";
char buf2[] = "test2";
memcmp(buf1, buf1, sizeof(buf1)); // 预期返回 0
memcmp(buf1, buf2, sizeof(buf1)); // 预期返回 -1 或其他值
// Uncomment below to uninstall the hook
// UninstallIatHook(dwMemcmp, (DWORD)MyMemcmp);
// memcmp(buf1, buf2, sizeof(buf1));
return 0;
}