mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Add a sample for the debugger API
This commit is contained in:
@@ -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("<on_exception> 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("<on_single_step> called with {0}".format(exception))
|
||||
self.dump_struct_once(exception, " single_step")
|
||||
|
||||
def on_create_process(self, create_process):
|
||||
print("<on_create_process> called with {0}".format(create_process))
|
||||
self.dump_struct_once(create_process, " create_process")
|
||||
pass
|
||||
|
||||
def on_exit_process(self, exit_process):
|
||||
print("<on_exit_process> called with {0}".format(exit_process))
|
||||
self.dump_struct_once(exit_process, " exit_process")
|
||||
pass
|
||||
|
||||
def on_create_thread(self, create_thread):
|
||||
print("<on_create_thread> called with {0}".format(create_thread))
|
||||
self.dump_struct_once(create_thread, " create_thread")
|
||||
pass
|
||||
|
||||
def on_exit_thread(self, exit_thread):
|
||||
print("<on_exit_thread> called with {0}".format(exit_thread))
|
||||
self.dump_struct_once(exit_thread, " exit_thread")
|
||||
pass
|
||||
|
||||
def on_load_dll(self, load_dll):
|
||||
print("<on_load_dll> 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("<on_unload_dll> called with <{0}>".format(unload_dll))
|
||||
self.dump_struct_once(unload_dll, " unload_dll")
|
||||
pass
|
||||
|
||||
def on_output_debug_string(self, debug_string):
|
||||
print("<on_output_debug_string> called with {0}".format(debug_string))
|
||||
self.dump_struct_once(debug_string, " debug_string")
|
||||
pass
|
||||
|
||||
def on_rip(self, rip_info):
|
||||
print("<on_rip> 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()
|
||||
+15
-15
@@ -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 <on_single_step>")
|
||||
|
||||
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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user