VirtualProtect locks whole page and Raises an Exception on access and removes the PAGE_GUARD Memory Protection.
In the Exception Handler you watch for a your small block
If except->ExceptionRecord->ExceptionAddress is not within your watch block
you reset the protection within Your Exception Handler.
reset the ContextRecord->Rip to next instruction and return EXECEPTION_CONTINUE_EXECUTION
see below for a sample code
#include <stdio.h>
#include <windows.h>
typedef struct _S1{
int field_a;
int field_b;
} S1, *PS1;
//putting guarded data in a seperate section for convenience
#pragma data_seg(push, MyGuardedSection, ".guarded")
S1 t1 = {0, 0};
#pragma data_seg(pop, MyGuardedSection)
DWORD oldprot = 0;
int filter(unsigned int code, struct _EXCEPTION_POINTERS *except){
if (code == EXCEPTION_GUARD_PAGE &&
except->ExceptionRecord->ExceptionAddress != (&(t1.field_b))) {
VirtualProtect(&t1.field_b, sizeof(t1.field_b), 0x140, &oldprot);
except->ContextRecord->Rip += 6;
return EXCEPTION_CONTINUE_EXECUTION;
}
printf("%x\n%p\n",
except->ExceptionRecord->ExceptionCode,
except->ExceptionRecord->ExceptionAddress);
return EXCEPTION_EXECUTE_HANDLER;
}
int main(void){
DWORD counter = 0;
DWORD loopcount = 0;
VirtualProtect(&t1.field_b, sizeof(t1.field_b), 0x140, &oldprot);
__try {
while (loopcount < 2) {
while (counter < 0x30) {
t1.field_a++; //this will raise guard page exception
counter++; // we return here from handler after reguarding
printf("%x ", counter);
Sleep(0x10);
}
counter = 0;
loopcount += 1;
printf("\nwe have reset guard page exception 0x60 times \n");
}
printf("we access our field now \n");
t1.field_b = 0xdead; //this again will raise exception and we execute handler
}
__except (filter(GetExceptionCode(), GetExceptionInformation())) {
//removing page guard
VirtualProtect(&t1.field_b, sizeof(t1.field_b), 0x40, &oldprot);
printf("t1.field_b = %x\n", t1.field_b);
t1.field_b = 0xdead;
printf("t1.field_b = %x\n", t1.field_b); // no exception
printf("Handler for PG %x\n", GetExceptionCode());
}
}
compiled and executed
:\>cl /Zi /W4 /analyze /EHsc /nologo vlock.cpp /link /release
vlock.cpp
:\>vlock.exe
1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30
we have reset guard page exception 0x60 times
1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30
we have reset guard page exception 0x60 times
we access our field now
c0000005
00007FF7CA131159
t1.field_b = 0
t1.field_b = dead
Handler for PG c0000005
VirtualProtect
to set up a guard page, catch the exception via SEH/VEH and then resume execution ...VirtualProtect
I can lock a whole memory page, but I'm looking for a way to lock something smaller, like astruct
.