VEH Hook
一、VEH Hook 原理简述
将目标 API 首地址页设为 PAGE_EXECUTE_READ | PAGE_GUARD;
注册一个 vectored handler(AddVectoredExceptionHandler);
每次调用该 API 时,访问触发 STATUS_GUARD_PAGE_VIOLATION 异常;
异常处理器中检查上下文,判断是否命中了 Hook;
修改 Context->Eip/Rip 跳转到你自定义的函数。
二、VEH Hook 示例:劫持 MessageBoxW
使用 C++ + WinAPI,在 VS2022 中完整实现(x86 版本,x64 类似,但注意 RIP 与寄存器偏移不同)。
1. 定义 Hook 函数
#include <windows.h>
#include <iostream>
typedef int (WINAPI* MessageBoxW_t)(HWND, LPCWSTR, LPCWSTR, UINT);
MessageBoxW_t OriginalMessageBoxW = nullptr;
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
return OriginalMessageBoxW(hWnd, L"[Hooked] Hello!", lpCaption, uType);
}
2. 注册 VEH Hook
PVOID vehHandle = nullptr;
BYTE originalBytes[16] = { 0 }; // 保存原始字节
LPVOID targetAddr = nullptr;
LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) {
CONTEXT* ctx = ExceptionInfo->ContextRecord;
#ifdef _M_IX86
if ((LPVOID)ctx->Eip == targetAddr) {
ctx->Eip = (DWORD)&MyMessageBoxW;
return EXCEPTION_CONTINUE_EXECUTION;
}
#else
if ((LPVOID)ctx->Rip == targetAddr) {
ctx->Rip = (DWORD64)&MyMessageBoxW;
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif
}
return EXCEPTION_CONTINUE_SEARCH;
}
3. 安装 Hook
void InstallVEHHook() {
HMODULE user32 = GetModuleHandleW(L"user32.dll");
targetAddr = (LPVOID)GetProcAddress(user32, "MessageBoxW");
OriginalMessageBoxW = (MessageBoxW_t)targetAddr;
// 设置 PAGE_GUARD
DWORD oldProtect;
VirtualProtect(targetAddr, 1, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtect);
// 注册异常处理器
vehHandle = AddVectoredExceptionHandler(1, VectoredHandler);
}
4. 卸载 Hook(恢复页面属性)
void UninstallVEHHook() {
if (vehHandle)
RemoveVectoredExceptionHandler(vehHandle);
if (targetAddr) {
DWORD oldProtect;
VirtualProtect(targetAddr, 1, PAGE_EXECUTE_READ, &oldProtect);
}
}
5. 主程序入口
int main() {
InstallVEHHook();
MessageBoxW(NULL, L"Original Text", L"VEH Hook Test", MB_OK);
UninstallVEHHook();
return 0;
}
二、VEH Hook 的核心优势
| 优点 | 说明 |
|---|---|
| 无需修改函数指令 | 不像 Inline Hook 会修改目标函数开头的指令 |
| 不易被检测 | 安全软件难以检测异常逻辑,兼具隐蔽性 |
| 动态可移除 | VEH 异常处理链支持动态注册/移除 |
| 支持任意函数 | 只要可访问内存的函数都可 Hook |
| 不依赖 IAT 或 Import Table | 可绕过导入表 Hook 检测或修复 |
| ---- | ---- |
三、VEH Hook 的应用场景
- 安全防护与反调试
- 检测非法访问特定地址(如关键结构体、PEB);
- 捕捉断点指令、调试器行为;
- 模拟 "抗调试" 行为:如 Hook NtReadVirtualMemory、IsDebuggerPresent 等 API。
- 逆向分析 / 动态追踪
- 动态监控某个函数是否被调用(如 MessageBoxW、CreateFileA);
- 记录 API 调用参数和调用栈,而不破坏原有流程;
- 动态流控跳转,用于函数劫持或行为重定向。
- 行为监控 / 黑盒注入
- 无需修改原程序代码,即可监视敏感行为(如网络、IO 操作);
- 在被保护程序中注入 VEH Hook 实现轻量行为感知。
- 沙箱 / 虚拟化软件
- 类似沙箱中使用 VEH 捕捉非法执行代码行为;
- 实现用户态保护,如监控执行任意 Shellcode 或注入 DLL。
- 自动化测试 / 接口劫持
- 在不修改程序的情况下替换某些 API 响应值;
- 模拟失败调用、异常路径测试(如 OpenProcess 返回 NULL);
四、典型 Hook 对比分析
| 技术 | 原理 | 可检测性 | 修改内存 | 稳定性 |
|---|---|---|---|---|
| IAT Hook | 修改 Import Table | 中 | 是 | 高 |
| Inline Hook | 改写函数入口指令 | 高 | 是 | 中 |
| VEH Hook | 异常 + 上下文跳转 | 低 | 否 | 高 |
| Shadow SSDT/SSDT Hook | 修改内核函数表 | 极高 | 是 | 易蓝屏(内核) |
五、VEH Hook 的限制
- 无法 Hook 已被内联展开的函数(比如 Release 模式某些 C 函数);
- 一次访问后 PAGE_GUARD 会被清除,需手动恢复;
- 对一些地址(如只读页、DEP 页)设置保护无效;
- 不能用于纯内核态(但可结合 R3-R0 通信);
六、总结:何时选择 VEH Hook?
选择 VEH Hook 通常是在:
- 你想要“隐蔽监控函数调用”;
- 不想触碰目标函数的指令或 IAT;
- 避免被杀软、EDR 检测(反检测);
- 你正在开发调试工具、注入器、反调试壳等;

浙公网安备 33010602011771号