From f54a64670ea898f866cdb762efe9b6569fbe0d10 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Wed, 20 Jul 2016 18:21:28 +0200 Subject: [PATCH] Add context_syswow/set_syswow_context + debugger able to handle BP in 64b part of syswow process --- CHANGELOG | 5 ++++- TODO | 3 +++ ctypes_generation/definitions/windef.txt | 1 + windows/debug/debugger.py | 24 ++++++++++++++++++++++-- windows/generated_def/windef.py | 1 + windows/syswow64.py | 9 +++++++-- windows/winobject/process.py | 22 ++++++++++++++++++++++ 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6da8d2e..d86dd27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,4 +19,7 @@ Since 0.2: * 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 \ No newline at end of file + * Add Context.func_result as abstract register for EAX/RAX + * Can retrieve 64b context of syswow thread via context_syswow/set_syswow_context + * Debugger handle breakpoint in 64b part of syswow process + * ReadSyswow64Process is now a Process (allows to parse exports of remote PEB64 of syswow process) \ No newline at end of file diff --git a/TODO b/TODO index 7960115..8b0a8cf 100644 --- a/TODO +++ b/TODO @@ -20,6 +20,9 @@ TODO: - registry - test ! + - processes + - TEST / DOC of Process.context_syswow + - Injection - death of process in execute_python raise a WindowsError with explicit message (change sample in readme) diff --git a/ctypes_generation/definitions/windef.txt b/ctypes_generation/definitions/windef.txt index 38788be..df557dc 100644 --- a/ctypes_generation/definitions/windef.txt +++ b/ctypes_generation/definitions/windef.txt @@ -223,6 +223,7 @@ #define CONTEXT_FULL CONTEXT_I386 | CONTEXT_FULL #define CONTEXT_ALL CONTEXT_I386 | CONTEXT_ALL +#define CONTEXT_XSTATE (CONTEXT_I386 | 0x00000040L) #define PAGE_NOACCESS 0x01 diff --git a/windows/debug/debugger.py b/windows/debug/debugger.py index 9ca8940..29287a3 100644 --- a/windows/debug/debugger.py +++ b/windows/debug/debugger.py @@ -14,6 +14,7 @@ from windows.generated_def.winstructs import * from windows.generated_def import windef from .breakpoints import * +#from windows.syswow64 import CS_32bits from windows.winobject.exception import VectoredException @@ -386,11 +387,18 @@ class Debugger(object): def _handle_exception_breakpoint(self, exception, excp_addr): + excp_bitness = self.get_exception_bitness(exception) if excp_addr in self.breakpoints[self.current_process.pid]: thread = self.current_thread - ctx = thread.context + if self.current_process.bitness == 32 and excp_bitness == 64: + ctx = thread.context_syswow + else: + ctx = thread.context ctx.pc -= 1 - thread.set_context(ctx) + if self.current_process.bitness == 32 and excp_bitness == 64: + thread.set_syswow_context(ctx) + else: + 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 if excp_addr in self.breakpoints[self.current_process.pid]: @@ -597,6 +605,11 @@ class Debugger(object): load_dll = debug_event.u.LoadDll dll = self._get_loaded_dll(load_dll) dll_name = os.path.basename(dll).lower() + if dll_name.endswith(".dll"): + dll_name = dll_name[:-4] + if dll_name.endswith(".dll64"): + dll_name = dll_name[:-6] + "64" # Crade.. + #print("Load {0} -> {1}".format(dll, dll_name)) self._module_by_process[self.current_process.pid][dll_name] = windows.pe_parse.GetPEFile(load_dll.lpBaseOfDll, self.current_process) self._setup_pending_breakpoints_load_dll(dll_name) with self.DisabledMemoryBreakpoint(): @@ -746,6 +759,13 @@ class Debugger(object): finally: self.restore_all_memory_breakpoints_verif_remove(data, target) + def get_exception_bitness(self, exc): + if windows.current_process.bitness == 32: + return 32 + if exc.ExceptionRecord.ExceptionCode in [STATUS_WX86_BREAKPOINT, STATUS_WX86_SINGLE_STEP]: + return 32 + return 64 + # Public callback def on_exception(self, exception): """Called on exception event other that known breakpoint or requested single step. ``exception`` is one of the following type: diff --git a/windows/generated_def/windef.py b/windows/generated_def/windef.py index 54661d4..171a6e6 100644 --- a/windows/generated_def/windef.py +++ b/windows/generated_def/windef.py @@ -222,6 +222,7 @@ CONTEXT_FULL = Flag("CONTEXT_FULL", ( CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEX CONTEXT_ALL = Flag("CONTEXT_ALL", ( CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS )) CONTEXT_FULL = Flag("CONTEXT_FULL", CONTEXT_I386 | CONTEXT_FULL) CONTEXT_ALL = Flag("CONTEXT_ALL", CONTEXT_I386 | CONTEXT_ALL) +CONTEXT_XSTATE = Flag("CONTEXT_XSTATE", ( CONTEXT_I386 | 0x00000040 )) PAGE_NOACCESS = Flag("PAGE_NOACCESS", 0x01) PAGE_READONLY = Flag("PAGE_READONLY", 0x02) PAGE_READWRITE = Flag("PAGE_READWRITE", 0x04) diff --git a/windows/syswow64.py b/windows/syswow64.py index 3a3626b..877c5e3 100644 --- a/windows/syswow64.py +++ b/windows/syswow64.py @@ -159,16 +159,21 @@ def get_current_process_syswow_peb(): return windows.winobject.process.RemotePEB64(peb_addr, CurrentProcessReadSyswow()) -class ReadSyswow64Process(object): +class ReadSyswow64Process(process.Process): def __init__(self, target): self.target = target - self.bitness = target.bitness + self._bitness = target.bitness + + def _get_handle(self): + return self.target.handle def read_memory(self, addr, size): buffer_addr = ctypes.create_string_buffer(size) winproxy.NtWow64ReadVirtualMemory64(self.target.handle, addr, buffer_addr, size) return buffer_addr[:] + #read_string = process.Process.read_string + def get_syswow_ntdll_exports(): if get_syswow_ntdll_exports.value is not None: diff --git a/windows/winobject/process.py b/windows/winobject/process.py index 34b7e34..000adc6 100644 --- a/windows/winobject/process.py +++ b/windows/winobject/process.py @@ -110,6 +110,19 @@ class WinThread(THREADENTRY32, AutoHandle): winproxy.GetThreadContext(self.handle, x) return x + @property + def context_syswow(self): + if not self.owner.is_wow_64: + raise ValueError("Not a syswow process") + x = exception.ECONTEXT64.new_aligned() + x.ContextFlags = CONTEXT_ALL + if windows.current_process.bitness == 64: + winproxy.GetThreadContext(self.handle, x) + else: + windows.syswow64.NtGetContextThread_32_to_64(self.handle, x) + return x + + def set_context(self, context): """Set the thread context to ``context``""" if self.owner.bitness == windows.current_process.bitness: @@ -118,6 +131,15 @@ class WinThread(THREADENTRY32, AutoHandle): return winproxy.Wow64SetThreadContext(self.handle, context) return windows.syswow64.NtSetContextThread_32_to_64(self.handle, ctypes.byref(context)) + + def set_syswow_context(self, context): + if not self.owner.is_wow_64: + raise ValueError("Not a syswow process") + if windows.current_process.bitness == 64: + return winproxy.SetThreadContext(self.handle, context) + return windows.syswow64.NtSetContextThread_32_to_64(self.handle, ctypes.byref(context)) + + @property def start_address(self): """The start address of the thread