LocalDebugger sample + fix

This commit is contained in:
Clement Rouault
2016-02-12 14:44:00 +01:00
parent 9a1088daab
commit 5ffa21cd8a
5 changed files with 191 additions and 14 deletions
+50
View File
@@ -0,0 +1,50 @@
import ctypes
import windows
import windows.debug
from windows.generated_def.winstructs import *
ct = windows.current_thread
t = [t for t in windows.current_process.threads if t.tid == ct.tid][0]
class YoloDebugger(windows.debug.LocalDebugger):
def __init__(self, single_step_count):
super(YoloDebugger, self).__init__()
self.single_step_count = single_step_count
def on_exception(self, exc):
code = self.get_exception_code()
context = self.get_exception_context()
print("EXCEPTION !!!! Got a {0} at 0x{1:x}".format(code, context.pc))
if self.single_step_count:
self.single_step_count -= 1
return self.single_step()
class YoloHXBP(windows.debug.HXBreakpoint):
def trigger(self, dbg, exc):
context = dbg.get_exception_context()
print("GOT AN HXBP <3 at 0x{0:x}".format(context.pc))
windows.current_process.write_memory(self.addr, "\x90\x90")
return dbg.single_step()
print("Your main thread is {0}".format(windows.current_thread.tid))
d = YoloDebugger(5)
# Infinite loop + nop + ret
addr = windows.native_exec.native_function.allocator.write_code("\xeb\xfe\x90\x90\x90\x90\xc3")
func_type = ctypes.CFUNCTYPE(PVOID)
func = func_type(addr)
print("Code addr = 0x{0:x}".format(addr))
t = windows.current_process.create_thread(addr, 0)
d.add_bp(YoloHXBP(addr))
t.wait()
+40
View File
@@ -0,0 +1,40 @@
import ctypes
import windows
import windows.test
from windows.generated_def.winstructs import *
remote_code = """
import windows
from windows.generated_def.winstructs import *
windows.utils.create_console()
class YOLOHXBP(windows.debug.HXBreakpoint):
def trigger(self, dbg, exc):
p = windows.current_process
arg_pos = 2
context = dbg.get_exception_context()
esp = context.Esp
unicode_string_addr = p.read_ptr(esp + (arg_pos + 1) * 4)
wstring_addr = p.read_ptr(unicode_string_addr + 4)
dll_loaded = p.read_wstring(wstring_addr)
print("I AM LOADING <{0}>".format(dll_loaded))
d = windows.debug.LocalDebugger()
exp = windows.current_process.peb.modules[1].pe.exports
#windows.utils.FixedInteractiveConsole(locals()).interact()
ldr = exp["LdrLoadDll"]
d.add_bp(YOLOHXBP(ldr))
print("By from {0}".format(windows.current_thread.tid))
"""
c = windows.test.pop_calc_32(dwCreationFlags=CREATE_SUSPENDED)
c.execute_python(remote_code)
c.threads[0].resume()
import time
time.sleep(2)
c.exit()
+95 -9
View File
@@ -423,8 +423,14 @@ class Debugger(object):
# Public callback
def on_exception(self, exception):
"""Called on exception event other that known breakpoint"""
pass
"""Called on exception event other that known breakpoint
The default behaviour is to return ``DBG_CONTINUE`` for the known exception code
and ``DBG_EXCEPTION_NOT_HANDLED`` else
"""
if not exception.ExceptionRecord.ExceptionCode in windows.exception.exception_name_by_value:
return DBG_EXCEPTION_NOT_HANDLED
return DBG_CONTINUE
def on_create_process(self, create_process):
"""Called on create_process event"""
@@ -499,10 +505,16 @@ class LocalDebugger(object):
self.breakpoints = {}
self._memory_save = {}
self._reput_breakpoint = {}
self._hxbp_breakpoint = defaultdict(dict)
self.callback_vectored = VectoredException(self.callback)
windows.winproxy.AddVectoredExceptionHandler(0, self.callback_vectored)
self.setup_hxbp_callback_vectored = VectoredException(self.setup_hxbp_callback)
self.hxbp_info = None
self.code = windows.native_exec.create_function("\xcc\xc3", [PVOID])
def get_exception_code(self):
return self.current_exception[0].ExceptionRecord[0].ExceptionCode
@@ -522,10 +534,11 @@ class LocalDebugger(object):
def callback(self, exc):
self.current_exception = exc
exp_code = self.get_exception_code()
exp_addr = self.get_exception_context().get_pc()
context = self.get_exception_context()
exp_addr = context.pc
if exp_code == EXCEPTION_BREAKPOINT and exp_addr in self.breakpoints:
continue_value = self.breakpoints[exp_addr].trigger(self, exc)
res = self.breakpoints[exp_addr].trigger(self, exc)
single_step = self.get_exception_context().EEFlags.TF # single step activated by breakpoint
return self._pass_breakpoint(exp_addr, single_step)
@@ -538,17 +551,90 @@ class LocalDebugger(object):
if single_step:
return self.on_exception(exc)
return windef.EXCEPTION_CONTINUE_EXECUTION
return self.on_exception(exc)
elif exp_code == EXCEPTION_SINGLE_STEP and exp_addr in self._hxbp_breakpoint[windows.current_thread.tid]:
res = self._hxbp_breakpoint[windows.current_thread.tid][exp_addr].trigger(self, exc)
context.EEFlags.RF = 1
return EXCEPTION_CONTINUE_EXECUTION
res = self.on_exception(exc)
return EXCEPTION_CONTINUE_EXECUTION
def on_exception(self, exc):
if not self.get_exception_code() in windows.exception.exception_name_by_value:
return windef.EXCEPTION_CONTINUE_SEARCH
return windef.EXCEPTION_CONTINUE_EXECUTION
def add_bp(self, bp):
def add_bp(self, bp, targets=None):
if bp.type == HARDWARE_EXEC_BP:
return self.add_bp_hxbp(bp, targets)
if bp.type != STANDARD_BP:
raise NotImplementedError("Add non standard-BP in LocalKernelDebugger")
raise NotImplementedError("Unknow BP type {0}".format(bp.type))
if targets is not None:
raise ValueError("LocalDebugger: STANDARD_BP doest not support targets {0}".format(targets))
self.breakpoints[bp.addr] = bp
self._memory_save[bp.addr] = windows.current_process.read_memory(bp.addr, 1)
with windows.utils.VirtualProtected(bp.addr, 1, PAGE_EXECUTE_READWRITE):
windows.current_process.write_memory(bp.addr, "\xcc")
return
return
def add_bp_hxbp(self, bp, targets=None):
if bp.type != HARDWARE_EXEC_BP:
raise NotImplementedError("Add non standard-BP in LocalDebugger")
if targets is None:
targets = windows.current_process.threads
for thread in targets:
if thread.owner.pid != windows.current_process.pid:
raise ValueError("Cannot add HXBP to target in remote process {0}".format(thread))
if thread.tid == windows.current_thread.tid:
self.setup_hxbp_self_thread(bp.addr)
else:
self.setup_hxbp_other_thread(bp.addr, thread)
self._hxbp_breakpoint[thread.tid][bp.addr] = bp
def setup_hxbp_callback(self, exc):
self.current_exception = exc
exp_code = self.get_exception_code()
context = self.get_exception_context()
exp_addr = context.pc
hxbp_used = self.setup_hxbp_in_context(context, self.data)
windows.current_process.write_memory(exp_addr, "\x90")
# Raising in the VEH is a bad idea..
# So better give the information to triggerer..
if hxbp_used is not None:
self.get_exception_context().Eax = exp_addr
else:
self.get_exception_context().Eax = 0
return windef.EXCEPTION_CONTINUE_EXECUTION
def setup_hxbp_in_context(self, context, addr):
for i in range(4):
is_used = getattr(context.EDr7, "L" + str(i))
empty_drx = str(i)
if not is_used:
context.EDr7.GE = 1
context.EDr7.LE = 1
setattr(context.EDr7, "L" + empty_drx, 1)
setattr(context, "Dr" + empty_drx, addr)
return i
return None
def setup_hxbp_self_thread(self, addr):
self.data = addr
with windows.exception.VectoredExceptionHandler(1, self.setup_hxbp_callback):
x = self.code()
if x is None:
raise ValueError("Could not setup HXBP")
windows.current_process.write_memory(x, "\xcc")
return
def setup_hxbp_other_thread(self, addr, thread):
thread.suspend()
ctx = thread.context
x = self.setup_hxbp_in_context(ctx, addr)
if x is None:
raise ValueError("Could not setup HXBP in {0}".format(thread))
thread.set_context(ctx)
thread.resume()
+5 -4
View File
@@ -316,19 +316,20 @@ class VectoredException(object):
return windef.EXCEPTION_CONTINUE_SEARCH
class WithExceptionHandler(object):
def __init__(self, handler):
class VectoredExceptionHandler(object):
def __init__(self, pos, handler):
self.handler = VectoredException(handler)
self.pos = pos
def __enter__(self):
self.value = windows.winproxy.AddVectoredExceptionHandler(0, self.handler)
self.value = windows.winproxy.AddVectoredExceptionHandler(self.pos, self.handler)
return self
def __exit__(self, exc_type, exc_value, traceback):
windows.winproxy.RemoveVectoredExceptionHandler(self.value)
return False
class DumpContextOnException(WithExceptionHandler):
class DumpContextOnException(VectoredExceptionHandler):
def __init__(self, exit=False):
self.exit = exit
super(DumpContextOnException, self).__init__(self.print_context_result)
+1 -1
View File
@@ -475,7 +475,7 @@ class Process(AutoHandle):
class CurrentThread(AutoHandle):
"""The current thread"""
@utils.fixedpropety
@property #It's not a fixedpropety because executing thread might change
def tid(self):
"""Thread ID