diff --git a/TODO b/TODO index cdae1c8..d596ec3 100644 --- a/TODO +++ b/TODO @@ -4,6 +4,11 @@ TODO: - Extend Registry feature (write) - remove pe_parse.transform_ctypes_fields (use utils.transform_ctypes_fields) + - DBG + - Verif multiple bp at same place.. + - Verif multiple pending at same place + - Clean / (rethink?) vectored_exception (+rename exception.py? context.py?) + - Test !! (bp, BP_HX, bp on only on process, bp_hx on only one thread..) FIXME: - WMI diff --git a/windows/debug.py b/windows/debug.py index 3d7a3f7..3155e1a 100644 --- a/windows/debug.py +++ b/windows/debug.py @@ -9,6 +9,11 @@ import windows.native_exec.simple_x64 as x64 from windows.generated_def.winstructs import * from .generated_def import windef +from collections import defaultdict + + +STANDARD_BP = "BP" +HARDWARE_EXEC_BP = "HXBP" class DEBUG_EVENT(DEBUG_EVENT): KNOWN_EVENT_CODE = dict((x,x) for x in [EXCEPTION_DEBUG_EVENT, @@ -33,9 +38,17 @@ class Debugger(object): self.current_process = None self.current_thread = None + # List of breakpoints self.breakpoints = {} - self._pending_breakpoints = {} #Breakpoints to put in new process - self._break_metadata = {} + + self._pending_breakpoints = {} #Breakpoints to put in new process / threads + + # Values rewritten by "\xcc" + self._memory_save = defaultdict(dict) + # Dict of {tid : {drx taken : BP}} + self._hardware_breakpoint = defaultdict(dict) + # Breakpoints to reput.. + self._breakpoint_to_reput = {} def _init_dispatch_handlers(self): @@ -73,43 +86,89 @@ class Debugger(object): def _dispatch_breakpoint(self, exception, addr): bp = self.breakpoints[addr] - return bp(self, exception) + bp.trigger(self, exception) + return bp + + # Breakpoint stuff + #def _setup_breakpoint(self, bp, target): + # if bp.type != 0: + # raise NotImplementedError("BP TYPE != 0 (TODO)") + # if target is None: + # targets = self.processes.items() + # # Raise on multiple pending at same addr ? + # # We will add the pending breakpoint to other new processes + # self._pending_breakpoints[bp.addr] = (bp, target) + # else: + # targets = [(target.pid, target)] + # + # for pid, process in targets: + # self._break_metadata[pid][bp.addr] = process.read_memory(bp.addr, 1) + # #print("Write BP: {0} at {1}".format(process, addr)) + # process.write_memory(bp.addr, "\xcc") + # return + + + def _setup_breakpoint_BP(self, bp, targets): + for target in targets: + if not isinstance(target, WinProcess): + raise ValueError("Cannot put standard breakpoint on target {0} (not a process)".format(target)) + self._memory_save[target.pid][bp.addr] = target.read_memory(bp.addr, 1) + #print("Write BP: {0} at {1}".format(process, addr)) + target.write_memory(bp.addr, "\xcc") + + def _setup_breakpoint_HXBP(self, bp, targets): + all_threads = [] + for target in targets: + if isinstance(target, WinProcess): + for t in target.threads: + all_threads.append(t) + elif isinstance(target, WinThread): + 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 + + setattr(ctx.EDr7, "L" + empty_drx, 1) + setattr(ctx, "Dr" + empty_drx, bp.addr) + x[int(empty_drx)] = bp + + target_thread.set_context(ctx) - def _setup_breakpoint(self, addr, type, target): - if type != 0: - raise NotImplementedError("BP TYPE != 0 (TODO)") - if target is None: - targets = self.processes.items() - # Raise on multiple pending ? - self._pending_breakpoints[addr] = (addr, type, target) - else: - targets = [(target.pid, target)] - for pid, process in targets: - self._break_metadata[pid] = process.read_memory(addr, 1) - print("Write BP: {0} at {1}".format(process, addr)) - process.write_memory(addr, "\xcc") - return def _setup_pending_breakpoints(self, target): - for addr, (bp_info) in self._pending_breakpoints.items(): + # TODO: good format of data ? (dict and we just use values) + # TODO: need to handle threads ? + # TODO: handle target/expected_target is a thread :) + # Can it happen ? + pending_todo = list(self._pending_breakpoints.values()) + for bp, expected_target in pending_todo: # Valid addr ? (in non-loaded module: raise / pass ?) - expected_target = bp_info[2] if expected_target is None or expected_target.pid == target.pid: - self._setup_breakpoint(bp_info[0], bp_info[1], target) - print("BP PLACED IN {0}".format(target)) + _setup_method = getattr(self, "_setup_breakpoint_" + bp.type) + _setup_method(bp, [target]) + # TODO REMOVE PENDING HERE if target is not None.. - def _activate_single_step(self, thread): - raise NotImplementedError("TODO") - regs = self.get_context(thread) + + def _pass_breakpoint(self, addr): + process = self.current_process + thread = self.current_thread + process.write_memory(addr, self._memory_save[process.pid][addr]) + regs = thread.context regs.EFlags |= (1 << 8) - self.set_context(thread, regs) - - def _desactivate_single_step(self, thread): - regs = self.get_context(thread) - raise NotImplementedError("TODO") - regs.EFlags &= ~(1 << 8) - self.set_context(thread, regs) + regs.Eip -= 1 + thread.set_context(regs) + self._breakpoint_to_reput[thread.tid] = addr #Register pending breakpoint for next single step + # debug event handlers def _handle_unknown_debug_event(self, debug_event): raise NotImplementedError("dwDebugEventCode = {0}".format(debug_event.dwDebugEventCode)) @@ -124,9 +183,25 @@ class Debugger(object): excp_code = exception.ExceptionRecord.ExceptionCode excp_addr = exception.ExceptionRecord.ExceptionAddress - print("Exception {0} at {1}".format(excp_code, hex(excp_addr))) if excp_code == EXCEPTION_BREAKPOINT and excp_addr in self.breakpoints: self._dispatch_breakpoint(exception, excp_addr) + self._pass_breakpoint(excp_addr) + return + elif excp_code == EXCEPTION_SINGLE_STEP: + if self.current_thread.tid in self._breakpoint_to_reput: + addr = self._breakpoint_to_reput[self.current_thread.tid] + del self._breakpoint_to_reput[self.current_thread.tid] + # Re-put the breakpoint + self.current_process.write_memory(addr, "\xcc") + elif excp_addr in self.breakpoints: + # Verif that's not a standard BP ? + bp = self.breakpoints[excp_addr] + bp.trigger(self, exception) + ctx = self.current_thread.context + ctx.EEFlags.RF = 1 + self.current_thread.set_context(ctx) + else: + self.on_exception(exception) else: # Do not trigger self.on_exception if breakpoint was registered self.on_exception(exception) @@ -136,6 +211,7 @@ class Debugger(object): 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): @@ -195,8 +271,45 @@ class Debugger(object): rip_info = debug_event.u.RipInfo self.on_rip(rip_info) - # Public callback + # Public API + def loop(self): + for debug_event in self._debug_event_generator(): + self._dispatch_debug_event(debug_event) + self._finish_debug_event(debug_event, windef.DBG_CONTINUE) + if not self.processes: + # No More process to debug + break + def add_bp(self, bp, addr=None, type=None, target=None): + """TODO: use type for hardware breakpoints""" + if getattr(bp, "addr", None) is None: + if addr is None or type is None: + raise ValueError("SUCK YOUR NONE") + bp = ProxyBreakpoint(bp, addr, type) + else: + if addr is not None or type is not None: + raise ValueError("Given by parameters but BP object have them") + del addr + del type + if target is None: + # Raise on multiple pending at same addr ? + # We will add the pending breakpoint to other new processes + if bp.addr in self._pending_breakpoints: + raise ValueError("Pending breakpoint already at {0}".format(hex(bp.addr))) + self._pending_breakpoints[bp.addr] = (bp, target) + targets = self.processes.values() + if targets is None: + return + else: + targets = [target] + if bp.addr in self.breakpoints: + raise ValueError("Breakpoint already at {0}".format(hex(bp.addr))) + self.breakpoints[bp.addr] = bp + _setup_method = getattr(self, "_setup_breakpoint_" + bp.type) + _setup_method(bp, targets) + return True + + # Public callback def on_exception(self, exception): pass @@ -224,36 +337,26 @@ class Debugger(object): def on_rip(self, rip_info): pass - # Public API - def loop(self): - for x, debug_event in enumerate(self._debug_event_generator()): - self._dispatch_debug_event(debug_event) - self._finish_debug_event(debug_event, windef.DBG_CONTINUE) - if not self.processes: - # No More process to debug - break - - def add_bp(self, bp, addr=None, target=None): - """TODO: use type for hardware breakpoints""" - call_target = bp - if getattr(bp, "addr", None) is not None: - addr = bp.addr - call_target = bp.trigger - # if addr is not None: raise ? - - # Non object breakpoint - if addr is None: - raise ValueError("No address: need a valid or parameter") - self.breakpoints[addr] = call_target - self._setup_breakpoint(addr, bp.type, target) - return True - class Breakpoint(object): - type = 0 # REAL BP + type = "BP" # REAL BP def __init__(self, addr): self.addr = addr - def trigger(self, exception): + def trigger(self, dbg, exception): 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): + type = HARDWARE_EXEC_BP + + + diff --git a/windows/test/mytest.py b/windows/test/mytest.py index 6c6973f..d50e7c9 100644 --- a/windows/test/mytest.py +++ b/windows/test/mytest.py @@ -8,9 +8,12 @@ from contextlib import contextmanager sys.path.append(".") import unittest import windows +import windows.debug import windows.native_exec.simple_x86 as x86 import windows.native_exec.simple_x64 as x64 +from windows.generated_def.winstructs import * + is_process_32_bits = windows.current_process.bitness == 32 is_process_64_bits = windows.current_process.bitness == 64 @@ -25,22 +28,22 @@ process_64bit_only = unittest.skipIf(not is_process_64_bits, "Test for 64bits pr if is_windows_32_bits: - def pop_calc_32(): - return windows.utils.create_process(r"C:\Windows\system32\calc.exe", show_windows=True) + def pop_calc_32(dwCreationFlags): + return windows.utils.create_process(r"C:\Windows\system32\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) - def pop_calc_64(): + def pop_calc_64(dwCreationFlags): raise WindowsError("Cannot create calc64 in 32bits system") else: - def pop_calc_32(): - return windows.utils.create_process(r"C:\Windows\syswow64\calc.exe", show_windows=True) + def pop_calc_32(dwCreationFlags): + 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(): + def pop_calc_64(dwCreationFlags): with windows.utils.DisableWow64FsRedirection(): - return windows.utils.create_process(r"C:\Windows\system32\calc.exe", show_windows=True) + return windows.utils.create_process(r"C:\Windows\system32\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) else: - def pop_calc_64(): - return windows.utils.create_process(r"C:\Windows\system32\calc.exe", show_windows=True) + def pop_calc_64(dwCreationFlags): + return windows.utils.create_process(r"C:\Windows\system32\calc.exe", dwCreationFlags=dwCreationFlags, show_windows=True) @contextmanager @@ -298,10 +301,154 @@ class WindowsAPITestCase(unittest.TestCase): windows.winproxy.CreateFileA("NONEXISTFILE.FILE") +class DebuggerTestCase(unittest.TestCase): + + def debuggable_calc_32(self): + return windows.utils.create_process(r"C:\python27\python.exe", dwCreationFlags=DEBUG_PROCESS | CREATE_NEW_CONSOLE, show_windows=True) + + def test_init_breakpoint_callback(self): + TEST_CASE = self + class MyDbg(windows.debug.Debugger): + def on_exception(self, exception): + TEST_CASE.assertEqual(exception.ExceptionRecord.ExceptionCode, EXCEPTION_BREAKPOINT) + self.current_process.exit() + + calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + d = MyDbg(calc) + d.loop() + + def test_simple_standard_breakpoint(self): + TEST_CASE = self + + class TSTBP(windows.debug.Breakpoint): + def trigger(self, dbg, exc): + TEST_CASE.assertEqual(dbg.current_process.pid, calc.pid) + TEST_CASE.assertEqual(dbg.current_process.read_memory(self.addr, 1), "\xcc") + TEST_CASE.assertEqual(dbg.current_thread.context.pc - 1, self.addr) + d.current_process.exit() + + calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + d = windows.debug.Debugger(calc) + d.add_bp(TSTBP(windows.current_process.peb.modules[1].pe.exports["LdrLoadDll"])) + d.loop() + + def test_simple_hwx_breakpoint(self): + TEST_CASE = self + + class TSTBP(windows.debug.HXBreakpoint): + def trigger(self, dbg, exc): + TEST_CASE.assertEqual(dbg.current_process.pid, calc.pid) + TEST_CASE.assertEqual(dbg.current_thread.context.pc, self.addr) + TEST_CASE.assertNotEqual(dbg.current_thread.context.Dr7, 0) + d.current_process.exit() + + calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + d = windows.debug.Debugger(calc) + d.add_bp(TSTBP(windows.current_process.peb.modules[1].pe.exports["LdrLoadDll"])) + d.loop() + + def test_multiple_hwx_breakpoint(self): + TEST_CASE = self + data = [0] + class TSTBP(windows.debug.HXBreakpoint): + def __init__(self, addr, expec_before): + self.addr = addr + self.expec_before = expec_before + + def trigger(self, dbg, exc): + TEST_CASE.assertEqual(dbg.current_process.pid, calc.pid) + TEST_CASE.assertEqual(dbg.current_thread.context.pc, self.addr) + TEST_CASE.assertNotEqual(dbg.current_thread.context.Dr7, 0) + TEST_CASE.assertEqual(data[0], self.expec_before) + TEST_CASE.assertNotEqual(dbg.current_process.read_memory(self.addr, 1), "\xcc") + data[0] += 1 + if data[0] == 4: + d.current_process.exit() + + calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + d = windows.debug.Debugger(calc) + addr = calc.virtual_alloc(0x1000) + calc.write_memory(addr, "\x90" * 8) + d.add_bp(TSTBP(addr, 0)) + d.add_bp(TSTBP(addr + 1, 1)) + d.add_bp(TSTBP(addr + 2, 2)) + d.add_bp(TSTBP(addr + 3, 3)) + + calc.create_thread(addr, 0) + d.loop() + # Used to verif we actually called the Breakpoints + TEST_CASE.assertEqual(data[0], 4) + + def test_four_hwx_breakpoint_fail(self): + TEST_CASE = self + data = [0] + + class TSTBP(windows.debug.HXBreakpoint): + def __init__(self, addr, expec_before): + self.addr = addr + self.expec_before = expec_before + + def trigger(self, dbg, exc): + raise NotImplementedError("Should fail before") + + calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + d = windows.debug.Debugger(calc) + addr = calc.virtual_alloc(0x1000) + calc.write_memory(addr, "\x90" * 8) + d.add_bp(TSTBP(addr, 0)) + d.add_bp(TSTBP(addr + 1, 1)) + d.add_bp(TSTBP(addr + 2, 2)) + d.add_bp(TSTBP(addr + 3, 3)) + d.add_bp(TSTBP(addr + 4, 4)) + + calc.create_thread(addr, 0) + with self.assertRaises(ValueError) as e: + d.loop() + self.assertIn("DRx", e.exception.message) + # Used to verif we actually NOT called the Breakpoints + TEST_CASE.assertEqual(data[0], 0) + + def test_hwx_breakpoint_are_on_all_thread(self): + TEST_CASE = self + data = [0] + + class MyDbg(windows.debug.Debugger): + def on_create_thread(self, exception): + # Check that later created thread have their HWX breakpoint :) + TEST_CASE.assertNotEqual(self.current_thread.context.Dr7, 0) + + class TSTBP(windows.debug.HXBreakpoint): + def __init__(self, addr, expec_before): + self.addr = addr + self.expec_before = expec_before + + 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 + calc.create_thread(addr, 0) + else: + d.current_process.exit() + + calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) + d = MyDbg(calc) + addr = calc.virtual_alloc(0x1000) + calc.write_memory(addr, "\x90" * 2) + d.add_bp(TSTBP(addr, 0)) + calc.create_thread(addr, 0) + d.loop() + # Used to verif we actually called the Breakpoints + TEST_CASE.assertEqual(data[0], 1) + + if __name__ == '__main__': alltests = unittest.TestSuite() alltests.addTest(unittest.makeSuite(WindowsTestCase)) alltests.addTest(unittest.makeSuite(WindowsAPITestCase)) + alltests.addTest(unittest.makeSuite(DebuggerTestCase)) alltests.debug() tester = unittest.TextTestRunner(verbosity=2) tester.run(alltests) diff --git a/windows/vectored_exception.py b/windows/vectored_exception.py index 31fa296..b273177 100644 --- a/windows/vectored_exception.py +++ b/windows/vectored_exception.py @@ -63,41 +63,92 @@ class EEXCEPTION_DEBUG_INFO32(ctypes.Structure): class EEXCEPTION_DEBUG_INFO64(ctypes.Structure): _fields_ = windows.utils.transform_ctypes_fields(EXCEPTION_DEBUG_INFO, {"ExceptionRecord": EnhancedEXCEPTION_RECORD64}) -class Eflags(int): - _flags_ = [("CF", 1), - ("RES_1", 1), - ("PF", 1), - ("RES_3", 1), - ("AF", 1), - ("RES_5", 1), - ("ZF", 1), - ("SF", 1), - ("TF", 1), - ("IF", 1), - ("DF", 1), - ("OF", 1), - ("IOPL_1", 1), - ("IOPL_2", 1), - ("NT", 1), - ("RES_15", 1), - ("RF", 1), - ("VM", 1), - ("AC", 1), - ("VIF", 1), - ("VIP", 1), - ("ID", 1), +#class Eflags(int): +# _flags_ = [("CF", 1), +# ("RES_1", 1), +# ("PF", 1), +# ("RES_3", 1), +# ("AF", 1), +# ("RES_5", 1), +# ("ZF", 1), +# ("SF", 1), +# ("TF", 1), +# ("IF", 1), +# ("DF", 1), +# ("OF", 1), +# ("IOPL_1", 1), +# ("IOPL_2", 1), +# ("NT", 1), +# ("RES_15", 1), +# ("RF", 1), +# ("VM", 1), +# ("AC", 1), +# ("VIF", 1), +# ("VIP", 1), +# ("ID", 1), +# ] +# +# _flag_mask_ = dict([(name, 1 << i) for i, (name, size) in enumerate(_flags_)]) +# +# def __getattr__(self, name): +# if name in self._flag_mask_: +# return bool(self & self._flag_mask_[name]) +# return super(Eflags, self).__getattr_(name) +# +# def dump(self): +# res = [] +# for name in self._flag_mask_: +# if name.startswith("RES_"): +# continue +# if getattr(self, name): +# res.append(name) +# return "|".join(res) +# +# def __repr__(self): +# return "{0}({1})".format(type(self).__name__, self.dump()) +# +# __str__ = __repr__ +# +# def __hex__(self): +# return "{0}({1}:{2})".format(type(self).__name__, int.__hex__(self), self.dump()) + +class EEflags(ctypes.Structure): + _fields_ = [("CF", DWORD, 1), + ("RES_1", DWORD, 1), + ("PF", DWORD, 1), + ("RES_3", DWORD, 1), + ("AF", DWORD, 1), + ("RES_5", DWORD, 1), + ("ZF", DWORD, 1), + ("SF", DWORD, 1), + ("TF", DWORD, 1), + ("IF", DWORD, 1), + ("DF", DWORD, 1), + ("OF", DWORD, 1), + ("IOPL_1", DWORD, 1), + ("IOPL_2", DWORD, 1), + ("NT", DWORD, 1), + ("RES_15", DWORD, 1), + ("RF", DWORD, 1), + ("VM", DWORD, 1), + ("AC", DWORD, 1), + ("VIF", DWORD, 1), + ("VIP", DWORD, 1), + ("ID", DWORD, 1), ] - _flag_mask_ = dict([(name, 1 << i) for i, (name, size) in enumerate(_flags_)]) + def get_raw(self): + x = DWORD.from_address(ctypes.addressof(self)) + return x.value - def __getattr__(self, name): - if name in self._flag_mask_: - return bool(self & self._flag_mask_[name]) - return super(Eflags, self).__getattr_(name) + def set_raw(self, value): + x = DWORD.from_address(ctypes.addressof(self)) + x.value = value + return None def dump(self): res = [] - for name in self._flag_mask_: + for name in [x[0] for x in self._fields_]: if name.startswith("RES_"): continue if getattr(self, name): @@ -105,12 +156,38 @@ class Eflags(int): return "|".join(res) def __repr__(self): - return "{0}({1})".format(type(self).__name__, self.dump()) - - __str__ = __repr__ + return hex(self) def __hex__(self): - return "{0}({1}:{2})".format(type(self).__name__, int.__hex__(self), self.dump()) + if self.raw == 0: + return "{0}({1})".format(type(self).__name__, hex(self.raw)) + return "{0}({1}:{2})".format(type(self).__name__, hex(self.raw), self.dump()) + + raw = property(get_raw, set_raw) + +class EDr7(ctypes.Structure): + _fields_ = [("L0", DWORD, 1), + ("G0", DWORD, 1), + ("L1", DWORD, 1), + ("G1", DWORD, 1), + ("L2", DWORD, 1), + ("G2", DWORD, 1), + ("L3", DWORD, 1), + ("G3", DWORD, 1), + ("LE", DWORD, 1), + ("GE", DWORD, 1), + ("RES_1", DWORD, 3), + ("GD", DWORD, 1), + ("RES_1", DWORD, 2), + ("RW0", DWORD, 2), + ("LEN0", DWORD, 2), + ("RW1", DWORD, 2), + ("LEN1", DWORD, 2), + ("RW2", DWORD, 2), + ("LEN2", DWORD, 2), + ("RW3", DWORD, 2), + ("LEN3", DWORD, 2), + ] class EnhancedCONTEXTBase(): default_dump = () @@ -142,23 +219,36 @@ class EnhancedCONTEXTBase(): pc = property(get_pc, set_pc, None, "Program Counter register (EIP or RIP)") + @property + def EEFlags(self): + off = type(self).EFlags.offset + x = EEflags.from_address(ctypes.addressof(self) + off) + x.self = self + return x -class EnhancedCONTEXT32(EnhancedCONTEXTBase, CONTEXT32): + @property + def EDr7(self): + off = type(self).Dr7.offset + x = EDr7.from_address(ctypes.addressof(self) + off) + x.self = self + return x + +class EnhancedCONTEXT32(EnhancedCONTEXTBase, (CONTEXT32)): default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') pc_reg = 'Eip' - special_reg_type = {'EFlags': Eflags} + #special_reg_type = {'EFlags': Eflags} -class EnhancedCONTEXTWOW64(EnhancedCONTEXTBase, WOW64_CONTEXT): +class EnhancedCONTEXTWOW64(EnhancedCONTEXTBase, (WOW64_CONTEXT)): default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') pc_reg = 'Eip' - special_reg_type = {'EFlags': Eflags} + #special_reg_type = {'EFlags': Eflags} -class EnhancedCONTEXT64(EnhancedCONTEXTBase, CONTEXT64): +class EnhancedCONTEXT64(EnhancedCONTEXTBase, (CONTEXT64)): default_dump = ('Rip', 'Rsp', 'Rax', 'Rbx', 'Rcx', 'Rdx', 'Rbp', 'Rdi', 'Rsi', 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'EFlags') pc_reg = 'Rip' - special_reg_type = {'EFlags': Eflags} + #special_reg_type = {'EFlags': Eflags} @classmethod def new_aligned(cls): diff --git a/windows/winobject.py b/windows/winobject.py index 431bbfc..8f022b5 100644 --- a/windows/winobject.py +++ b/windows/winobject.py @@ -3,6 +3,7 @@ import os import copy import time import struct +import itertools import windows import windows.network @@ -52,7 +53,6 @@ class AutoHandle(object): def __del__(self): if hasattr(self, "_handle") and self._handle: - print("Del HANDLE {0} ({1})".format((self), self._handle)) self.CLOSE_FUNCTION(self._handle) @@ -147,13 +147,13 @@ class WinThread(THREADENTRY32, AutoHandle): if self.owner.bitness == 32 and windows.current_process.bitness == 64: # Wow64 x = windows.vectored_exception.EnhancedCONTEXTWOW64() - x.ContextFlags = CONTEXT_FULL + x.ContextFlags = CONTEXT_ALL winproxy.Wow64GetThreadContext(self.handle, x) return x if self.owner.bitness == 64 and windows.current_process.bitness == 32: x = windows.vectored_exception.EnhancedCONTEXT64.new_aligned() - x.ContextFlags = CONTEXT_FULL + x.ContextFlags = CONTEXT_ALL windows.syswow64.NtGetContextThread_32_to_64(self.handle, x) return x @@ -161,7 +161,7 @@ class WinThread(THREADENTRY32, AutoHandle): x = windows.vectored_exception.EnhancedCONTEXT32() else: x = windows.vectored_exception.EnhancedCONTEXT64.new_aligned() - x.ContextFlags = CONTEXT_FULL + x.ContextFlags = CONTEXT_ALL winproxy.GetThreadContext(self.handle, x) return x @@ -234,7 +234,6 @@ class WinThread(THREADENTRY32, AutoHandle): # Really useful ? thread = [t for t in System().threads if t.tid == tid][0] # set AutoHandle _handle - print("New thread from handle {0}".format(handle)) thread._handle = handle return thread except IndexError: @@ -519,7 +518,6 @@ class WinProcess(PROCESSENTRY32, Process): pid = winproxy.GetProcessId(handle) proc = [p for p in windows.system.processes if p.pid == pid][0] proc._handle = handle - print("New Process from handle {0}".format(handle)) return proc @@ -600,6 +598,27 @@ class WinProcess(PROCESSENTRY32, Process): return self.read_dword(addr) return self.read_qword(addr) + def read_string(self, addr): + res = [] + for i in itertools.count(): + x = self.read_memory(addr + (i * 0x100), 0x100) + if "\x00" in x: + res.append(x.split("\x00", 1)[0]) + break + res.append(x) + return "".join(res) + + def read_wstring(self, addr): + res = [] + for i in itertools.count(): + x = self.read_memory(addr + (i * 0x100), 0x100) + utf16_chars = ["".join(c) for c in zip(*[iter(x)] * 2)] + if "\x00\x00" in utf16_chars: + res.extend(utf16_chars[:utf16_chars.index("\x00\x00")]) + break + res.extend(x) + return "".join(res).decode('utf16') + # Simple cache test # real_read = read_memory #