diff --git a/tests/test_debugger.py b/tests/test_debugger.py index 09bd3fc..f2d8401 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -8,8 +8,8 @@ import windows.generated_def as gdef import windows.native_exec.simple_x86 as x86 import windows.native_exec.simple_x64 as x64 -from conftest import generate_pop_and_exit_fixtures, pop_proc_32, pop_proc_64 -from pfwtest import * +from .conftest import generate_pop_and_exit_fixtures, pop_proc_32, pop_proc_64 +from .pfwtest import * proc32_debug = generate_pop_and_exit_fixtures([pop_proc_32], ids=["proc32dbg"], dwCreationFlags=gdef.DEBUG_PROCESS) proc64_debug = generate_pop_and_exit_fixtures([pop_proc_64], ids=["proc64dbg"], dwCreationFlags=gdef.DEBUG_PROCESS) @@ -46,7 +46,7 @@ def test_simple_standard_breakpoint(proc32_64_debug): class TSTBP(windows.debug.Breakpoint): def trigger(self, dbg, exc): assert dbg.current_process.pid == proc32_64_debug.pid - assert dbg.current_process.read_memory(self.addr, 1) == "\xcc" + assert dbg.current_process.read_memory(self.addr, 1) == b"\xcc" assert dbg.current_thread.context.pc == self.addr d.current_process.exit() @@ -85,7 +85,7 @@ def test_multiple_hwx_breakpoint(proc32_64_debug): assert dbg.current_thread.context.pc == self.addr assert dbg.current_thread.context.Dr7 != 0 assert TSTBP.COUNTER == self.expec_before - assert dbg.current_process.read_memory(self.addr, 1) != "\xcc" + assert dbg.current_process.read_memory(self.addr, 1) != b"\xcc" TSTBP.COUNTER += 1 if TSTBP.COUNTER == 4: d.current_process.exit() @@ -126,7 +126,7 @@ def test_four_hwx_breakpoint_fail(proc32_64_debug): proc32_64_debug.create_thread(addr, 0) with pytest.raises(ValueError) as e: d.loop() - assert "DRx" in e.value.message + assert "DRx" in e.value.args[0] def test_hwx_breakpoint_are_on_all_thread(proc32_64_debug): @@ -182,7 +182,7 @@ def test_simple_breakpoint_name_addr(proc32_64_debug, bptype): d.loop() assert TSTBP.COUNTER == 1 -import dbg_injection +from . import dbg_injection def test_hardware_breakpoint_name_addr(proc32_64_debug): """Check that name addr in HXBP are trigger in all threads""" @@ -357,7 +357,7 @@ import threading @python_injection @pytest.mark.parametrize("bptype", [windows.debug.FunctionParamDumpHXBP, windows.debug.FunctionParamDumpBP]) def test_standard_breakpoint_self_remove(proc32_64_debug, bptype): - data = [] + data = set() def do_check(): proc32_64_debug.execute_python_unsafe("open(u'FILENAME1')").wait() @@ -371,20 +371,21 @@ def test_standard_breakpoint_self_remove(proc32_64_debug, bptype): addr = exc.ExceptionRecord.ExceptionAddress ctx = dbg.current_thread.context filename = self.extract_arguments(dbg.current_process, dbg.current_thread)["lpFileName"] - data.append(filename) + data.add(filename) if filename == u"FILENAME2": dbg.del_bp(self) d = windows.debug.Debugger(proc32_64_debug) - d.add_bp(TSTBP("kernel32!CreateFileW")) + d.add_bp(TSTBP("kernelbase!CreateFileW")) threading.Thread(target=do_check).start() d.loop() - assert data == [u"FILENAME1", u"FILENAME2"] + assert data >= set([u"FILENAME1", u"FILENAME2"]) + assert u"FILENAME3" not in data @python_injection @pytest.mark.parametrize("bptype", [windows.debug.FunctionParamDumpHXBP, windows.debug.FunctionParamDumpBP]) def test_standard_breakpoint_remove(proc32_64_debug, bptype): - data = [] + data = set() def do_check(): proc32_64_debug.execute_python_unsafe("open(u'FILENAME1')").wait() @@ -396,19 +397,19 @@ def test_standard_breakpoint_remove(proc32_64_debug, bptype): class TSTBP(bptype): TARGET = windows.winproxy.CreateFileW def trigger(self, dbg, exc): - # import pdb;pdb.set_trace() addr = exc.ExceptionRecord.ExceptionAddress ctx = dbg.current_thread.context filename = self.extract_arguments(dbg.current_process, dbg.current_thread)["lpFileName"] - data.append(filename) + data.add(filename) d = windows.debug.Debugger(proc32_64_debug) - the_bp = TSTBP("kernel32!CreateFileW") + the_bp = TSTBP("kernelbase!CreateFileW") # import pdb;pdb.set_trace() d.add_bp(the_bp) threading.Thread(target=do_check).start() d.loop() - assert data == [u"FILENAME1", u"FILENAME2"] + assert data >= set([u"FILENAME1", u"FILENAME2"]) + assert u"FILENAME3" not in data def get_generate_read_at_for_proc(target): @@ -540,6 +541,8 @@ def test_exe_in_module_list(proc32_64_debug): class MyDbg(windows.debug.Debugger): def on_exception(self, exception): exename = os.path.basename(proc32_64_debug.peb.imagepath.str) + assert exename.endswith(".exe") + exename = exename[:-len(".exe")] # Remove the .exe from the module name this_process_modules = self._module_by_process[self.current_process.pid] assert exename and exename in this_process_modules.keys() self.current_process.exit() @@ -562,6 +565,8 @@ def test_bp_exe_by_name(proc32_64_debug): exepe = proc32_64_debug.peb.exe entrypoint = exepe.get_OptionalHeader().AddressOfEntryPoint exename = os.path.basename(proc32_64_debug.peb.imagepath.str) + assert exename.endswith(".exe") + exename = exename[:-len(".exe")] # Remove the .exe from the module name d = windows.debug.Debugger(proc32_64_debug) # The goal is to test bp of format 'exename!offset' so we craft a string based on the entrypoint d.add_bp(TSTBP("{name}!{offset}".format(name=exename, offset=entrypoint))) @@ -579,7 +584,7 @@ def test_keyboardinterrupt_when_bp_event(proc32_64_debug, monkeypatch): def WaitForDebugEvent_KeyboardInterrupt(debug_event): real_WaitForDebugEvent(debug_event) - if not debug_event.code == gdef.EXCEPTION_DEBUG_EVENT: + if not debug_event.dwDebugEventCode == gdef.EXCEPTION_DEBUG_EVENT: return if not debug_event.u.Exception.ExceptionRecord.ExceptionCode in [gdef.EXCEPTION_BREAKPOINT, gdef.STATUS_WX86_BREAKPOINT]: return # Not a BP @@ -592,7 +597,7 @@ def test_keyboardinterrupt_when_bp_event(proc32_64_debug, monkeypatch): # This should emultate a ctrl+c on when waiting for the event # Our goal is to set the target back to a good state :) - TEST_CODE = "\xeb\xfe\xff\xff\xff\xff\xff" # Loop + invalid instr + TEST_CODE = b"\xeb\xfe\xff\xff\xff\xff\xff" # Loop + invalid instr addr = proc32_64_debug.virtual_alloc(0x1000) proc32_64_debug.write_memory(addr, TEST_CODE) d = windows.debug.Debugger(proc32_64_debug) diff --git a/windows/debug/debugger.py b/windows/debug/debugger.py index c90ebfe..593fc1b 100644 --- a/windows/debug/debugger.py +++ b/windows/debug/debugger.py @@ -19,9 +19,13 @@ from .breakpoints import * #from windows.syswow64 import CS_32bits from windows.winobject.exception import VectoredException +from windows.pycompat import basestring + PAGE_SIZE = 0x1000 +class DebuggerError(Exception): + pass class DEBUG_EVENT(DEBUG_EVENT): KNOWN_EVENT_CODE = dict((x,x) for x in [EXCEPTION_DEBUG_EVENT, @@ -102,7 +106,7 @@ class Debugger(object): self.target = None # Remove ref to process -> GC -> CloseHandle -> process is destroyed windows.winproxy.DebugActiveProcessStop(tpid) return - for proc in targets: + for proc in list(targets): self.detach(proc) del targets return @@ -110,7 +114,7 @@ class Debugger(object): raise ValueError("Detach accept only WinProcess") self.disable_all_memory_breakpoints(target) - for bp in self.breakpoints[target.pid].values(): + for bp in list(self.breakpoints[target.pid].values()): if not bp.apply_to_target(target): target_threads = [t for t in target.threads if t.tid in self.threads] bp_threads = [] @@ -173,7 +177,7 @@ class Debugger(object): def _debug_event_generator(self): while True: - debug_event = DEBUG_EVENT() + debug_event = gdef.DEBUG_EVENT() try: winproxy.WaitForDebugEvent(debug_event) except KeyboardInterrupt as e: @@ -181,7 +185,7 @@ class Debugger(object): # BP trigger will not be called. # So AT LEAST quit loop with a coherent context # Fix thread PC if we just triggered a BP - if (debug_event.code == gdef.EXCEPTION_DEBUG_EVENT and + if (debug_event.dwDebugEventCode == gdef.EXCEPTION_DEBUG_EVENT and debug_event.u.Exception.ExceptionRecord.ExceptionCode in [gdef.EXCEPTION_BREAKPOINT, gdef.STATUS_WX86_BREAKPOINT]): # This is a breakpoint: One of ours ? bp_addr = debug_event.u.Exception.ExceptionRecord.ExceptionAddress @@ -207,7 +211,9 @@ class Debugger(object): def _add_exe_to_module_list(self, create_process_event): """Add the intial exe file described by create_process_event to the list of module in the process""" exe_path = self.current_process.get_mapped_filename(create_process_event.lpBaseOfImage) - exe_name = os.path.basename(exe_path) + exe_name = os.path.basename(exe_path).lower() + if exe_name.endswith(".exe"): + exe_name = exe_name[:-len(".exe")] #print("Exe name is {0}".format(exe_name)) self._module_by_process[self.current_process.pid][exe_name] = windows.pe_parse.GetPEFile(create_process_event.lpBaseOfImage, self.current_process) #self._setup_pending_breakpoints_load_dll(exe_name) # Already setup in _setup_pending_breakpoints_new_process @@ -251,7 +257,13 @@ class Debugger(object): if api not in exports: dbgprint("Error resolving <{0}> in <{1}>".format(addr, target), "DBG") raise ValueError("Unknown API <{0}> in DLL {1}".format(api, dll)) - return exports[api] + target_addr = exports[api] + if isinstance(target_addr, basestring): + target_string = target_addr.replace(".", "!") + dbgprint("<{0}> is export proxy to <{1}>".format(addr, target_string), "DBG") + # Possible infinite loop ? + return self._resolve(target_string, target) + return target_addr def add_pending_breakpoint(self, bp, target): self._pending_breakpoints_new[target].append(bp) @@ -285,6 +297,9 @@ class Debugger(object): raise ValueError("Cannot setup STANDARD_BP on {0}".format(target)) addr = self._resolve(bp.addr, target) + + # raise DebuggerError("Could not set breakpoint {0} at <{1}>".format(bp, bp.addr)) + if addr is None: return False dbgprint("Setting soft-BP at <{0:#x}> in <{1}>".format(addr, target), "DBG") @@ -821,6 +836,9 @@ class Debugger(object): del self._breakpoint_to_reput[self.current_thread.tid] return retvalue + def _internal_on_load_dll(self, load_dll): + return None + def _handle_load_dll(self, debug_event): """Handle LOAD_DLL_DEBUG_EVENT""" self._update_debugger_state(debug_event) @@ -835,6 +853,7 @@ class Debugger(object): dll_name = dll_name[:-6] + "64" # Crade.. #print("Load {0} -> {1}".format(dll, dll_name)) self._module_by_process[self.current_process.pid][dll_name] = windows.pe_parse.GetPEFile(load_dll.lpBaseOfDll, self.current_process) + self._internal_on_load_dll(load_dll) # Allow hook for symbol-debugger self._setup_pending_breakpoints_load_dll(dll_name) with self.DisabledMemoryBreakpoint(): try: