VEH Hook vs Inline Hook vs IAT Hook

VEH Hook

  • Windows 有异常处理机制(SEH / VEH),可以在访问非法内存、执行非法指令时触发。
  • VEH Hook 的思路是:故意在目标函数入口插入一个“非法指令”(比如 INT 3 或无效操作码),当程序执行到这里时,会触发异常。
  • 我们提前注册一个 VEH Handler(异常处理函数),在异常里拦截执行流程,转到我们的 Hook Handler。
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
#include <windows.h>
#include <iostream>

typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT);
MessageBoxW_t TrueMessageBoxW = MessageBoxW;

// VEH 回调函数
LONG CALLBACK VectoredHandler(EXCEPTION_POINTERS* ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) {
std::wcout << L"[VEH Hook] MessageBoxW called!" << std::endl;
// 跳过异常,继续执行原始函数
ExceptionInfo->ContextRecord->Eip += 1; // x86 示例,x64 要改 Rip
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}

int main() {
AddVectoredExceptionHandler(1, VectoredHandler);

// 在 MessageBoxW 的开头插入 int 3
DWORD oldProtect;
VirtualProtect((LPVOID)MessageBoxW, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
*(BYTE*)MessageBoxW = 0xCC; // int 3
VirtualProtect((LPVOID)MessageBoxW, 1, oldProtect, &oldProtect);

MessageBoxW(NULL, L"Hello", L"VEH Hook Demo", MB_OK);
return 0;
}

Inline Hook

  • 直接修改目标函数的开头几个字节(通常是 5 字节 jmp 指令),跳转到我们自己写的函数(Hook Handler)。
  • 在我们的 Hook 函数里,可以先处理逻辑,再决定是否调用原函数(通常需要写“Trampoline”跳板保存被覆盖的指令)。
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
#include <windows.h>
#include <iostream>

typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT);
MessageBoxW_t TrueMessageBoxW = MessageBoxW;

BYTE originalBytes[5];

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
std::wcout << L"[Inline Hook] MessageBoxW hooked!" << std::endl;

// 恢复原字节再调用
DWORD oldProtect;
VirtualProtect((LPVOID)TrueMessageBoxW, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy((LPVOID)TrueMessageBoxW, originalBytes, 5);
VirtualProtect((LPVOID)TrueMessageBoxW, 5, oldProtect, &oldProtect);

int ret = TrueMessageBoxW(hWnd, lpText, lpCaption, uType);

// 重新安装 hook
VirtualProtect((LPVOID)TrueMessageBoxW, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
DWORD relativeAddr = (DWORD)MyMessageBoxW - (DWORD)TrueMessageBoxW - 5;
*(BYTE*)TrueMessageBoxW = 0xE9;
*(DWORD*)((BYTE*)TrueMessageBoxW + 1) = relativeAddr;
VirtualProtect((LPVOID)TrueMessageBoxW, 5, oldProtect, &oldProtect);

return ret;
}

void InstallInlineHook() {
DWORD oldProtect;
VirtualProtect((LPVOID)TrueMessageBoxW, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(originalBytes, (LPVOID)TrueMessageBoxW, 5);

DWORD relativeAddr = (DWORD)MyMessageBoxW - (DWORD)TrueMessageBoxW - 5;
*(BYTE*)TrueMessageBoxW = 0xE9;
*(DWORD*)((BYTE*)TrueMessageBoxW + 1) = relativeAddr;

VirtualProtect((LPVOID)TrueMessageBoxW, 5, oldProtect, &oldProtect);
}

int main() {
InstallInlineHook();
MessageBoxW(NULL, L"Hello", L"Inline Hook Demo", MB_OK);
return 0;
}

IAT Hook

  • Windows 程序在运行时会加载 DLL 并填充导入表(IAT),IAT 中保存了各个 API 的函数指针。
  • 通过修改 IAT 中对应 API 的地址,让程序调用 API 时跳转到我们自定义的函数。
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
#include <windows.h>
#include <iostream>
#include <winnt.h>

typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT);
MessageBoxW_t TrueMessageBoxW = nullptr;

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
std::wcout << L"[IAT Hook] MessageBoxW hooked!" << std::endl;
return TrueMessageBoxW(hWnd, lpText, lpCaption, uType);
}

void InstallIATHook() {
HMODULE hModule = GetModuleHandle(NULL);
ULONG size;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);

for (; pImportDesc->Name; pImportDesc++) {
LPCSTR moduleName = (LPCSTR)((PBYTE)hModule + pImportDesc->Name);
if (_stricmp(moduleName, "user32.dll") == 0) {
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImportDesc->FirstThunk);
for (; pThunk->u1.Function; pThunk++) {
PROC* pFunc = (PROC*)&pThunk->u1.Function;
if (*pFunc == (PROC)MessageBoxW) {
DWORD oldProtect;
VirtualProtect(pFunc, sizeof(PROC), PAGE_READWRITE, &oldProtect);
TrueMessageBoxW = (MessageBoxW_t)*pFunc;
*pFunc = (PROC)MyMessageBoxW;
VirtualProtect(pFunc, sizeof(PROC), oldProtect, &oldProtect);
return;
}
}
}
}
}

int main() {
InstallIATHook();
MessageBoxW(NULL, L"Hello", L"IAT Hook Demo", MB_OK);
return 0;
}

VEH Hook vs Inline Hook vs IAT Hook
http://candyb0x.github.io/2025/08/10/VEH-Hook-vs-Inline-Hook-vs-IAT-Hook/
作者
Candy
发布于
2025年8月10日
更新于
2025年10月9日
许可协议