mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Improve debugger/BP doc + add sample + small fixes in WMI/LocalDebugger + new data in ApiProxy for FunctionBP
This commit is contained in:
@@ -44,8 +44,6 @@ There is not much documentation for now as the code might change soon.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
:class:`Breakpoint`
|
||||
"""""""""""""""""""
|
||||
|
||||
@@ -77,8 +75,14 @@ When a breakpoint is hit, its ``trigger`` function is called with the debugger a
|
||||
:special-members: __init__
|
||||
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
MemoryBreakpoint are triggered based on the fault address only (as I don't know a way to get the size of the read/write causing the fault without embeding a disassembler).
|
||||
MemoryBreakpoint are triggered based on the fault address only (as I don't know a way to get the size of the read/write causing the fault without embedding a disassembler).
|
||||
|
||||
This means that a MEMBP at address ``X`` won't be triggered by a write of size 4 at address ``X - 1`` (it's sad I know :( )
|
||||
This means that a MEMBP at address ``X`` won't be triggered by a write of size 4 at address ``X - 1``. it's sad I know.
|
||||
|
||||
.. autoclass:: FunctionBP
|
||||
:members:
|
||||
:inherited-members:
|
||||
:special-members: __init__
|
||||
@@ -362,6 +362,9 @@ Ouput::
|
||||
Ask to load <ole32.dll>: exiting process
|
||||
|
||||
|
||||
Single stepping
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. literalinclude:: ..\..\samples\debugger_membp_singlestep.py
|
||||
|
||||
Ouput::
|
||||
@@ -379,8 +382,27 @@ Ouput::
|
||||
No more single step: exiting
|
||||
|
||||
|
||||
:class:`windows.debug.FunctionBP`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. literalinclude:: ..\..\samples\debug_functionbp.py
|
||||
|
||||
Ouput::
|
||||
|
||||
NtCreateFile of <\??\C:\Windows\syswow64\en-US\calc.exe.mui>: handle = 0xac
|
||||
Handle manually found! typename=<File>, name=<\Device\HarddiskVolume2\Windows\SysWOW64\en-US\calc.exe.mui>
|
||||
|
||||
NtCreateFile of <\Device\DeviceApi\CMApi>: handle = 0x108
|
||||
Handle manually found! typename=<File>, name=<\Device\DeviceApi>
|
||||
|
||||
NtCreateFile of <\??\C:\Windows\Fonts\staticcache.dat>: handle = 0x154
|
||||
Handle manually found! typename=<File>, name=<\Device\HarddiskVolume2\Windows\Fonts\StaticCache.dat>
|
||||
|
||||
Exiting process
|
||||
|
||||
.. _sample_local_debugger:
|
||||
|
||||
|
||||
:class:`LocalDebugger`
|
||||
''''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ class SingleStepOnWrite(windows.debug.MemoryBreakpoint):
|
||||
"""Check that BP/dbg can trigger single step and that instruction follows"""
|
||||
def trigger(self, dbg, exc):
|
||||
fault_addr = exc.ExceptionRecord.ExceptionInformation[1]
|
||||
import pdb;pdb.set_trace()
|
||||
eip = dbg.current_thread.context.pc
|
||||
print("Instruction at <{0:#x}> wrote at <{1:#x}>".format(eip, fault_addr))
|
||||
dbg.single_step_counter = 4
|
||||
|
||||
@@ -12,6 +12,8 @@ from windows.generated_def import interfaces
|
||||
from windows.generated_def.interfaces import generate_IID, IID
|
||||
|
||||
|
||||
# Simple raw -> UUID
|
||||
# "-".join("{:02X}".format(c) for c in struct.unpack("<IHHHBBBBBB", x))
|
||||
|
||||
# Simple Implem to create COM Interface in Python (COM -> Python)
|
||||
def create_c_callable(func, types, keepalive=[]):
|
||||
|
||||
@@ -73,9 +73,11 @@ class X64ArgumentRetriever(object):
|
||||
return proc.read_dword(thread.context.sp + 8 + (8 * nb))
|
||||
|
||||
## Behaviour breakpoint !
|
||||
class ParamDumpBP(Breakpoint):
|
||||
def __init__(self, addr, target):
|
||||
super(ParamDumpBP, self).__init__(addr)
|
||||
class FunctionParamDumpBP(Breakpoint):
|
||||
def __init__(self, target, addr=None):
|
||||
if addr is None:
|
||||
addr = "{0}!{1}".format(target.target_dll, target.target_func)
|
||||
super(FunctionParamDumpBP, self).__init__(addr)
|
||||
self.target = target
|
||||
self.target_args = target.prototype._argtypes_
|
||||
|
||||
@@ -116,6 +118,7 @@ class ParamDumpBP(Breakpoint):
|
||||
return res
|
||||
|
||||
def extract_arguments(self, cproc, cthread):
|
||||
"""Extracts the functions parameters in an :class:`OrderedDict`"""
|
||||
if windows.current_process.bitness == 32:
|
||||
return self.extract_arguments_32bits(cproc, cthread)
|
||||
if cproc.bitness == 64:
|
||||
@@ -137,10 +140,20 @@ class FunctionRetBP(Breakpoint):
|
||||
|
||||
|
||||
class FunctionCallBP(Breakpoint):
|
||||
def trigger(self, dbg, exception):
|
||||
def break_on_ret(self, dbg, exception):
|
||||
"""Setup a breakpoint at the return address of the function, this breakpoint will call :func:`ret_trigger`"""
|
||||
cproc = dbg.current_process
|
||||
return_addr = dbg.current_process.read_ptr(dbg.current_thread.context.sp)
|
||||
dbg.add_bp(FunctionRetBP(return_addr, self), target=dbg.current_process)
|
||||
|
||||
def ret_trigger(self, dbg, exception):
|
||||
pass
|
||||
"""Called at the return of the function if :func:`break_on_ret` was called"""
|
||||
raise NotImplementedError("ret_trigger")
|
||||
|
||||
|
||||
class FunctionBP(FunctionCallBP, FunctionParamDumpBP):
|
||||
"""A breakpoint that accepts a function from :mod:`windows.winproxy` and able to:
|
||||
|
||||
- Extract the arguments of the functions
|
||||
- Break at the return of the function
|
||||
"""
|
||||
@@ -83,6 +83,7 @@ class Debugger(object):
|
||||
return cls(target)
|
||||
|
||||
def detach(self, target=None):
|
||||
"""Detach from all debugged processes or process ``target``"""
|
||||
if target is None:
|
||||
for proc in self.processes.values():
|
||||
self.detach(proc)
|
||||
@@ -116,7 +117,7 @@ class Debugger(object):
|
||||
windows.winproxy.DebugActiveProcessStop(target.pid)
|
||||
|
||||
def _killed_in_action(self):
|
||||
"""Return True if current process have been detached by user callback"""
|
||||
"""Return ``True`` if current process have been detached by user callback"""
|
||||
return self.current_process.pid not in self.processes
|
||||
|
||||
|
||||
@@ -385,7 +386,7 @@ class Debugger(object):
|
||||
def _setup_pending_breakpoints_load_dll(self, dll_name):
|
||||
for bp in self._pending_breakpoints_new[None]:
|
||||
if isinstance(bp.addr, basestring):
|
||||
target_dll = bp.addr.split("!")[0]
|
||||
target_dll = bp.addr.lower().split("!")[0]
|
||||
if target_dll == dll_name:
|
||||
_setup_method = getattr(self, "_setup_breakpoint_" + bp.type)
|
||||
if bp.apply_to_target(self.current_process):
|
||||
@@ -710,7 +711,7 @@ class Debugger(object):
|
||||
|
||||
## Public API
|
||||
def loop(self):
|
||||
"""Debugging loop: handle event / dispatch to breakpoint. Returns when all targets are dead"""
|
||||
"""Debugging loop: handle event / dispatch to breakpoint. Returns when all targets are dead/detached"""
|
||||
for debug_event in self._debug_event_generator():
|
||||
self.REMOVE_ME_debug_event = debug_event
|
||||
dbg_continue_flag = self._dispatch_debug_event(debug_event)
|
||||
@@ -861,7 +862,7 @@ class Debugger(object):
|
||||
return DBG_CONTINUE
|
||||
|
||||
def on_single_step(self, exception):
|
||||
"""Called on requested single step``exception`` is one of the following type:
|
||||
"""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`
|
||||
|
||||
@@ -110,14 +110,14 @@ class LocalDebugger(object):
|
||||
del self.breakpoints[bp.addr]
|
||||
return
|
||||
if bp.type == HARDWARE_EXEC_BP:
|
||||
threads_by_tid = {t.tid: t for t in windows.current_process.threads}
|
||||
for tid in self._hxbp_breakpoint:
|
||||
if bp.addr in self._hxbp_breakpoint[tid] and self._hxbp_breakpoint[tid][bp.addr] == bp:
|
||||
if tid == windows.current_thread.tid:
|
||||
self.remove_hxbp_self_thread(bp.addr)
|
||||
else:
|
||||
self.remove_hxbp_other_thread(bp.addr)
|
||||
self.remove_hxbp_other_thread(bp.addr, threads_by_tid[tid])
|
||||
del self._hxbp_breakpoint[tid][bp.addr]
|
||||
#print("Need to remove {0} in {1}".format(self._hxbp_breakpoint[tid][bp.addr], tid))
|
||||
return
|
||||
raise NotImplementedError("Unknow BP type {0}".format(bp.type))
|
||||
|
||||
|
||||
@@ -14,20 +14,21 @@ class WmiRequester(object):
|
||||
r"""An object to perform wmi request to ``root\cimv2``"""
|
||||
INSTANCE = None
|
||||
|
||||
def __new__(cls):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls.INSTANCE is not None:
|
||||
return cls.INSTANCE
|
||||
cls.INSTANCE = super(cls, cls).__new__(cls)
|
||||
cls.INSTANCE = super(cls, cls).__new__(cls, *args, **kwargs)
|
||||
return cls.INSTANCE
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, target="root\\cimv2", user=None, password=None):
|
||||
locator = IWbemLocator()
|
||||
service = IWbemServices()
|
||||
CLSID_WbemAdministrativeLocator_IID = windows.com.IID.from_string('CB8555CC-9128-11D1-AD9B-00C04FD8FDFF')
|
||||
#CLSID_WbemAdministrativeLocator_IID = windows.com.IID.from_string('CB8555CC-9128-11D1-AD9B-00C04FD8FDFF')
|
||||
WbemLocator_CLSID = windows.com.IID.from_string('4590F811-1D3A-11D0-891F-00AA004B2E24')
|
||||
|
||||
windows.com.init()
|
||||
windows.com.create_instance(CLSID_WbemAdministrativeLocator_IID, locator)
|
||||
locator.ConnectServer("root\\cimv2", None, None , None, 0x80, None, None, ctypes.byref(service))
|
||||
windows.com.create_instance(WbemLocator_CLSID, locator)
|
||||
locator.ConnectServer(target, user, password , None, 0x80, None, None, ctypes.byref(service))
|
||||
self.service = service
|
||||
|
||||
def select(self, frm, attrs="*"):
|
||||
|
||||
@@ -114,6 +114,8 @@ class ApiProxy(object):
|
||||
python_proxy.prototype = prototype
|
||||
python_proxy.params = params
|
||||
python_proxy.errcheck = self.error_check
|
||||
python_proxy.target_dll = self.APIDLL
|
||||
python_proxy.target_func = self.func_name
|
||||
params_name = [param[1] for param in params]
|
||||
if (self.error_check.__doc__):
|
||||
doc = python_proxy.__doc__
|
||||
|
||||
Reference in New Issue
Block a user