Search code examples
winapiseh

Win32 GUARD Memory : How can I use PAGE_GUARD to implement stack


I'm writing a tiny byte-code, interpreted language (or framework? vm?). I know Windows use PAGE_GUARD on stack, and I want to use this.

First, I reserve virtual memory and do MEM_COMMIT/PAGE_GUARD on one page.

pStack->end = VirtualAlloc(NULL, MaxSize, MEM_RESERVE, PAGE_READWRITE);
if (pStack->end != NULL)
{
    pStack->bp = pStack->sp = pStack->base = pStack->end + MaxSize;

    if (VirtualAlloc(pStack->base - PageSize, PageSize, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD) != NULL)

(I know I should commit (non PAGE_GUARD) one page, but it's for testing PAGE_GUARD.)

and I write __except as follows:

__except (StackOnSEHExcept(GetExceptionInformation())) {}

/* A */

...
DWORD StackOnSEHExcept(PEXCEPTION_POINTERS exc)
{
    if (exc->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
    {
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    else
    {
        return EXCEPTION_CONTINUE_SEARCH;
    }
}

(I also know I should commit/guard the next page, but it's for testing, too.)

When I touch memory of stack, STATUS_GUARD_PAGE_VIOLATION is occured. but after that, /* A */ is run;

Doesn't Windows unmark PAGE_GUARD after exception occur? and why doesn't this code work well?


And, I don't know how to do this part: (I also know I should commit/guard the next page, but it's for testing, too.). How can I do? I think I should 1. get guarded-page's address 2. commit/guard the next page, but I don't know how to do 1.

edit: I know how to do 1. the guarded address is here:

exc->ExceptionRecord->ExceptionInformation[1]

Thanks for all your help!


Solution

  • Doesn't Windows unmark PAGE_GUARD after exception occur?

    http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx

    ... Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time access alarm.

    Try this:

    DWORD OnSEH()
    {
        ::OutputDebugString( L"SEH!\n" );
        return (DWORD) EXCEPTION_CONTINUE_EXECUTION;
    }
    
    static void Test()
    {
        const DWORD pageSize = 4096;
        void* baseAddr = ::VirtualAlloc(NULL, pageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
    
        DWORD oldAttr = 0;
        void* protectedAddr = baseAddr;
        BOOL ok = ::VirtualProtect( protectedAddr, pageSize, PAGE_READWRITE | PAGE_GUARD, &oldAttr );
        if( !ok ) {
            int lastError = ::GetLastError(); lastError;
            return;
        }
    
        ::OutputDebugString( L"Reading the guarded page\n" );
    
        __try {
            int* testAddr = static_cast<int*>( protectedAddr );
            int value = *testAddr; value;
    
            ::OutputDebugString( L"Continue execution\n" );
        }
        __except( OnSEH() ) {}