带有VirtualProtect的PAGE_GUARD不会在执行访问时引发异常

时间:2018-05-28 03:37:11

标签: c++ winapi exception

我正在尝试使用PAGE_GUARD挂钩函数,但在调用页面/地址时不会引发任何异常。

void HookMe(){
    printf("Not hooked\n");
}
void GoodFnc(){
    printf("Hooked!\n");
}
long ExceptionHandler(PEXCEPTION_POINTERS ex){
    printf("ExceptionHandler called\n");
}
/*Called by CreateThread in main*/
DWORD WINAPI ExceptionTesting(LPVOID) {
    DWORD old = 0;
    AddVectoredExceptionHandler(1, ExceptionHandler);
    if (VirtualProtect((LPVOID)HookMe, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old))
        printf("PAGE_GUARD set\n");
    //This was for testing:
    //*(char*)0 = 0;//ExceptionHandler gets called when ACCESS_VIOLATION happens
    while (1) {
        HookMe();
        Sleep(1000);
    }
    return 0;
}

上面的代码每秒只显示PAGE_GUARD set然后Not hooked,而不会引发任何异常。

我还确保HookMe()位于与ExceptionHandler(...)ExceptionTesting(LPVOID)

不同的内存页面中

导致任何类型的异常,例如ACCESS_VIOLATION(如无限循环上方的注释中所示)将导致调用ExceptionHandler。

3 个答案:

答案 0 :(得分:2)

根据您的编译器,可能会内联对HookMe的调用。检查生成的代码。你应该能够在__declspec(noinline)的声明中用HookMe之类的东西来打败这个。 (MS VC ++)。请注意,即使在所有调用中内联函数,您也可以获取函数的地址!

答案 1 :(得分:2)

documentation for VirtualProtect表示受保护的地址必须是使用VirtualAlloc(或VirtualAllocEx)获取的保留区域的一部分。程序中的代码没有以这种方式分配。

此外,保护是在页面基础上完成的(通常是4K),因此上面示例中代码的所有都可能受到保护,并且当调用时,警卫会立即关闭VirtualProtect已退回 - 而不是在Hook被调用时。

答案 2 :(得分:1)

VirtualProtect

  

更改对已提交的网页区域的保护   调用进程的虚拟地址空间。

PAGES - 不是单字节。我们至少可以在页面(0x1000)字节上设置PAGE_GUARD属性。因此,当您尝试将PAGE_GUARD设置为某个函数时 - 您不仅将保护属性设置为它,而且将其设置为围绕它的许多字节(之前和之后)。如果您的代码是这样的代码(无论如何您的代码是伪代码,甚至不能编译) - 所有保护异常将在VirtualProtect返回后更快 - 在调用后的下一条指令上。如果您只希望保护页面影响单个功能 - 您需要将其放在单独的exe部分中,例如#pragma code_seg。也可以注意 - 不需要任何无限循环或单独的线程创建测试

//#pragma code_seg(".guard")
void HookMe(){
    MessageBoxW(0, 0, L"HookMe", MB_ICONINFORMATION);
}
#pragma code_seg()

LONG NTAPI ExceptionHandler(::PEXCEPTION_POINTERS pep)
{
    if (pep->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
    {
        WCHAR msg[64];
        swprintf(msg, L"guard violation at %p (%p)", pep->ExceptionRecord->ExceptionAddress, HookMe);
        MessageBoxW(0, msg, L"ExceptionHandler", MB_ICONWARNING);
        return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

void gtest()
{
    if (PVOID pv = AddVectoredExceptionHandler(TRUE, ExceptionHandler))
    {
        ULONG op;
        if (VirtualProtect(HookMe, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &op))
        {
            HookMe();
        }
        RemoveVectoredExceptionHandler(pv);
    }
}