diff --git a/samples/debugger_api.py b/samples/debugger_api.py new file mode 100644 index 0000000..57ebaef --- /dev/null +++ b/samples/debugger_api.py @@ -0,0 +1,76 @@ +import sys +import os.path +import pprint +sys.path.append(os.path.abspath(__file__ + "\..\..")) + +import windows +import windows.test +import windows.debug + +from windows.generated_def.winstructs import * + +class MyDebugger(windows.debug.Debugger): + def __init__(self, *args, **kwargs): + super(MyDebugger, self).__init__(*args, **kwargs) + self.struct_already_dump = set() + + def dump_struct_once(self, struct, name): + if name in self.struct_already_dump: + return + windows.utils.print_ctypes_struct(struct, name, hexa=True) + self.struct_already_dump.add(name) + + def on_exception(self, exception): + print(" called with {0}".format(exception)) + self.dump_struct_once(exception, " exception") + print("Single Stepping") + return self.single_step() + + def on_single_step(self, exception): + print(" called with {0}".format(exception)) + self.dump_struct_once(exception, " single_step") + + def on_create_process(self, create_process): + print(" called with {0}".format(create_process)) + self.dump_struct_once(create_process, " create_process") + pass + + def on_exit_process(self, exit_process): + print(" called with {0}".format(exit_process)) + self.dump_struct_once(exit_process, " exit_process") + pass + + def on_create_thread(self, create_thread): + print(" called with {0}".format(create_thread)) + self.dump_struct_once(create_thread, " create_thread") + pass + + def on_exit_thread(self, exit_thread): + print(" called with {0}".format(exit_thread)) + self.dump_struct_once(exit_thread, " exit_thread") + pass + + def on_load_dll(self, load_dll): + print(" called with {0} ({1})".format(load_dll, self._get_loaded_dll(load_dll))) + self.dump_struct_once(load_dll, " load_dll") + pass + + def on_unload_dll(self, unload_dll): + print(" called with <{0}>".format(unload_dll)) + self.dump_struct_once(unload_dll, " unload_dll") + pass + + def on_output_debug_string(self, debug_string): + print(" called with {0}".format(debug_string)) + self.dump_struct_once(debug_string, " debug_string") + pass + + def on_rip(self, rip_info): + print(" called with {0}".format(rip_info)) + self.dump_struct_once(rip_info, " rip_info") + pass + + +calc = windows.test.pop_calc_32(dwCreationFlags=DEBUG_PROCESS) +d = MyDebugger(calc) +d.loop() diff --git a/samples/debugger.py b/samples/debugger_print_LdrLoaddll.py similarity index 100% rename from samples/debugger.py rename to samples/debugger_print_LdrLoaddll.py diff --git a/windows/debug.py b/windows/debug.py index d32a364..26891bd 100644 --- a/windows/debug.py +++ b/windows/debug.py @@ -71,6 +71,12 @@ class Debugger(object): winproxy.DebugActiveProcess(target.pid) return cls(target) + @classmethod + def debug(cls, path, args=None, dwCreationFlags=0, show_windows=False): + dwCreationFlags |= DEBUG_PROCESS + c = windows.utils.create_process(path, args=args, dwCreationFlags=dwCreationFlags, show_windows=show_windows) + return cls(c) + def _init_dispatch_handlers(self): dbg_evt_dispatch = {} dbg_evt_dispatch[EXCEPTION_DEBUG_EVENT] = self._handle_exception @@ -337,16 +343,6 @@ class Debugger(object): for bp, begin, end, original_prot in self._watched_memory: if begin <= fault_addr < end: ## Reject bad EXCEPTION ? - #if fault_type == EXEC and bp.PROTECT not in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE]: - # break - #if fault_type == READ and bp.PROTECT not in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE]: - # break - #if fault_type == EXEC and bp.PROTECT not in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE]: - # break - - - - #print("BP MEM TRIGGER {0}".format(bp)) continue_flag = bp.trigger(self, exception) self._explicit_single_step[self.current_thread.tid] = self.current_thread.context.EEFlags.TF self._pass_memory_breakpoint(bp, begin, end, original_prot) @@ -542,7 +538,7 @@ class Debugger(object): # Public callback def on_exception(self, exception): - """Called on exception event other that known breakpoint. ``exception`` is one of the following type: + """Called on exception event other that known breakpoint or requested single step. ``exception`` is one of the following type: * :class:`windows.winobject.exception.EEXCEPTION_DEBUG_INFO32` * :class:`windows.winobject.exception.EEXCEPTION_DEBUG_INFO64` @@ -555,6 +551,13 @@ class Debugger(object): return DBG_CONTINUE def on_single_step(self, exception): + """Called on requested single step``exception`` is one of the following type: + + * :class:`windows.winobject.exception.EEXCEPTION_DEBUG_INFO32` + * :class:`windows.winobject.exception.EEXCEPTION_DEBUG_INFO64` + + There is no default implementation, if you use ``Debugger.single_step()`` you should implement ``on_single_step`` + """ raise NotImplementedError("Debugger that explicitly single step should implement ") def on_create_process(self, create_process): @@ -589,10 +592,7 @@ class Debugger(object): """Called on rip_info event (for param type see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680587(v=vs.85).aspx)""" pass -def debug(path, args=None, dwCreationFlags=0, show_windows=False): - dwCreationFlags |= DEBUG_PROCESS - c = windows.utils.create_process(path, args=args, dwCreationFlags=dwCreationFlags, show_windows=show_windows) - return Debugger(c) + class Breakpoint(object): diff --git a/windows/test/mytest.py b/windows/test/mytest.py index 3aaff19..353d4a7 100644 --- a/windows/test/mytest.py +++ b/windows/test/mytest.py @@ -547,7 +547,6 @@ class NativeUtilsTestCase(unittest.TestCase): # Put name in test to know which function caused the assert fails self.assertEqual((name, hex(addr)), (name, hex(compute_addr))) - self.assertEqual(getprocaddr32("YOLO.DLL", "whatever"), 0xfffffffe) self.assertEqual(getprocaddr32("KERNEL32.DLL", "YOLOAPI"), 0xffffffff) diff --git a/windows/test/test_debugger.py b/windows/test/test_debugger.py index a3ee1e2..100e8e4 100644 --- a/windows/test/test_debugger.py +++ b/windows/test/test_debugger.py @@ -372,7 +372,6 @@ class DebuggerTestCase(unittest.TestCase): def test_memory_breakpoint_write(self): """Check MemoryBP WRITE""" - TEST_CASE = self store_data = [0] class TSTBP(windows.debug.MemoryBreakpoint): diff --git a/windows/utils/pythonutils.py b/windows/utils/pythonutils.py index 96923b5..1814dcf 100644 --- a/windows/utils/pythonutils.py +++ b/windows/utils/pythonutils.py @@ -1,6 +1,7 @@ """utils fonctions non windows-related""" import ctypes import _ctypes +from windows.generated_def import Flag def fixedpropety(f): @@ -40,7 +41,7 @@ def print_ctypes_struct(struct, name="", ident=0, hexa=False): if isinstance(value, basestring): value = repr(value) - if hexa: + if hexa and not isinstance(value, Flag): try: print("{0} -> {1}".format(name, hex(value))) return