@@ -367,6 +367,54 @@ def trigger(self, dbg, exc):
367
367
for i in range (NB_NOP_IN_PAGE + 1 ):
368
368
assert TSTBP .DATA [i ] == addr + i
369
369
370
+ def test_memory_breakpoint_trigger_multipage (proc32_64_debug ):
371
+ """Check that a memory breakpoint triggering on multiple page on the same instruction restore are correctly restored on all pages"""
372
+
373
+ class MultiPageMemBP (windows .debug .MemoryBreakpoint ):
374
+ ALL_TRIGGER_ADDR = []
375
+
376
+ def trigger (self , dbg , exc ):
377
+ pc_fault_addr = dbg .current_thread .context .pc
378
+ self .ALL_TRIGGER_ADDR .append (pc_fault_addr )
379
+ print (hex (pc_fault_addr ))
380
+ # Stop when we have a breakpoint in the 2nd page of the alloc
381
+ if shellcodeaddr + 0x1000 <= pc_fault_addr <= shellcodeaddr + 0x2000 :
382
+ dbg .current_process .exit ()
383
+
384
+ # Trigger a write that will write on both page at once,
385
+ # Triggering both pages mem-bp on the same instruction.
386
+ # Then call an instruction at the end of page to see if both page of mem-bp still trigger the BP
387
+
388
+ shellcodeaddr = proc32_64_debug .virtual_alloc (0x2000 )
389
+
390
+ if proc32_64_debug .bitness == 64 :
391
+ shellcode = x64 .MultipleInstr ()
392
+ shellcode += x64 .Mov ("RAX" , shellcodeaddr + 0xffe )
393
+ shellcode += x64 .Mov ("RCX" , 0xc3909090 ) # Nopnopnopret
394
+ shellcode += x64 .Mov (x64 .mem ("[RAX]" ), "ECX" ) # Will write on both page at once
395
+ shellcode += x64 .Push ("RAX" )
396
+ shellcode += x64 .Ret () # Jump on the nop + ret
397
+ else :
398
+ shellcode = x86 .MultipleInstr ()
399
+ shellcode += x86 .Mov ("EAX" , shellcodeaddr + 0xffe )
400
+ shellcode += x86 .Mov ("ECX" , 0xc3909090 ) # Nopnopnopret
401
+ shellcode += x86 .Mov (x86 .mem ("[EAX]" ), "ECX" ) # Will write on both page at once
402
+ shellcode += x86 .Push ("EAX" )
403
+ shellcode += x86 .Ret () # Jump on the nop + ret
404
+
405
+ d = windows .debug .Debugger (proc32_64_debug )
406
+ bp = MultiPageMemBP (addr = shellcodeaddr , size = 0x2000 , events = "XW" )
407
+ proc32_64_debug .write_memory (shellcodeaddr , shellcode .get_code ())
408
+ d .add_bp (bp )
409
+ proc32_64_debug .create_thread (shellcodeaddr , 0 )
410
+
411
+ d .loop ()
412
+ # Check that the 2 nop at the end of the first page of the membp trigger
413
+ # If access right where not correctly restored: this would not trigger on the first page
414
+ assert shellcodeaddr + 0xffe in bp .ALL_TRIGGER_ADDR
415
+ assert shellcodeaddr + 0xfff in bp .ALL_TRIGGER_ADDR
416
+ assert shellcodeaddr + 0x1000 in bp .ALL_TRIGGER_ADDR
417
+
370
418
371
419
# breakpoint remove
372
420
import threading
@@ -700,4 +748,6 @@ def WaitForDebugEvent_KeyboardInterrupt(debug_event):
700
748
assert proc32_64_debug .read_memory (addr , len (TEST_CODE )) == TEST_CODE
701
749
assert bad_thread .context .pc == addr
702
750
else :
703
- raise ValueError ("Should have raised" )
751
+ raise ValueError ("Should have raised" )
752
+
753
+
0 commit comments