Playing with advanced breakpoint

This commit is contained in:
Clement Rouault
2016-07-13 13:54:42 +02:00
parent 1f6ffd043c
commit d90e461bcf
5 changed files with 127 additions and 12 deletions
+4 -1
View File
@@ -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
+4 -8
View File
@@ -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
+89 -1
View File
@@ -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
View File
@@ -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):
+11
View File
@@ -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"""