从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:

  1. 为目标函数地址设置 PAGE_GUARD 属性
  2. 当函数被调用时触发异常
  3. 在异常处理中修改执行流程(实现 Hook)
  4. 利用单步异常恢复 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 属性:

  1. Hook ZwAllocateVirtualMemory
  2. 检测内存分配请求
  3. 对符合条件的分配添加 PAGE_GUARD 属性
  4. 通过 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 优化建议

  1. 扩展保护范围:除了 Hook ZwAllocateVirtualMemory,还可以 Hook NtProtectVirtualMemory,对任何修改为可执行的内存添加 PAGE_GUARD

  2. 条件筛选:可以根据内存大小、分配模式等进一步筛选需要保护的内存区域

  3. 性能考虑:频繁的异常处理会影响性能,需要权衡保护强度和性能开销

4. 技术限制与注意事项

  1. 调试环境差异:调试器会处理某些异常,导致行为与直接运行不同

  2. 完整性保护:某些安全软件会检测和阻止这类 Hook 技术

  3. 兼容性问题:不同 Windows 版本可能有细微的行为差异

  4. 性能影响:异常处理会带来一定的性能开销

5. 参考资源

  1. Hooks: Hooking using PAGE_GUARD
  2. Microsoft Docs: PAGE_GUARD
  3. Microsoft Docs: Vectored Exception Handling
PAGE_ GUARD HOOK 与内存扫描规避技术详解 1. PAGE_ GUARD 基础概念 PAGE_ GUARD 是 Windows 内存页的一种特殊属性,它为内存提供一次性警报机制: 当访问被 PAGE_ GUARD 修饰的内存地址时,会触发 STATUS_ GUARD_ PAGE_ VIOLATION 异常 触发后,系统会自动移除该内存页的 PAGE_ GUARD 属性 这种特性常被用于调试和内存保护机制 基本使用示例 注意 :在调试环境下异常会被处理,直接运行程序会导致崩溃。 2. 基于 PAGE_ GUARD 的 Hook 技术 2.1 基本原理 利用 PAGE_ GUARD 和单步异常(SINGLE_ STEP)实现可持续的 Hook: 为目标函数地址设置 PAGE_ GUARD 属性 当函数被调用时触发异常 在异常处理中修改执行流程(实现 Hook) 利用单步异常恢复 PAGE_ GUARD 属性 2.2 关键数据结构 2.3 异常处理回调 2.4 辅助函数 2.5 使用示例 3. 内存扫描规避技术 3.1 基本原理 通过 Hook 内存分配函数,为敏感内存区域自动添加 PAGE_ GUARD 属性: Hook ZwAllocateVirtualMemory 检测内存分配请求 对符合条件的分配添加 PAGE_ GUARD 属性 通过 VEH 处理异常 3.2 实现代码 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