From 010453e96dae17165c522bfd69e8c954dac5f5ec Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Tue, 26 Jan 2016 14:50:21 +0100 Subject: [PATCH] Fix test + Fix a Use-After-CloseHandle in debugger + add dbgprint on HANDLE --- windows/debug.py | 30 ++++++++++++++++++++---------- windows/test/__init__.py | 4 ++-- windows/test/mytest.py | 12 ++++++------ windows/winobject.py | 9 +++++++++ 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/windows/debug.py b/windows/debug.py index 3155e1a..10b81ad 100644 --- a/windows/debug.py +++ b/windows/debug.py @@ -2,6 +2,7 @@ import windows import windows.winproxy as winproxy from windows.winobject import WinProcess, WinThread +from windows.dbgprint import dbgprint import windows.native_exec.simple_x86 as x86 import windows.native_exec.simple_x64 as x64 @@ -126,13 +127,11 @@ class Debugger(object): all_threads.append(target) else: raise ValueError("Unknow HXBP target type for <{0}>".format(target)) - for target_thread in all_threads: x = self._hardware_breakpoint[target_thread.tid] if all(pos in x for pos in range(4)): raise ValueError("Cannot put {0} in {1} (DRx full)".format(bp, target_thread)) empty_drx = str([pos for pos in range(4) if pos not in x][0]) - #print("Empty DRx = {0}".format(empty_drx)) ctx = target_thread.context ctx.EDr7.GE = 1 ctx.EDr7.LE = 1 @@ -140,7 +139,6 @@ class Debugger(object): setattr(ctx.EDr7, "L" + empty_drx, 1) setattr(ctx, "Dr" + empty_drx, bp.addr) x[int(empty_drx)] = bp - target_thread.set_context(ctx) @@ -153,6 +151,12 @@ class Debugger(object): for bp, expected_target in pending_todo: # Valid addr ? (in non-loaded module: raise / pass ?) if expected_target is None or expected_target.pid == target.pid: + if isinstance(target, WinThread): + x = self._hardware_breakpoint[target.tid] + # Ignore BP on thread_create that have already been + # put by the process_create event + if bp in x.values(): + continue _setup_method = getattr(self, "_setup_breakpoint_" + bp.type) _setup_method(bp, [target]) # TODO REMOVE PENDING HERE if target is not None.. @@ -206,13 +210,7 @@ class Debugger(object): self.on_exception(exception) - def _handle_create_thread(self, debug_event): - """Handle CREATE_THREAD_DEBUG_EVENT""" - create_thread = debug_event.u.CreateThread - self.current_thread = WinThread._from_handle(create_thread.hThread) - self.threads[self.current_thread.tid] = self.current_thread - self._setup_pending_breakpoints(self.current_thread) - self.on_create_thread(create_thread) + def _handle_create_process(self, debug_event): """Handle CREATE_PROCESS_DEBUG_EVENT""" @@ -232,10 +230,21 @@ class Debugger(object): self._update_debugger_state(debug_event) exit_process = debug_event.u.ExitProcess self.on_exit_process(exit_process) + del self.threads[self.current_thread.tid] del self.processes[self.current_process.pid] # Hack IT, ContinueDebugEvent will close the HANDLE for us # Should we make another handle instead ? + dbgprint("Removing handle {0} for {1} (will be closed by continueDebugEvent".format(hex(self.current_process._handle), self.current_process), "HANDLE") del self.current_process._handle + del self.current_thread._handle + + def _handle_create_thread(self, debug_event): + """Handle CREATE_THREAD_DEBUG_EVENT""" + create_thread = debug_event.u.CreateThread + self.current_thread = WinThread._from_handle(create_thread.hThread) + self.threads[self.current_thread.tid] = self.current_thread + self._setup_pending_breakpoints(self.current_thread) + self.on_create_thread(create_thread) def _handle_exit_thread(self, debug_event): """Handle EXIT_THREAD_DEBUG_EVENT""" @@ -245,6 +254,7 @@ class Debugger(object): del self.threads[self.current_thread.tid] # Hack IT, ContinueDebugEvent will close the HANDLE for us # Should we make another handle instead ? + dbgprint("Removing handle {0} for {1} (will be closed by continueDebugEvent".format(hex(self.current_thread._handle), self.current_thread), "HANDLE") del self.current_thread._handle def _handle_load_dll(self, debug_event): diff --git a/windows/test/__init__.py b/windows/test/__init__.py index 2635965..8b6e9ab 100644 --- a/windows/test/__init__.py +++ b/windows/test/__init__.py @@ -1,3 +1,3 @@ -from mytest import WindowsTestCase, WindowsAPITestCase, pop_calc_32, pop_calc_64, Calc32, Calc64 +from mytest import WindowsTestCase, WindowsAPITestCase, DebuggerTestCase, pop_calc_32, pop_calc_64, Calc32, Calc64 -__all__ = ["WindowsTestCase", "WindowsAPITestCase"] +__all__ = ["WindowsTestCase", "WindowsAPITestCase", "DebuggerTestCase"] diff --git a/windows/test/mytest.py b/windows/test/mytest.py index d50e7c9..e61834c 100644 --- a/windows/test/mytest.py +++ b/windows/test/mytest.py @@ -28,21 +28,21 @@ process_64bit_only = unittest.skipIf(not is_process_64_bits, "Test for 64bits pr if is_windows_32_bits: - def pop_calc_32(dwCreationFlags): + def pop_calc_32(dwCreationFlags=0): return windows.utils.create_process(r"C:\Windows\system32\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) - def pop_calc_64(dwCreationFlags): + def pop_calc_64(dwCreationFlags=0): raise WindowsError("Cannot create calc64 in 32bits system") else: - def pop_calc_32(dwCreationFlags): + def pop_calc_32(dwCreationFlags=0): return windows.utils.create_process(r"C:\Windows\syswow64\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) if is_process_32_bits: - def pop_calc_64(dwCreationFlags): + def pop_calc_64(dwCreationFlags=0): with windows.utils.DisableWow64FsRedirection(): return windows.utils.create_process(r"C:\Windows\system32\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) else: - def pop_calc_64(dwCreationFlags): + def pop_calc_64(dwCreationFlags=0): return windows.utils.create_process(r"C:\Windows\system32\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) @@ -55,6 +55,7 @@ def Calc64(exit_code=0): calc.exit(exit_code) + @contextmanager def Calc32(exit_code=0): try: @@ -425,7 +426,6 @@ class DebuggerTestCase(unittest.TestCase): def trigger(self, dbg, exc): TEST_CASE.assertNotEqual(len(dbg.current_process.threads), 1) for t in dbg.current_process.threads: - print(hex(t.context.Dr7)) TEST_CASE.assertNotEqual(t.context.Dr7, 0) if data[0] == 0: #First time we got it ! create new thread data[0] = 1 diff --git a/windows/winobject.py b/windows/winobject.py index 8f022b5..e0323d5 100644 --- a/windows/winobject.py +++ b/windows/winobject.py @@ -26,6 +26,7 @@ import windows.pe_parse as pe_parse + class AutoHandle(object): """An abstract class that allow easy handle creation/destruction/wait""" # Big bypass to prevent missing reference at programm close.. @@ -45,6 +46,7 @@ class AutoHandle(object): if hasattr(self, "_handle"): return self._handle self._handle = self._get_handle() + dbgprint("Open handle {0} for {1}".format(hex(self._handle), self), "HANDLE") return self._handle def wait(self, timeout=INFINITE): @@ -53,6 +55,7 @@ class AutoHandle(object): def __del__(self): if hasattr(self, "_handle") and self._handle: + dbgprint("Closing Handle {0} for {1}".format(hex(self._handle), self), "HANDLE") self.CLOSE_FUNCTION(self._handle) @@ -235,8 +238,10 @@ class WinThread(THREADENTRY32, AutoHandle): thread = [t for t in System().threads if t.tid == tid][0] # set AutoHandle _handle thread._handle = handle + dbgprint("Thread {0} from handle {1}".format(thread, hex(handle)), "HANDLE") return thread except IndexError: + dbgprint("DeadThread from handle {0}".format(hex(handle)), "HANDLE") return DeadThread(handle, tid) class DeadThread(AutoHandle): @@ -518,6 +523,7 @@ class WinProcess(PROCESSENTRY32, Process): pid = winproxy.GetProcessId(handle) proc = [p for p in windows.system.processes if p.pid == pid][0] proc._handle = handle + dbgprint("Process {0} from handle {1}".format(proc, hex(handle)), "HANDLE") return proc @@ -738,6 +744,9 @@ class WinProcess(PROCESSENTRY32, Process): """Exit the process""" return winproxy.TerminateProcess(self.handle, code) + + + # Create ProcessToken and Thread Token objects ? class Token(AutoHandle): def __init__(self, handle):