@@ -367,6 +367,54 @@ def trigger(self, dbg, exc):
367367 for i in range (NB_NOP_IN_PAGE + 1 ):
368368 assert TSTBP .DATA [i ] == addr + i
369369
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+
370418
371419# breakpoint remove
372420import threading
@@ -700,4 +748,6 @@ def WaitForDebugEvent_KeyboardInterrupt(debug_event):
700748 assert proc32_64_debug .read_memory (addr , len (TEST_CODE )) == TEST_CODE
701749 assert bad_thread .context .pc == addr
702750 else :
703- raise ValueError ("Should have raised" )
751+ raise ValueError ("Should have raised" )
752+
753+
0 commit comments