Log in

View Full Version : PAGE_GUARD protected memory


0rp
March 28th, 2005, 15:01
hi,

i'm trying to use the PAGE_GUARD flag for memoryregions to get breakpoint functionality without using a real debugging loop.

to use PAGE_GUARD exceptions, i add an exceptionhandler to the SEH-chain with the AddVectoredExceptionHandler api

this works very well and i can detect memoryaccess. the problem is, that after accessing a PAGE_GUARDed region, the PAGE_GUARD-flag will be removed from that region and to detect more accesses, PAGE_GUARD must be re-enabled. the question is how or better when.

if i enable PAGE_GUARD in my exceptionhandler, the trapping instruction will never be executable, so this wouldn't work at all.

in other words: how can i re-enable PAGE_GUARD for memoryregions?


thx

goggles99
March 28th, 2005, 16:42
This is a good situation for the use of the trace flag. With it, you can specify a the number of instructions to execute before another exception is triggered.

I would suggest looking over this atricle.
New Vectored Exception Handling in Windows XP
by Matt Pietrek
http://msdn.microsoft.com/msdnmag/issues/01/09/hood/default.aspx

and more specifically this example (figure 2 from that article).
http://msdn.microsoft.com/msdnmag/issues/01/09/hood/figures.asp

Code:

// Set trace flag in the EFlags register so that only one
// instruction will execute before we get a STATUS_SINGLE_STEP
// (see below)
pExceptionInfo->ContextRecord->EFlags |= 0x00000100;

0rp
March 29th, 2005, 06:16
singlestepping could work
thanks for the hint

homersux
March 29th, 2005, 16:11
Can you elaborate on the statement "if i enable PAGE_GUARD in my exceptionhandler, the trapping instruction will never be executable, so this wouldn't work at all.". I don't see why you cannot renable
PAGE_GUARD in the trap handler.

0rp
March 29th, 2005, 16:50
if i reenable PAGE_GUARD in my handler and return EXCEPTION_CONTINUE_EXECUTION, the same instruction will throw a new STATUS_GUARD_PAGE_VIOLATION

[NtSC]
March 30th, 2005, 04:28
You would need to check the length of the triggering opcode and update the EIP reg before you return back to code to avoid the same instruction triggering u again,no?

Fake51
March 30th, 2005, 05:20
I'd say he is tracing and not debugging, hence he wouldn't want to step over the opcode but execute it.

Either use goggles suggestion, or figure out opcode length and place an int 3.

Fake

0rp
March 30th, 2005, 11:03
does any1 has an idea, why i get a stack overflow for this code?

Code:
DWORD addr;

LONG WINAPI handler(PEXCEPTION_POINTERS ExceptionInfo)
{
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
{
addr = (DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress;
ExceptionInfo->ContextRecord->EFlags |= 0x00000100;
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD oldprotect;

VirtualQuery((void *)addr, &mbi, sizeof(mbi));
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.AllocationProtect | PAGE_GUARD, &oldprotect);
return EXCEPTION_CONTINUE_EXECUTION;
}

return EXCEPTION_CONTINUE_SEARCH;
}


int main(int argc, char **args)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD oldprotect, len;
BYTE *mem;

len = 100;
mem = new BYTE[len];

AddVectoredExceptionHandler(1, handler);

VirtualQuery(mem, &mbi, sizeof(mbi));
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.AllocationProtect | PAGE_GUARD, &oldprotect);

mem[10] = 1234;
mem[11] = 1234;
mem[12] = 1234;

VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.AllocationProtect, &oldprotect);

printf("done\n";

return 0;
}


this is a very weird problem
accessing protected memory like mem[10]=1234 doesnt work
but if i fill mem with NOPs and a RET and execute this mem with a CALL, it works fine

0rp
March 30th, 2005, 11:54
addr = (DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress;

this is wrong

instead of saving the address _where_ the exception occured, i should save the adress of the used memory

bilbo
March 30th, 2005, 11:54
Little bug!

You want to remove the page guard protection, in your exception handler after the single step, not to put it again, isn't it?

So simply replace
Code:

..., mbi.AllocationProtect | PAGE_GUARD, ...

with
Code:

..., mbi.AllocationProtect & ~PAGE_GUARD, ...


Regards, bilbo

0rp
March 30th, 2005, 11:59
Quote:
[Originally Posted by bilbo]You want to remove the page guard protection, in your exception handler after the single step, not to put it again, isn't it?



no
the page guard protection will automatically be removed by the os and i have to re-enable it if i'm interested in further accesses

disavowed
March 30th, 2005, 14:15
Quote:
[Originally Posted by Fake51]I'd say he is tracing and not debugging, hence he wouldn't want to step over the opcode but execute it.

I wouldn't really recommend this, but you could do it: have your exception code emulate the instruction, then step over it. Probably crap-loads more work than you want to do, though

kao
March 31st, 2005, 04:02
Hmm... After catching SINGLE_STEP exception you should remove SINGLE_STEP flag, shouldn't you?

bilbo
March 31st, 2005, 04:44
You are right, 0rp, PAGE_GUARD is removed by O.S., and no, kao, also SINGLE_STEP is removed by O.S.

Now, the real problem is that
Code:

addr = (DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress;
is the address containing the offending opcode (the EIP contents) and not the guarded page address!

So you want to assign addr as
Code:

addr = ExceptionInfo->ExceptionRecord->ExceptionInformation[1];


Best regards, bilbo

EDIT: OOPS, I DIDN'T SEE 0rp MESSAGE #9 - YOU DID ALREADY FIND THE REASON!

0rp
March 31st, 2005, 08:10
Quote:
[Originally Posted by bilbo]EDIT: OOPS, I DIDN'T SEE 0rp MESSAGE #9 - YOU DID ALREADY FIND THE REASON!



yes, but i didn't know that exception param 1 is the memaddress