diff --git a/TODO.txt b/TODO.txt index 96bbb1c..56be531 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,2 +1,8 @@ TODO: - - get thread context (clean code + 32<->64 compat) \ No newline at end of file + - ProcessMemory object ? (metasm like) + +FIXME: + - WMI + - COM initialisation when injected in another process + - The CoInitialize might be already called + - Fix that \ No newline at end of file diff --git a/syswow64.py b/syswow64.py index 1ef430c..2af15e9 100644 --- a/syswow64.py +++ b/syswow64.py @@ -54,8 +54,6 @@ def execute_64bits_code_from_syswow(shellcode): def generate_syswow64_call(target): nb_args = len(target.prototype._argtypes_) target_addr = get_syswow_ntdll_exports()[target.__name__] - print hex(target_addr) - argument_buffer_len = (nb_args * 8) argument_buffer = windows.current_process.allocator.reserve_size(argument_buffer_len) alignement_information = windows.current_process.allocator.reserve_size(8) @@ -76,8 +74,8 @@ def generate_syswow64_call(target): code_64b += x64.Push('R11') code_64b += x64.Push('R12') code_64b += x64.Push('R13') - # Alignment stuff :) + # Alignment stuff :) code_64b += x64.Mov('RCX', 'RSP') code_64b += x64.And('RCX', 0x0f) code_64b += x64.Mov(x64.deref(alignement_information), 'RCX') @@ -167,17 +165,15 @@ def try_generate_stub_target(shellcode, argument_buffer, target): def get_current_process_syswow_peb_addr(): current_process = windows.current_process - dest = current_process.virtual_alloc(0x1000) - get_peb_64_code = codecs.decode(b"65488B042560000000", 'hex') - store_peb = x64.MultipleInstr() - store_peb += x64.Mov(x64.create_displacement(disp=dest), 'RAX') - get_peb_64_code += store_peb.get_code() + dest = current_process.allocator.reserve_size(8) + get_peb_64_code = x64.MultipleInstr() + get_peb_64_code += x64.Mov('RAX', x64.mem('gs:[0x60]')) + get_peb_64_code += x64.Mov(x64.create_displacement(disp=dest), 'RAX') current_process.write_memory(dest, "\x00" * 8) - windows.syswow64.execute_64bits_code_from_syswow(get_peb_64_code) + execute_64bits_code_from_syswow(get_peb_64_code.get_code()) peb_addr = struct.unpack(" EXCEPTION_GUARD_PAGE(0x80000001L) exception_name_by_value = dict([(x, x) for x in [getattr(windows.generated_def.windef, name) for name in exception_type]]) +def generate_enhanced_exception_record(base, name_suffix=""): + class EnhancedEXCEPTION_RECORD(base): + @property + def ExceptionCode(self): + real_code = super(EnhancedEXCEPTION_RECORD, self).ExceptionCode + return exception_name_by_value.get(real_code, 'UNKNOW_EXCEPTION({0})'.format(hex(real_code))) -class EnhancedEXCEPTION_RECORD(EXCEPTION_RECORD): - @property - def ExceptionCode(self): - real_code = super(EnhancedEXCEPTION_RECORD, self).ExceptionCode - return exception_name_by_value.get(real_code, 'UNKNOW_EXCEPTION({0})'.format(hex(real_code))) + @property + def ExceptionAddress(self): + x = super(EnhancedEXCEPTION_RECORD, self).ExceptionAddress + if x is None: + return 0x0 + return x + EnhancedEXCEPTION_RECORD.__name__ += name_suffix + return EnhancedEXCEPTION_RECORD - @property - def ExceptionAddress(self): - x = super(EnhancedEXCEPTION_RECORD, self).ExceptionAddress - if x is None: - return 0x0 - return x +EnhancedEXCEPTION_RECORD = generate_enhanced_exception_record(EXCEPTION_RECORD) +EnhancedEXCEPTION_RECORD32 = generate_enhanced_exception_record(EXCEPTION_RECORD32, "32") +EnhancedEXCEPTION_RECORD64 = generate_enhanced_exception_record(EXCEPTION_RECORD64, "64") + + +#class EnhancedEXCEPTION_RECORD(EXCEPTION_RECORD): +# @property +# def ExceptionCode(self): +# real_code = super(EnhancedEXCEPTION_RECORD, self).ExceptionCode +# return exception_name_by_value.get(real_code, 'UNKNOW_EXCEPTION({0})'.format(hex(real_code))) +# +# @property +# def ExceptionAddress(self): +# x = super(EnhancedEXCEPTION_RECORD, self).ExceptionAddress +# if x is None: +# return 0x0 +# return x class Eflags(int): @@ -101,7 +121,7 @@ class Eflags(int): return "{0}({1}:{2})".format(type(self).__name__, int.__hex__(self), self.dump()) -class EnhancedCONTEXTBase(CONTEXT): +class EnhancedCONTEXTBase(): default_dump = () pc_reg = '' special_reg_type = {} @@ -132,19 +152,48 @@ class EnhancedCONTEXTBase(CONTEXT): pc = property(get_pc, set_pc, None, "Program Counter register (EIP or RIP)") -class EnhancedCONTEXT32(EnhancedCONTEXTBase): +class EnhancedCONTEXT32(EnhancedCONTEXTBase, CONTEXT32): + default_dump = ('Eip', 'Esp', 'Eax', 'Ebx', 'Ecx', 'Edx', 'Ebp', 'Edi', 'Esi', 'EFlags') + pc_reg = 'Eip' + special_reg_type = {'EFlags': Eflags} + +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} -class EnhancedCONTEXT64(EnhancedCONTEXTBase): +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} -if windows.current_process.bitness == 32: + @classmethod + def new_aligned(cls): + """Return a new EnhancedCONTEXT64 aligned on 16 bits + temporary workaround or horrible hack ? choose your side + """ + size = ctypes.sizeof(cls) + nb_qword = (size + 8) / ctypes.sizeof(ULONGLONG) + buffer = (nb_qword * ULONGLONG)() + struct_address = ctypes.addressof(buffer) + if (struct_address & 0xf) not in [0, 8]: + raise ValueError("ULONGLONG array not aligned on 8") + if (struct_address & 0xf) == 8: + struct_address += 8 + self = cls.from_address(struct_address) + # Keep the raw buffer alive + self._buffer = buffer + return self + +def bitness(): + """Return 32 or 64""" + import platform + bits = platform.architecture()[0] + return int(bits[:2]) + +if bitness() == 32: EnhancedCONTEXT = EnhancedCONTEXT32 else: EnhancedCONTEXT = EnhancedCONTEXT64 @@ -192,3 +241,17 @@ class WithExceptionHandler(object): def __exit__(self, exc_type, exc_value, traceback): windows.winproxy.RemoveVectoredExceptionHandler(self.value) return False + +class DumpContextOnException(WithExceptionHandler): + def __init__(self, exit=False): + self.exit = exit + super(DumpContextOnException, self).__init__(self.print_context_result) + + def print_context_result(self, exception_pointers): + except_record = exception_pointers[0].ExceptionRecord[0] + exception_pointers[0].dump() + sys.stdout.flush() + if self.exit: + windows.current_process.exit() + return 0 + diff --git a/winobject.py b/winobject.py index de0b858..610352f 100644 --- a/winobject.py +++ b/winobject.py @@ -139,7 +139,23 @@ class WinThread(THREADENTRY32, AutoHandle): @property def context(self): - x = windows.vectored_exception.EnhancedCONTEXT() + if self.owner.bitness == 32 and windows.current_process.bitness == 64: + # Wow64 + x = windows.vectored_exception.EnhancedCONTEXTWOW64() + x.ContextFlags = CONTEXT_FULL + 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 + windows.syswow64.NtGetContextThread_32_to_64(self.handle, x) + return x + + if self.owner.bitness == 32: + x = windows.vectored_exception.EnhancedCONTEXT32() + else: + x = windows.vectored_exception.EnhancedCONTEXT64.new_aligned() x.ContextFlags = CONTEXT_FULL winproxy.GetThreadContext(self.handle, x) return x @@ -147,6 +163,20 @@ class WinThread(THREADENTRY32, AutoHandle): def set_context(self, context): return winproxy.SetThreadContext(self.handle, context) + @property + def start_address(self): + if windows.current_process.bitness == 32 and self.owner.bitness == 64: + res = ULONGLONG() + windows.syswow64.NtQueryInformationThread_32_to_64(self.handle, ThreadQuerySetWin32StartAddress, byref(res), ctypes.sizeof(res)) + return res.value + res_size = max(self.owner.bitness, windows.current_process.bitness) + if res_size == 32: + res = ULONG() + else: + res = ULONGLONG() + winproxy.NtQueryInformationThread(self.handle, ThreadQuerySetWin32StartAddress, byref(res), ctypes.sizeof(res)) + return res.value + def exit(self, code=0): return winproxy.TerminateThread(self.handle, code) @@ -536,9 +566,15 @@ class WinProcess(PROCESSENTRY32, Process): windows.syswow64.NtQueryInformationProcess_32_to_64(self.handle, ProcessInformation=data, ProcessInformationLength=ctypes.sizeof(x)) peb_offset = x.PebBaseAddress.offset peb_addr = struct.unpack("