mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Commit <a l'arrache> for a quick implem of del_bp on standard BP
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
from .debugger import Debugger, HXBreakpoint
|
||||
from .localdbg import LocalDebugger
|
||||
from .breakpoints import *
|
||||
@@ -0,0 +1,55 @@
|
||||
from windows.generated_def.winstructs import *
|
||||
from windows.generated_def import windef
|
||||
|
||||
from windows.winobject.process import WinProcess, WinThread
|
||||
|
||||
|
||||
STANDARD_BP = "BP"
|
||||
HARDWARE_EXEC_BP = "HXBP"
|
||||
MEMORY_BREAKPOINT = "MEMBP"
|
||||
|
||||
class Breakpoint(object):
|
||||
"""An standard (Int3) breakpoint (type == ``STANDARD_BP``)"""
|
||||
type = STANDARD_BP # REAL BP
|
||||
def __init__(self, addr):
|
||||
self.addr = addr
|
||||
|
||||
def apply_to_target(self, target):
|
||||
return isinstance(target, WinProcess)
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
"""Called when breakpoint is hit"""
|
||||
pass
|
||||
|
||||
|
||||
class ProxyBreakpoint(Breakpoint):
|
||||
def __init__(self, target, addr, type):
|
||||
self.target = target
|
||||
self.addr = addr
|
||||
self.type = type
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
return self.target(dbg, exception)
|
||||
|
||||
|
||||
class HXBreakpoint(Breakpoint):
|
||||
"""An hardware-execution breakpoint (type == ``HARDWARE_EXEC_BP``)"""
|
||||
type = HARDWARE_EXEC_BP
|
||||
|
||||
def apply_to_target(self, target):
|
||||
return isinstance(target, WinThread)
|
||||
|
||||
class MemoryBreakpoint(Breakpoint):
|
||||
type = MEMORY_BREAKPOINT
|
||||
|
||||
DEFAULT_PROTECT = PAGE_READONLY
|
||||
DEFAULT_SIZE = 0x1000
|
||||
def __init__(self, addr, size=None, prot=None):
|
||||
super(MemoryBreakpoint, self).__init__(addr)
|
||||
self.size = size if size is not None else self.DEFAULT_SIZE
|
||||
self.protect = size if prot is not None else self.DEFAULT_PROTECT
|
||||
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
"""Called when breakpoint is hit"""
|
||||
pass
|
||||
@@ -11,13 +11,12 @@ from windows.winobject.process import WinProcess, WinThread
|
||||
from windows.dbgprint import dbgprint
|
||||
from windows import winproxy
|
||||
from windows.generated_def.winstructs import *
|
||||
from .generated_def import windef
|
||||
|
||||
from windows.generated_def import windef
|
||||
from .breakpoints import *
|
||||
|
||||
from windows.winobject.exception import VectoredException
|
||||
|
||||
|
||||
|
||||
STANDARD_BP = "BP"
|
||||
HARDWARE_EXEC_BP = "HXBP"
|
||||
MEMORY_BREAKPOINT = "MEMBP"
|
||||
@@ -155,7 +154,6 @@ class Debugger(object):
|
||||
for target in targets:
|
||||
return _setup_method(bp, target)
|
||||
|
||||
|
||||
def _setup_breakpoint_BP(self, bp, target):
|
||||
if not isinstance(target, WinProcess):
|
||||
raise ValueError("SETUP STANDARD_BP on {0}".format(target))
|
||||
@@ -168,6 +166,15 @@ class Debugger(object):
|
||||
target.write_memory(addr, "\xcc")
|
||||
return True
|
||||
|
||||
def _remove_breakpoint_BP(self, bp, target):
|
||||
if not isinstance(target, WinProcess):
|
||||
raise ValueError("SETUP STANDARD_BP on {0}".format(target))
|
||||
addr = self._resolve(bp.addr, target)
|
||||
target.write_memory(addr, self._memory_save[target.pid][addr])
|
||||
del self._memory_save[target.pid][addr]
|
||||
del self.breakpoints[target.pid][addr]
|
||||
return True
|
||||
|
||||
def _setup_breakpoint_HXBP(self, bp, target):
|
||||
if not isinstance(target, WinThread):
|
||||
raise ValueError("SETUP HXBP_BP on {0}".format(target))
|
||||
@@ -288,7 +295,9 @@ class Debugger(object):
|
||||
thread.set_context(ctx)
|
||||
continue_flag = self._dispatch_breakpoint(exception, excp_addr)
|
||||
self._explicit_single_step[self.current_thread.tid] = self.current_thread.context.EEFlags.TF
|
||||
self._pass_breakpoint(excp_addr)
|
||||
if excp_addr in self.breakpoints[self.current_process.pid]:
|
||||
# Setup BP if not suppressed
|
||||
self._pass_breakpoint(excp_addr)
|
||||
return continue_flag
|
||||
return self.on_exception(exception)
|
||||
|
||||
@@ -416,7 +425,7 @@ class Debugger(object):
|
||||
self._setup_pending_breakpoints_new_process(self.current_process)
|
||||
self._setup_pending_breakpoints_new_thread(self.current_thread)
|
||||
return self.on_create_process(create_process)
|
||||
# TODO: clode hFile
|
||||
# TODO: close hFile
|
||||
|
||||
def _handle_exit_process(self, debug_event):
|
||||
"""Handle EXIT_PROCESS_DEBUG_EVENT"""
|
||||
@@ -530,6 +539,23 @@ class Debugger(object):
|
||||
raise ValueError("Unknown target {0}".format(target))
|
||||
return self._setup_breakpoint(bp, target)
|
||||
|
||||
def del_bp(self, bp, targets=None):
|
||||
if targets is not None:
|
||||
raise NotImplementedError("TODO: DEL BP with targets ?")
|
||||
if bp.type != STANDARD_BP:
|
||||
raise NotImplementedError("Remove non-STANDARD_BP breakpoint")
|
||||
|
||||
_remove_method = getattr(self, "_remove_breakpoint_" + bp.type)
|
||||
if targets is None:
|
||||
if bp.type in [STANDARD_BP, MEMORY_BREAKPOINT]: #TODO: better..
|
||||
targets = self.processes.values()
|
||||
else:
|
||||
targets = self.threads.values()
|
||||
else:
|
||||
targets = [target]
|
||||
for target in targets:
|
||||
return _remove_method(bp, target)
|
||||
|
||||
def single_step(self):
|
||||
t = self.current_thread
|
||||
ctx = t.context
|
||||
@@ -595,287 +621,3 @@ class Debugger(object):
|
||||
|
||||
|
||||
|
||||
class Breakpoint(object):
|
||||
"""An standard (Int3) breakpoint (type == ``STANDARD_BP``)"""
|
||||
type = STANDARD_BP # REAL BP
|
||||
def __init__(self, addr):
|
||||
self.addr = addr
|
||||
|
||||
def apply_to_target(self, target):
|
||||
return isinstance(target, WinProcess)
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
"""Called when breakpoint is hit"""
|
||||
pass
|
||||
|
||||
|
||||
class ProxyBreakpoint(Breakpoint):
|
||||
def __init__(self, target, addr, type):
|
||||
self.target = target
|
||||
self.addr = addr
|
||||
self.type = type
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
return self.target(dbg, exception)
|
||||
|
||||
|
||||
class HXBreakpoint(Breakpoint):
|
||||
"""An hardware-execution breakpoint (type == ``HARDWARE_EXEC_BP``)"""
|
||||
type = HARDWARE_EXEC_BP
|
||||
|
||||
def apply_to_target(self, target):
|
||||
return isinstance(target, WinThread)
|
||||
|
||||
class MemoryBreakpoint(Breakpoint):
|
||||
type = MEMORY_BREAKPOINT
|
||||
|
||||
DEFAULT_PROTECT = PAGE_READONLY
|
||||
DEFAULT_SIZE = 0x1000
|
||||
def __init__(self, addr, size=None, prot=None):
|
||||
super(MemoryBreakpoint, self).__init__(addr)
|
||||
self.size = size if size is not None else self.DEFAULT_SIZE
|
||||
self.protect = size if prot is not None else self.DEFAULT_PROTECT
|
||||
|
||||
|
||||
def trigger(self, dbg, exception):
|
||||
"""Called when breakpoint is hit"""
|
||||
pass
|
||||
|
||||
|
||||
class LocalDebugger(object):
|
||||
"""A debugger interface around :func:`AddVectoredExceptionHandler`"""
|
||||
def __init__(self):
|
||||
self.breakpoints = {}
|
||||
self._memory_save = {}
|
||||
self._reput_breakpoint = {}
|
||||
self._hxbp_breakpoint = defaultdict(dict)
|
||||
|
||||
self.callback_vectored = winexception.VectoredException(self.callback)
|
||||
winproxy.AddVectoredExceptionHandler(0, self.callback_vectored)
|
||||
self.setup_hxbp_callback_vectored = winexception.VectoredException(self.setup_hxbp_callback)
|
||||
self.hxbp_info = None
|
||||
self.code = windows.native_exec.create_function("\xcc\xc3", [PVOID])
|
||||
self.veh_depth = 0
|
||||
self.current_exception = None
|
||||
self.exceptions_stack = [None]
|
||||
|
||||
@contextmanager
|
||||
def NewCurrentException(self, exc):
|
||||
try:
|
||||
self.exceptions_stack.append(exc)
|
||||
self.current_exception = exc
|
||||
self.veh_depth += 1
|
||||
yield exc
|
||||
finally:
|
||||
self.exceptions_stack.pop()
|
||||
self.current_exception = self.exceptions_stack[-1]
|
||||
self.veh_depth -= 1
|
||||
|
||||
def get_exception_code(self):
|
||||
"""Return ExceptionCode of current exception"""
|
||||
return self.current_exception[0].ExceptionRecord[0].ExceptionCode
|
||||
|
||||
def get_exception_context(self):
|
||||
"""Return context of current exception"""
|
||||
return self.current_exception[0].ContextRecord[0]
|
||||
|
||||
def single_step(self):
|
||||
"""Make the current thread to single step"""
|
||||
self.get_exception_context().EEFlags.TF = 1
|
||||
return windef.EXCEPTION_CONTINUE_EXECUTION
|
||||
|
||||
def _pass_breakpoint(self, addr, single_step):
|
||||
with windows.utils.VirtualProtected(addr, 1, PAGE_EXECUTE_READWRITE):
|
||||
windows.current_process.write_memory(addr, self._memory_save[addr])
|
||||
self._reput_breakpoint[windows.current_thread.tid] = self.breakpoints[addr], single_step
|
||||
return self.single_step()
|
||||
|
||||
def callback(self, exc):
|
||||
with self.NewCurrentException(exc):
|
||||
return self.handle_exception(exc)
|
||||
|
||||
def handle_exception(self, exc):
|
||||
exp_code = self.get_exception_code()
|
||||
context = self.get_exception_context()
|
||||
exp_addr = context.pc
|
||||
|
||||
if exp_code == EXCEPTION_BREAKPOINT and exp_addr in self.breakpoints:
|
||||
res = self.breakpoints[exp_addr].trigger(self, exc)
|
||||
single_step = self.get_exception_context().EEFlags.TF # single step activated by breakpoint
|
||||
if exp_addr in self.breakpoints: # Breakpoint deleted itself ?
|
||||
return self._pass_breakpoint(exp_addr, single_step)
|
||||
return EXCEPTION_CONTINUE_EXECUTION
|
||||
|
||||
if exp_code == EXCEPTION_SINGLE_STEP and windows.current_thread.tid in self._reput_breakpoint:
|
||||
bp, single_step = self._reput_breakpoint[windows.current_thread.tid]
|
||||
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")
|
||||
del self._reput_breakpoint[windows.current_thread.tid]
|
||||
if single_step:
|
||||
return self.on_exception(exc)
|
||||
return windef.EXCEPTION_CONTINUE_EXECUTION
|
||||
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
|
||||
return self.on_exception(exc)
|
||||
|
||||
def on_exception(self, exc):
|
||||
"""Called on exception"""
|
||||
if not self.get_exception_code() in winexception.exception_name_by_value:
|
||||
return windef.EXCEPTION_CONTINUE_SEARCH
|
||||
return windef.EXCEPTION_CONTINUE_EXECUTION
|
||||
|
||||
def del_bp(self, bp):
|
||||
if bp.type == STANDARD_BP:
|
||||
with windows.utils.VirtualProtected(bp.addr, 1, PAGE_EXECUTE_READWRITE):
|
||||
windows.current_process.write_memory(bp.addr, self._memory_save[bp.addr])
|
||||
del self._memory_save[bp.addr]
|
||||
del self.breakpoints[bp.addr]
|
||||
return
|
||||
if bp.type == HARDWARE_EXEC_BP:
|
||||
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)
|
||||
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))
|
||||
|
||||
def add_bp(self, bp, targets=None):
|
||||
"""Add a breakpoint, bp is a "class:`Breakpoint`
|
||||
|
||||
If the ``bp`` type is ``STANDARD_BP``, target must be None.
|
||||
|
||||
If the ``bp`` type is ``HARDWARE_EXEC_BP``, target can be None (all threads), or some threads of the process
|
||||
"""
|
||||
if bp.type == HARDWARE_EXEC_BP:
|
||||
return self.add_bp_hxbp(bp, targets)
|
||||
if bp.type != STANDARD_BP:
|
||||
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
|
||||
|
||||
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):
|
||||
with self.NewCurrentException(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 remove_hxbp_callback(self, exc):
|
||||
with self.NewCurrentException(exc):
|
||||
exp_code = self.get_exception_code()
|
||||
context = self.get_exception_context()
|
||||
exp_addr = context.pc
|
||||
hxbp_used = self.remove_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 remove_hxbp_in_context(self, context, addr):
|
||||
for i in range(4):
|
||||
target_drx = str(i)
|
||||
is_used = getattr(context.EDr7, "L" + str(i))
|
||||
draddr = getattr(context, "Dr" + target_drx)
|
||||
|
||||
if is_used and draddr == addr:
|
||||
setattr(context.EDr7, "L" + target_drx, 0)
|
||||
setattr(context, "Dr" + target_drx, 0)
|
||||
return i
|
||||
return None
|
||||
|
||||
def setup_hxbp_self_thread(self, addr):
|
||||
if self.current_exception is not None:
|
||||
x = self.setup_hxbp_in_context(self.get_exception_context(), addr)
|
||||
if x is None:
|
||||
raise ValueError("Could not setup HXBP")
|
||||
return
|
||||
|
||||
self.data = addr
|
||||
with winexception.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()
|
||||
|
||||
def remove_hxbp_self_thread(self, addr):
|
||||
if self.current_exception is not None:
|
||||
x = self.remove_hxbp_in_context(self.get_exception_context(), addr)
|
||||
if x is None:
|
||||
raise ValueError("Could not setup HXBP")
|
||||
return
|
||||
self.data = addr
|
||||
with winexception.VectoredExceptionHandler(1, self.remove_hxbp_callback):
|
||||
x = self.code()
|
||||
if x is None:
|
||||
raise ValueError("Could not remove HXBP")
|
||||
windows.current_process.write_memory(x, "\xcc")
|
||||
return
|
||||
|
||||
def remove_hxbp_other_thread(self, addr, thread):
|
||||
thread.suspend()
|
||||
ctx = thread.context
|
||||
x = self.remove_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()
|
||||
@@ -0,0 +1,249 @@
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
|
||||
import windows
|
||||
import windows.winobject.exception as winexception
|
||||
|
||||
from windows import winproxy
|
||||
from windows.generated_def import windef
|
||||
from windows.generated_def.winstructs import *
|
||||
from .breakpoints import *
|
||||
|
||||
|
||||
class LocalDebugger(object):
|
||||
"""A debugger interface around :func:`AddVectoredExceptionHandler`"""
|
||||
def __init__(self):
|
||||
self.breakpoints = {}
|
||||
self._memory_save = {}
|
||||
self._reput_breakpoint = {}
|
||||
self._hxbp_breakpoint = defaultdict(dict)
|
||||
|
||||
self.callback_vectored = winexception.VectoredException(self.callback)
|
||||
winproxy.AddVectoredExceptionHandler(0, self.callback_vectored)
|
||||
self.setup_hxbp_callback_vectored = winexception.VectoredException(self.setup_hxbp_callback)
|
||||
self.hxbp_info = None
|
||||
self.code = windows.native_exec.create_function("\xcc\xc3", [PVOID])
|
||||
self.veh_depth = 0
|
||||
self.current_exception = None
|
||||
self.exceptions_stack = [None]
|
||||
|
||||
@contextmanager
|
||||
def NewCurrentException(self, exc):
|
||||
try:
|
||||
self.exceptions_stack.append(exc)
|
||||
self.current_exception = exc
|
||||
self.veh_depth += 1
|
||||
yield exc
|
||||
finally:
|
||||
self.exceptions_stack.pop()
|
||||
self.current_exception = self.exceptions_stack[-1]
|
||||
self.veh_depth -= 1
|
||||
|
||||
def get_exception_code(self):
|
||||
"""Return ExceptionCode of current exception"""
|
||||
return self.current_exception[0].ExceptionRecord[0].ExceptionCode
|
||||
|
||||
def get_exception_context(self):
|
||||
"""Return context of current exception"""
|
||||
return self.current_exception[0].ContextRecord[0]
|
||||
|
||||
def single_step(self):
|
||||
"""Make the current thread to single step"""
|
||||
self.get_exception_context().EEFlags.TF = 1
|
||||
return windef.EXCEPTION_CONTINUE_EXECUTION
|
||||
|
||||
def _pass_breakpoint(self, addr, single_step):
|
||||
with windows.utils.VirtualProtected(addr, 1, PAGE_EXECUTE_READWRITE):
|
||||
windows.current_process.write_memory(addr, self._memory_save[addr])
|
||||
self._reput_breakpoint[windows.current_thread.tid] = self.breakpoints[addr], single_step
|
||||
return self.single_step()
|
||||
|
||||
def callback(self, exc):
|
||||
with self.NewCurrentException(exc):
|
||||
return self.handle_exception(exc)
|
||||
|
||||
def handle_exception(self, exc):
|
||||
exp_code = self.get_exception_code()
|
||||
context = self.get_exception_context()
|
||||
exp_addr = context.pc
|
||||
|
||||
if exp_code == EXCEPTION_BREAKPOINT and exp_addr in self.breakpoints:
|
||||
res = self.breakpoints[exp_addr].trigger(self, exc)
|
||||
single_step = self.get_exception_context().EEFlags.TF # single step activated by breakpoint
|
||||
if exp_addr in self.breakpoints: # Breakpoint deleted itself ?
|
||||
return self._pass_breakpoint(exp_addr, single_step)
|
||||
return EXCEPTION_CONTINUE_EXECUTION
|
||||
|
||||
if exp_code == EXCEPTION_SINGLE_STEP and windows.current_thread.tid in self._reput_breakpoint:
|
||||
bp, single_step = self._reput_breakpoint[windows.current_thread.tid]
|
||||
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")
|
||||
del self._reput_breakpoint[windows.current_thread.tid]
|
||||
if single_step:
|
||||
return self.on_exception(exc)
|
||||
return windef.EXCEPTION_CONTINUE_EXECUTION
|
||||
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
|
||||
return self.on_exception(exc)
|
||||
|
||||
def on_exception(self, exc):
|
||||
"""Called on exception"""
|
||||
if not self.get_exception_code() in winexception.exception_name_by_value:
|
||||
return windef.EXCEPTION_CONTINUE_SEARCH
|
||||
return windef.EXCEPTION_CONTINUE_EXECUTION
|
||||
|
||||
def del_bp(self, bp):
|
||||
if bp.type == STANDARD_BP:
|
||||
with windows.utils.VirtualProtected(bp.addr, 1, PAGE_EXECUTE_READWRITE):
|
||||
windows.current_process.write_memory(bp.addr, self._memory_save[bp.addr])
|
||||
del self._memory_save[bp.addr]
|
||||
del self.breakpoints[bp.addr]
|
||||
return
|
||||
if bp.type == HARDWARE_EXEC_BP:
|
||||
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)
|
||||
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))
|
||||
|
||||
def add_bp(self, bp, targets=None):
|
||||
"""Add a breakpoint, bp is a "class:`Breakpoint`
|
||||
|
||||
If the ``bp`` type is ``STANDARD_BP``, target must be None.
|
||||
|
||||
If the ``bp`` type is ``HARDWARE_EXEC_BP``, target can be None (all threads), or some threads of the process
|
||||
"""
|
||||
if bp.type == HARDWARE_EXEC_BP:
|
||||
return self.add_bp_hxbp(bp, targets)
|
||||
if bp.type != STANDARD_BP:
|
||||
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
|
||||
|
||||
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):
|
||||
with self.NewCurrentException(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 remove_hxbp_callback(self, exc):
|
||||
with self.NewCurrentException(exc):
|
||||
exp_code = self.get_exception_code()
|
||||
context = self.get_exception_context()
|
||||
exp_addr = context.pc
|
||||
hxbp_used = self.remove_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 remove_hxbp_in_context(self, context, addr):
|
||||
for i in range(4):
|
||||
target_drx = str(i)
|
||||
is_used = getattr(context.EDr7, "L" + str(i))
|
||||
draddr = getattr(context, "Dr" + target_drx)
|
||||
|
||||
if is_used and draddr == addr:
|
||||
setattr(context.EDr7, "L" + target_drx, 0)
|
||||
setattr(context, "Dr" + target_drx, 0)
|
||||
return i
|
||||
return None
|
||||
|
||||
def setup_hxbp_self_thread(self, addr):
|
||||
if self.current_exception is not None:
|
||||
x = self.setup_hxbp_in_context(self.get_exception_context(), addr)
|
||||
if x is None:
|
||||
raise ValueError("Could not setup HXBP")
|
||||
return
|
||||
|
||||
self.data = addr
|
||||
with winexception.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()
|
||||
|
||||
def remove_hxbp_self_thread(self, addr):
|
||||
if self.current_exception is not None:
|
||||
x = self.remove_hxbp_in_context(self.get_exception_context(), addr)
|
||||
if x is None:
|
||||
raise ValueError("Could not setup HXBP")
|
||||
return
|
||||
self.data = addr
|
||||
with winexception.VectoredExceptionHandler(1, self.remove_hxbp_callback):
|
||||
x = self.code()
|
||||
if x is None:
|
||||
raise ValueError("Could not remove HXBP")
|
||||
windows.current_process.write_memory(x, "\xcc")
|
||||
return
|
||||
|
||||
def remove_hxbp_other_thread(self, addr, thread):
|
||||
thread.suspend()
|
||||
ctx = thread.context
|
||||
x = self.remove_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()
|
||||
Reference in New Issue
Block a user