从PAGE_GUARD HOOK 到内存扫描规避
字数 1021 2025-08-22 12:23:19
PAGE_GUARD HOOK 与内存扫描规避技术详解
1. PAGE_GUARD 基础概念
PAGE_GUARD 是 Windows 内存页的一种特殊属性,它为内存提供一次性警报机制:
- 当访问被 PAGE_GUARD 修饰的内存地址时,会触发 STATUS_GUARD_PAGE_VIOLATION 异常
- 触发后,系统会自动移除该内存页的 PAGE_GUARD 属性
- 这种特性常被用于调试和内存保护机制
基本使用示例
#include <iostream>
#include <windows.h>
#include "loader.h"
int main() {
LPVOID lpMem = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT, PAGE_GUARD | PAGE_EXECUTE_READWRITE);
memcpy(lpMem, shellcode, sizeof(shellcode)); // 第一次写入会触发异常
memcpy(lpMem, shellcode, sizeof(shellcode)); // 第二次写入成功
printf("%p\n", lpMem);
((void(*)(void))lpMem)();
system("pause");
}
注意:在调试环境下异常会被处理,直接运行程序会导致崩溃。
2. 基于 PAGE_GUARD 的 Hook 技术
2.1 基本原理
利用 PAGE_GUARD 和单步异常(SINGLE_STEP)实现可持续的 Hook:
- 为目标函数地址设置 PAGE_GUARD 属性
- 当函数被调用时触发异常
- 在异常处理中修改执行流程(实现 Hook)
- 利用单步异常恢复 PAGE_GUARD 属性
2.2 关键数据结构
typedef struct _CIntelligentHookedFunction {
void* from; // 原函数地址
void* to; // 目标函数地址
void** original; // 保存原函数指针
} CIntelligentHookedFunction;
typedef struct _CHooks {
CIntelligentHookedFunction* hookedFunctions;
size_t count;
size_t capacity;
} CHooks;
CHooks g_hooks = { NULL, 0, 0 };
2.3 异常处理回调
LONG NTAPI ExceptionCallBack(struct _EXCEPTION_POINTERS* ExceptionInfo) {
LPVOID ExceptionAddress = ExceptionInfo->ExceptionRecord->ExceptionAddress;
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_GUARD_PAGE) {
// 处理PAGE_GUARD异常
#ifdef _WIN64
uintptr_t ip = (uintptr_t)ExceptionInfo->ContextRecord->Rip;
#else
uintptr_t ip = (uintptr_t)ExceptionInfo->ContextRecord->Eip;
#endif
// 查找匹配的Hook
size_t count;
const CIntelligentHookedFunction* funcs = CHooks_GetHookedFunctions(&count);
for (size_t i = 0; i < count; ++i) {
if (ip == (uintptr_t)funcs[i].from) {
// 修改执行流程
#ifdef _WIN64
*funcs[i].original = (void*)ExceptionInfo->ContextRecord->Rip;
ExceptionInfo->ContextRecord->Rip = (uintptr_t)funcs[i].to;
#else
*funcs[i].original = (void*)ExceptionInfo->ContextRecord->Eip;
ExceptionInfo->ContextRecord->Eip = (uintptr_t)funcs[i].to;
#endif
break;
}
}
// 设置单步异常标志
ExceptionInfo->ContextRecord->EFlags |= 0x100;
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
// 处理单步异常,恢复PAGE_GUARD
#ifdef _WIN64
uintptr_t ip = (uintptr_t)ExceptionInfo->ContextRecord->Rip;
#else
uintptr_t ip = (uintptr_t)ExceptionInfo->ContextRecord->Eip;
#endif
size_t count;
const CIntelligentHookedFunction* funcs = CHooks_GetHookedFunctions(&count);
for (size_t i = 0; i < count; ++i) {
if (ip == (uintptr_t)funcs[i].from) {
AddPageGuardProtect(funcs[i].from);
break;
}
}
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
2.4 辅助函数
// 添加PAGE_GUARD保护
static void AddPageGuardProtect(void* addr) {
DWORD oldProtect;
MEMORY_BASIC_INFORMATION mbi;
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
VirtualQuery(addr, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
VirtualProtect(addr, sysInfo.dwPageSize, mbi.Protect | PAGE_GUARD, &oldProtect);
}
// 初始化Hook系统
void CHooks_Init() {
g_hooks.hookedFunctions = NULL;
g_hooks.count = 0;
g_hooks.capacity = 0;
AddVectoredExceptionHandler(1, &ExceptionCallBack);
}
// 添加Hook
void CHooks_AddHook(void* _Function, void* _Hooked, void** _Original) {
if (g_hooks.count == g_hooks.capacity) {
g_hooks.capacity = g_hooks.capacity == 0 ? 4 : g_hooks.capacity * 2;
g_hooks.hookedFunctions = (CIntelligentHookedFunction*)realloc(
g_hooks.hookedFunctions,
g_hooks.capacity * sizeof(CIntelligentHookedFunction));
if (!g_hooks.hookedFunctions) {
exit(1);
}
}
AddPageGuardProtect(_Function);
CIntelligentHookedFunction hook = { _Function, _Hooked, _Original };
g_hooks.hookedFunctions[g_hooks.count++] = hook;
}
2.5 使用示例
typedef int(WINAPI* pMessageBoxW)(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText,
_In_opt_ LPCWSTR lpCaption, _In_ UINT uType);
pMessageBoxW oriMessageBoxW = MessageBoxW;
int WINAPI myMessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText,
_In_opt_ LPCWSTR lpCaption, _In_ UINT uType) {
return oriMessageBoxW(hWnd, L"Hooked", lpCaption, uType);
}
int main() {
CHooks_Init();
CHooks_AddHook(MessageBoxW, myMessageBoxW, (void**)&oriMessageBoxW);
// 测试代码
MessageBoxW(NULL, L"Original", L"Test", MB_OK);
}
3. 内存扫描规避技术
3.1 基本原理
通过 Hook 内存分配函数,为敏感内存区域自动添加 PAGE_GUARD 属性:
- Hook ZwAllocateVirtualMemory
- 检测内存分配请求
- 对符合条件的分配添加 PAGE_GUARD 属性
- 通过 VEH 处理异常
3.2 实现代码
// 修改后的异常处理
LONG NTAPI ExceptionCallBack(struct _EXCEPTION_POINTERS* ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_GUARD_PAGE) {
lastGuardAddress = (LPVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1];
ExceptionInfo->ContextRecord->EFlags |= 0x100;
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
if (lastGuardAddress != nullptr) {
AddPageGuardProtect(lastGuardAddress);
lastGuardAddress = nullptr;
}
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
// Hook ZwAllocateVirtualMemory
HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
pZwAllocateVirtualMemory ZwAllocateVirtualMemory =
(pZwAllocateVirtualMemory)(GetProcAddress(hNtdll, "ZwAllocateVirtualMemory"));
pZwAllocateVirtualMemory oriZwAllocateVirtualMemory = ZwAllocateVirtualMemory;
NTSTATUS NTAPI myZwAllocateVirtualMemory(
_In_ HANDLE ProcessHandle,
_Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID* BaseAddress,
_In_ ULONG_PTR ZeroBits,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG AllocationType,
_In_ ULONG Protect) {
NTSTATUS status = oriZwAllocateVirtualMemory(
ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
do {
if (status != 0) break;
if (ProcessHandle != GetCurrentProcess()) break;
if (AllocationType != MEM_COMMIT) break;
if (Protect != PAGE_EXECUTE_READWRITE) break;
// 符合条件的分配添加PAGE_GUARD
status = oriZwAllocateVirtualMemory(
ProcessHandle, BaseAddress, ZeroBits, RegionSize,
AllocationType, Protect | PAGE_GUARD);
} while (false);
return status;
}
// 初始化
void VEH_init() {
AddVectoredExceptionHandler(1, &ExceptionCallBack);
}
// 安装Hook
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oriZwAllocateVirtualMemory, myZwAllocateVirtualMemory);
DetourTransactionCommit();
3.3 优化建议
-
扩展保护范围:除了 Hook ZwAllocateVirtualMemory,还可以 Hook NtProtectVirtualMemory,对任何修改为可执行的内存添加 PAGE_GUARD
-
条件筛选:可以根据内存大小、分配模式等进一步筛选需要保护的内存区域
-
性能考虑:频繁的异常处理会影响性能,需要权衡保护强度和性能开销
4. 技术限制与注意事项
-
调试环境差异:调试器会处理某些异常,导致行为与直接运行不同
-
完整性保护:某些安全软件会检测和阻止这类 Hook 技术
-
兼容性问题:不同 Windows 版本可能有细微的行为差异
-
性能影响:异常处理会带来一定的性能开销
5. 参考资源
- Hooks: Hooking using PAGE_GUARD
- Microsoft Docs: PAGE_GUARD
- Microsoft Docs: Vectored Exception Handling