mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Playing with advanced breakpoint
This commit is contained in:
@@ -16,4 +16,7 @@ Since 0.2:
|
||||
* Added COMImplementation to com interface
|
||||
* fix x86.assemble + add x64.assemble | fix some enconding problem in x64
|
||||
* Add test_code.py sample
|
||||
* Remove OptionExport from winproxy
|
||||
* Remove OptionExport from winproxy
|
||||
* MemoryBP + single_step for windows.debug.Debugger
|
||||
* Possibility to delete breakpoints in windows.debug.Debugger
|
||||
* Add Context.func_result as abstract register for EAX/RAX
|
||||
@@ -8,16 +8,11 @@ TODO:
|
||||
- Verif multiple pending at same place
|
||||
- Test !! (bp, BP_HX, bp on only on process, bp_hx on only one thread..)
|
||||
- test breakpoint with specific target
|
||||
- Add test for debugger with breakpoint that add another breakpoint on trigger
|
||||
|
||||
- Readme
|
||||
- Debugger ? Veh ?
|
||||
- remotectypes
|
||||
- pretty sur I can get rid of PointerToStruct64/PointerToStruct32
|
||||
|
||||
- TransparentApiProxy
|
||||
double name (params and args) for same info..
|
||||
|
||||
- Parse .IDL file for more COM NAME->IID
|
||||
|
||||
- Add test for debugger with breakpoint that add another breakpoint on trigger
|
||||
|
||||
- Some test/doc on windows.system.handles
|
||||
|
||||
@@ -28,6 +23,7 @@ TODO:
|
||||
Documentation
|
||||
* verif samples
|
||||
* COMImplementation (example in LKD)
|
||||
* MemoryBP + single_step() in Debugger
|
||||
|
||||
FIXME:
|
||||
- setup.py build seems to raise an error
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
import windows
|
||||
from windows.generated_def.winstructs import *
|
||||
from windows.generated_def import windef
|
||||
|
||||
from windows.winobject.process import WinProcess, WinThread
|
||||
|
||||
|
||||
@@ -52,4 +54,90 @@ class MemoryBreakpoint(Breakpoint):
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
"""Called when breakpoint is hit"""
|
||||
pass
|
||||
|
||||
|
||||
## Arguments Helper (need to move this elsewhere)
|
||||
class X86ArgumentRetriever(object):
|
||||
def get_arg(self, nb, proc, thread):
|
||||
return proc.read_dword(thread.context.sp + 4 + (4 * nb))
|
||||
|
||||
class X64ArgumentRetriever(object):
|
||||
REG_ARGS = ["Rcx", "Rdx", "R8", "R9"]
|
||||
def get_arg(self, nb, proc, thread):
|
||||
if nb < len(self.REG_ARGS):
|
||||
return getattr(thread.context, self.REG_ARGS[nb])
|
||||
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)
|
||||
self.target = target
|
||||
self.target_args = target.prototype._argtypes_
|
||||
|
||||
def extract_arguments_32bits(self, cproc, cthread):
|
||||
x = windows.debug.X86ArgumentRetriever()
|
||||
res = OrderedDict()
|
||||
for i, (name, type) in enumerate(zip(self.target.params, self.target_args)):
|
||||
value = x.get_arg(i, cproc, cthread)
|
||||
rt = windows.remotectypes.transform_type_to_remote32bits(type)
|
||||
if issubclass(rt, windows.remotectypes.RemoteValue):
|
||||
t = rt(value, cproc)
|
||||
else:
|
||||
t = rt(value)
|
||||
if not hasattr(t, "contents"):
|
||||
try:
|
||||
t = t.value
|
||||
except AttributeError:
|
||||
pass
|
||||
res[name[1]] = t
|
||||
return res
|
||||
|
||||
def extract_arguments_64bits(self, cproc, cthread):
|
||||
x = windows.debug.X64ArgumentRetriever()
|
||||
res = OrderedDict()
|
||||
for i, (name, type) in enumerate(zip(self.target.params, self.target_args)):
|
||||
value = x.get_arg(i, cproc, cthread)
|
||||
rt = windows.remotectypes.transform_type_to_remote64bits(type)
|
||||
if issubclass(rt, windows.remotectypes.RemoteValue):
|
||||
t = rt(value, cproc)
|
||||
else:
|
||||
t = rt(value)
|
||||
if not hasattr(t, "contents"):
|
||||
try:
|
||||
t = t.value
|
||||
except AttributeError:
|
||||
pass
|
||||
res[name[1]] = t
|
||||
return res
|
||||
|
||||
def extract_arguments(self, cproc, cthread):
|
||||
if windows.current_process.bitness == 32:
|
||||
return self.extract_arguments_32bits(cproc, cthread)
|
||||
if cproc.bitness == 64:
|
||||
return self.extract_arguments_64bits(cproc, cthread)
|
||||
# SysWow process from a 64bits debugger, handle bitness with CS
|
||||
if cthread.context.SegCs == windows.syswow64.CS_32bits:
|
||||
return self.extract_arguments_32bits(cproc, cthread)
|
||||
return self.extract_arguments_64bits(cproc, cthread)
|
||||
|
||||
|
||||
class FunctionRetBP(Breakpoint):
|
||||
def __init__(self, addr, initial_breakpoint):
|
||||
super(FunctionRetBP, self).__init__(addr)
|
||||
self.initial_breakpoint = initial_breakpoint
|
||||
|
||||
def trigger(self, dbg, exc):
|
||||
dbg.del_bp(self, targets=[dbg.current_process])
|
||||
return self.initial_breakpoint.ret_trigger(dbg, exc)
|
||||
|
||||
|
||||
class FunctionCallBP(Breakpoint):
|
||||
def trigger(self, dbg, exception):
|
||||
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
|
||||
+19
-2
@@ -188,7 +188,7 @@ class Remote_c_char_p64(c_char_p64, RemotePtr64, RemoteCCharP):
|
||||
|
||||
class Remote_w_char_p64(c_wchar_p64, RemotePtr64, RemoteWCharP):
|
||||
def __repr__(self):
|
||||
return "<Remote_c_char_p64({0})>".format(self.raw_value)
|
||||
return "<Remote_c_wchar_p64({0})>".format(self.raw_value)
|
||||
|
||||
|
||||
class RemoteStructurePointer64(Remote_c_void_p64):
|
||||
@@ -246,7 +246,7 @@ class Remote_c_char_p32(c_char_p32, RemotePtr32, RemoteCCharP):
|
||||
|
||||
class Remote_w_char_p32(c_wchar_p32, RemotePtr32, RemoteWCharP):
|
||||
def __repr__(self):
|
||||
return "<Remote_c_char_p32({0})>".format(self.raw_value)
|
||||
return "<Remote_c_wchar_p32({0})>".format(self.raw_value)
|
||||
|
||||
|
||||
class RemoteStructurePointer32(Remote_c_void_p32):
|
||||
@@ -375,6 +375,13 @@ remote_struct = RemoteStructure.from_structure
|
||||
def MakePtr64(type):
|
||||
class PointerToStruct64(Remote_c_void_p64):
|
||||
_sub_ctypes_ = (type)
|
||||
|
||||
@property
|
||||
def contents(self):
|
||||
return RemoteStructurePointer64.from_buffer_with_target_and_ptr_type(bytearray(self), target=self.target, ptr_type=self).contents
|
||||
|
||||
def __repr__(self):
|
||||
return "<RemotePtr64 to struct {0}>".format(type.__name__)
|
||||
return PointerToStruct64
|
||||
|
||||
def transform_structure_to_remote64bits(structcls):
|
||||
@@ -410,6 +417,16 @@ def transform_type_to_remote64bits(ftype):
|
||||
def MakePtr32(type):
|
||||
class PointerToStruct32(Remote_c_void_p32):
|
||||
_sub_ctypes_ = (type)
|
||||
|
||||
# Not sur about this code..
|
||||
# Logic problem: why do I have PointerToStruct32 and RemoteStructurePointer32... ?
|
||||
@property
|
||||
def contents(self):
|
||||
return RemoteStructurePointer32.from_buffer_with_target_and_ptr_type(bytearray(self), target=self.target, ptr_type=self).contents
|
||||
|
||||
def __repr__(self):
|
||||
return "<RemotePtr32 to struct {0}>".format(type.__name__)
|
||||
|
||||
return PointerToStruct32
|
||||
|
||||
def transform_structure_to_remote32bits(structcls):
|
||||
|
||||
@@ -184,6 +184,7 @@ class ECONTEXTBase(object):
|
||||
default_dump = ()
|
||||
pc_reg = ''
|
||||
sp_reg = ''
|
||||
func_result_reg = ''
|
||||
special_reg_type = {}
|
||||
|
||||
|
||||
@@ -220,8 +221,15 @@ class ECONTEXTBase(object):
|
||||
def set_sp(self, value):
|
||||
return setattr(self, self.sp_reg, value)
|
||||
|
||||
def get_func_result(self):
|
||||
return getattr(self, self.func_result_reg)
|
||||
|
||||
def set_func_result(self, value):
|
||||
return setattr(self, self.func_result_reg, value)
|
||||
|
||||
pc = property(get_pc, set_pc, None, "Program Counter register (EIP or RIP)")
|
||||
sp = property(get_sp, set_sp, None, "Stack Pointer register (ESP or RSP)")
|
||||
func_result = property(get_func_result, set_func_result, None, "Function Resultat register (EAX or RAX)")
|
||||
|
||||
@property
|
||||
def EEFlags(self):
|
||||
@@ -249,6 +257,7 @@ class ECONTEXT32(ECONTEXTBase, CONTEXT32):
|
||||
default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags')
|
||||
pc_reg = 'Eip'
|
||||
sp_reg = 'Esp'
|
||||
func_result_reg = 'Eax'
|
||||
fields = [f[0] for f in CONTEXT32._fields_]
|
||||
"""The fields of the structure"""
|
||||
|
||||
@@ -256,6 +265,7 @@ class ECONTEXTWOW64(ECONTEXTBase, WOW64_CONTEXT):
|
||||
default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags')
|
||||
pc_reg = 'Eip'
|
||||
sp_reg = 'Esp'
|
||||
func_result_reg = 'Eax'
|
||||
fields = [f[0] for f in WOW64_CONTEXT._fields_]
|
||||
"""The fields of the structure"""
|
||||
|
||||
@@ -265,6 +275,7 @@ class ECONTEXT64(ECONTEXTBase, CONTEXT64):
|
||||
'R8', 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'EFlags')
|
||||
pc_reg = 'Rip'
|
||||
sp_reg = 'Rsp'
|
||||
func_result_reg = 'Rax'
|
||||
fields = [f[0] for f in CONTEXT64._fields_]
|
||||
"""The fields of the structure"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user