From ea78f81468f0ee4c52d21667ccbbd2deb5d55319 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Fri, 13 Nov 2015 09:25:05 +0100 Subject: [PATCH] Add 64->32 bits pe/peb parsing + stuff in simple_x86/64 --- generated_def/winstructs.py | 82 +++++++++++++- injection.py | 5 - native_exec/simple_x86.py | 28 ++++- native_exec/test_simple_x86.py | 8 ++ pe_parse.py | 49 +++++---- remotectypes.py | 188 +++++++++++++++++++++++++++------ test/mytest.py | 8 +- utils/winutils.py | 5 + winobject.py | 48 ++++++++- 9 files changed, 351 insertions(+), 70 deletions(-) diff --git a/generated_def/winstructs.py b/generated_def/winstructs.py index 50785bf..0aadaaf 100644 --- a/generated_def/winstructs.py +++ b/generated_def/winstructs.py @@ -32,9 +32,9 @@ REGSAM = ACCESS_MASK LPCONTEXT = PVOID VOID = DWORD -structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_IMAGE_IMPORT_BY_NAME', '_IMAGE_EXPORT_DIRECTORY', '_MEMORY_BASIC_INFORMATION', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT32', '_M128A', '_CONTEXT64', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_TOKEN_ELEVATION', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW', '_OVERLAPPED', '_MIB_TCPROW_OWNER_PID', '_MIB_TCPTABLE_OWNER_PID', '_MIB_UDPROW_OWNER_PID', '_MIB_UDPTABLE_OWNER_PID', '_MIB_UDP6ROW_OWNER_PID', '_MIB_UDP6TABLE_OWNER_PID', '_MIB_TCP6ROW_OWNER_PID', '_MIB_TCP6TABLE_OWNER_PID', '_MIB_TCPROW', '_EXCEPTION_RECORD', '_EXCEPTION_POINTERS64', '_EXCEPTION_POINTERS32', '_DEBUG_PROCESSOR_IDENTIFICATION_ALPHA', '_DEBUG_PROCESSOR_IDENTIFICATION_AMD64', '_DEBUG_PROCESSOR_IDENTIFICATION_IA64', '_DEBUG_PROCESSOR_IDENTIFICATION_X86', '_DEBUG_PROCESSOR_IDENTIFICATION_ARM', '_DEBUG_PROCESSOR_IDENTIFICATION_ALL', '_SYMBOL_INFO', '_MODLOAD_DATA', '_SYSTEM_MODULE32', '_SYSTEM_MODULE64', '_SYSTEM_MODULE_INFORMATION32', '_SYSTEM_MODULE_INFORMATION64'] +structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_IMAGE_IMPORT_BY_NAME', '_IMAGE_EXPORT_DIRECTORY', '_MEMORY_BASIC_INFORMATION', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT32', '_M128A', '_CONTEXT64', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_TOKEN_ELEVATION', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW', '_OVERLAPPED', '_MIB_TCPROW_OWNER_PID', '_MIB_TCPTABLE_OWNER_PID', '_MIB_UDPROW_OWNER_PID', '_MIB_UDPTABLE_OWNER_PID', '_MIB_UDP6ROW_OWNER_PID', '_MIB_UDP6TABLE_OWNER_PID', '_MIB_TCP6ROW_OWNER_PID', '_MIB_TCP6TABLE_OWNER_PID', '_MIB_TCPROW', '_EXCEPTION_RECORD', '_EXCEPTION_POINTERS64', '_EXCEPTION_POINTERS32', '_DEBUG_PROCESSOR_IDENTIFICATION_ALPHA', '_DEBUG_PROCESSOR_IDENTIFICATION_AMD64', '_DEBUG_PROCESSOR_IDENTIFICATION_IA64', '_DEBUG_PROCESSOR_IDENTIFICATION_X86', '_DEBUG_PROCESSOR_IDENTIFICATION_ARM', '_DEBUG_PROCESSOR_IDENTIFICATION_ALL', '_SYMBOL_INFO', '_MODLOAD_DATA', '_SYSTEM_MODULE32', '_SYSTEM_MODULE64', '_SYSTEM_MODULE_INFORMATION32', '_SYSTEM_MODULE_INFORMATION64', 'tagSAFEARRAYBOUND', 'tagSAFEARRAY'] -enums = ['_SYSTEM_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE', '_TOKEN_INFORMATION_CLASS', '_IMAGEHLP_SYMBOL_TYPE_INFO'] +enums = ['_SYSTEM_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_VARENUM', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE', '_TOKEN_INFORMATION_CLASS', '_IMAGEHLP_SYMBOL_TYPE_INFO'] # Enum _SYSTEM_INFORMATION_CLASS definitions _SYSTEM_INFORMATION_CLASS = DWORD @@ -138,6 +138,63 @@ TCP_TABLE_OWNER_MODULE_LISTENER = 0x6 TCP_TABLE_OWNER_MODULE_CONNECTIONS = 0x7 TCP_TABLE_OWNER_MODULE_ALL = 0x8 +# Enum _VARENUM definitions +_VARENUM = DWORD +VARENUM = _VARENUM + +VT_EMPTY = 0x0 +VT_NULL = 0x1 +VT_I2 = 0x2 +VT_I4 = 0x3 +VT_R4 = 0x4 +VT_R8 = 0x5 +VT_CY = 0x6 +VT_DATE = 0x7 +VT_BSTR = 0x8 +VT_DISPATCH = 0x9 +VT_ERROR = 0xa +VT_BOOL = 0xb +VT_VARIANT = 0xc +VT_UNKNOWN = 0xd +VT_DECIMAL = 0xe +VT_I1 = 0x10 +VT_UI1 = 0x11 +VT_UI2 = 0x12 +VT_UI4 = 0x13 +VT_I8 = 0x14 +VT_UI8 = 0x15 +VT_INT = 0x16 +VT_UINT = 0x17 +VT_VOID = 0x18 +VT_HRESULT = 0x19 +VT_PTR = 0x1a +VT_SAFEARRAY = 0x1b +VT_CARRAY = 0x1c +VT_USERDEFINED = 0x1d +VT_LPSTR = 0x1e +VT_LPWSTR = 0x1f +VT_RECORD = 0x24 +VT_INT_PTR = 0x25 +VT_UINT_PTR = 0x26 +VT_FILETIME = 0x40 +VT_BLOB = 0x41 +VT_STREAM = 0x42 +VT_STORAGE = 0x43 +VT_STREAMED_OBJECT = 0x44 +VT_STORED_OBJECT = 0x45 +VT_BLOB_OBJECT = 0x46 +VT_CF = 0x47 +VT_CLSID = 0x48 +VT_VERSIONED_STREAM = 0x49 +VT_BSTR_BLOB = 0xfff +VT_VECTOR = 0x1000 +VT_ARRAY = 0x2000 +VT_BYREF = 0x4000 +VT_RESERVED = 0x8000 +VT_ILLEGAL = 0xffff +VT_ILLEGALMASKED = 0xfff +VT_TYPEMASK = 0xfff + # Enum _UDP_TABLE_CLASS definitions _UDP_TABLE_CLASS = DWORD UDP_TABLE_CLASS = _UDP_TABLE_CLASS @@ -1196,3 +1253,24 @@ class _SYSTEM_MODULE_INFORMATION64(Structure): PSYSTEM_MODULE_INFORMATION64 = POINTER(_SYSTEM_MODULE_INFORMATION64) SYSTEM_MODULE_INFORMATION64 = _SYSTEM_MODULE_INFORMATION64 +# Struct tagSAFEARRAYBOUND definitions +class tagSAFEARRAYBOUND(Structure): + _fields_ = [ + ("cElements", ULONG), + ("lLbound", LONG), + ] +SAFEARRAYBOUND = tagSAFEARRAYBOUND +LPSAFEARRAYBOUND = POINTER(tagSAFEARRAYBOUND) + +# Struct tagSAFEARRAY definitions +class tagSAFEARRAY(Structure): + _fields_ = [ + ("cDims", USHORT), + ("fFeatures", USHORT), + ("cbElements", ULONG), + ("cLocks", ULONG), + ("pvData", PVOID), + ("rgsabound", SAFEARRAYBOUND * 1), + ] +SAFEARRAY = tagSAFEARRAY + diff --git a/injection.py b/injection.py index 3140aac..d2f2ff0 100644 --- a/injection.py +++ b/injection.py @@ -128,10 +128,5 @@ def inject_python_command(process, code_injected, PYDLL="python27.dll\x00"): def execute_python_code(process, code): - print("me = {0}".format(windows.current_process.bitness)) - print("him = {0}".format(process.bitness)) - if windows.current_process.bitness != process.bitness: - if windows.current_process.bitness == 64 and process.bitness == 32: - raise NotImplementedError("Cannot perform 64 -> 32 injection") shellcode_remote_addr = inject_python_command(process, code) return process.create_thread(shellcode_remote_addr, 0) diff --git a/native_exec/simple_x86.py b/native_exec/simple_x86.py index 68ec2b8..99480a9 100644 --- a/native_exec/simple_x86.py +++ b/native_exec/simple_x86.py @@ -473,8 +473,30 @@ class Slash(object): return arg_consum, value return arg_consum - 1, value -instr_state = collections.namedtuple('instr_state', ['previous', 'prefixes']) +class ControlRegisterModRM(object): + def __init__(self, writecr = False): + self.writecr = writecr + def accept_arg(self, args, instr_state): + writecr = self.writecr + if len(args) < 2: + return None, None + reg = args[writecr] + cr = args[not writecr] + if not cr.lower().startswith("cr"): + return None, None + try: + cr_number = int(cr[2:], 10) + except ValueError as e: + raise ValueError("Invalid ControlRegister {0}".format(cr)) + if cr_number > 7: + raise ValueError("Invalid ControlRegister {0}".format(cr)) + + modrm_params = [reg, x86_regs[cr_number]] + args[2:] + return ModRM([ModRM_REG__REG], has_direction_bit=False).accept_arg(modrm_params, instr_state) + + +instr_state = collections.namedtuple('instr_state', ['previous', 'prefixes']) class Instruction(object): """Base class of instructions, use `encoding` to find a valid way to assemble the instruction""" @@ -610,7 +632,9 @@ class Sub(Instruction): class Mov(Instruction): encoding = [(RawBits.from_int(8, 0x89), ModRM([ModRM_REG__REG, ModRM_REG__MEM])), - (RawBits.from_int(5, 0xb8 >> 3), X86RegisterSelector(), Imm32())] + (RawBits.from_int(5, 0xb8 >> 3), X86RegisterSelector(), Imm32()), + (RawBits.from_int(16, 0x0f20), ControlRegisterModRM(writecr=False)), + (RawBits.from_int(16, 0x0f22), ControlRegisterModRM(writecr=True))] class Movsb(Instruction): diff --git a/native_exec/test_simple_x86.py b/native_exec/test_simple_x86.py index 101ab37..f80ddcc 100644 --- a/native_exec/test_simple_x86.py +++ b/native_exec/test_simple_x86.py @@ -80,6 +80,14 @@ class TestInstr(object): raise AssertionError("Expected mem.disp {0} got {1}".format(memaccess.disp, cap_mem.disp)) +TestInstr(Mov)('EAX', 'CR3') +TestInstr(Mov)('EDX', 'CR0') +TestInstr(Mov)('EDI', 'CR7') + +TestInstr(Mov)('CR3', 'EAX') +TestInstr(Mov)('CR0', 'EDX') +TestInstr(Mov)('CR7', 'EDI') + TestInstr(Mov)('EAX', 'ESP') TestInstr(Mov)('ECX', mem('[EAX]')) TestInstr(Mov)('EDX', mem('[ECX + 0x10]')) diff --git a/pe_parse.py b/pe_parse.py index ba47580..baa0eff 100644 --- a/pe_parse.py +++ b/pe_parse.py @@ -26,30 +26,37 @@ def transform_ctypes_fields(struct, replacement): return [(name, replacement.get(name, type)) for name, type in struct._fields_] +def get_structure_transformer_for_target(target): + current_bitness = windows.current_process.bitness + if target is None: + ctypes_structure_transformer = lambda x:x + create_structure_at = lambda structcls, addr: structcls.from_address(addr) + return ctypes_structure_transformer, create_structure_at + + if target.bitness == 32 and current_bitness == 64: + ctypes_structure_transformer = rctypes.transform_type_to_remote32bits + elif target.bitness == 64 and current_bitness == 32: + ctypes_structure_transformer = rctypes.transform_type_to_remote64bits + elif target.bitness == current_bitness: + ctypes_structure_transformer = rctypes.transform_type_to_remote + else: + raise NotImplementedError("Parsing {0} PE from {1} Process".format(targetedbitness, proc_bitness)) + + def create_structure_at(structcls, addr): + return ctypes_structure_transformer(structcls)(addr, target) + return ctypes_structure_transformer, create_structure_at + + def PEFile(baseaddr, target=None): - # TODO: 32 with target 32 - # 64 with target 64 - # For now you can do it by injecting a remote python.. proc_bitness = windows.current_process.bitness if target is None: targetedbitness = proc_bitness else: targetedbitness = target.bitness - if targetedbitness == 32 and proc_bitness == 64: - raise NotImplementedError("Parse 32bits PE with 64bits current_process") - elif targetedbitness == 64 and proc_bitness == 32: - ctypes_structure_transformer = rctypes.transform_type_to_remote64bits + transformers = get_structure_transformer_for_target(target) + ctypes_structure_transformer, create_structure_at = transformers - def create_structure_at(structcls, addr): - return rctypes.transform_type_to_remote64bits(structcls)(addr, target) - elif targetedbitness == proc_bitness: # Does not handle remote of same bitness.. - ctypes_structure_transformer = lambda x: x - - def create_structure_at(structcls, addr): - return structcls.from_address(addr) - else: - raise NotImplementedError("Parsing {0} PE from {1} Process".format(targetedbitness, proc_bitness)) if targetedbitness == 32: IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32 @@ -65,14 +72,14 @@ def PEFile(baseaddr, target=None): return "".format(self.value, hex(self.addr)) class StringRVa(RVA): - if proc_bitness == 32 and targetedbitness == 64: - @property - def str(self): - return rctypes.Remote_c_char_p64(self.addr, target=target).value - else: + if target is None: @property def str(self): return ctypes.c_char_p(self.addr).value.decode() + else: + @property + def str(self): + return create_structure_at(ctypes.c_char_p, self.addr).value.decode() def __repr__(self): return "".format(self.value, self.str) diff --git a/remotectypes.py b/remotectypes.py index 17c0193..d79fe89 100644 --- a/remotectypes.py +++ b/remotectypes.py @@ -1,3 +1,6 @@ +"""remote ctypes, a try to a ctypes wrapper that accept a target object for every ready operation +Some code is copy-paste, might be userful to rewrite some part later""" + import _ctypes import ctypes import ctypes.wintypes @@ -49,6 +52,20 @@ class c_char_p64(_SimpleCData): class c_wchar_p64(_SimpleCData): _type_ = "Q" + +# # 32bits pointer types # # +class c_void_p32(_SimpleCData): + _type_ = "I" + + +class c_char_p32(_SimpleCData): + _type_ = "I" + + +class c_wchar_p32(_SimpleCData): + _type_ = "I" + + # standard type translation # don't know how to handle size_t since it's non-distinguable from c_ulong # maybe force import before ctypes and modif stuff into ctypes ? @@ -142,6 +159,7 @@ def create_remote_array(subtype, len): # 64bits pointers + class RemotePtr64(RemoteValue): def __init__(self, value, target): self.target = target @@ -198,6 +216,64 @@ type_32_64_translation_table = { } +# 32bits pointers + +class RemotePtr32(RemoteValue): + def __init__(self, value, target): + self.target = target + super(RemotePtr32, self).__init__(value) + + @property + def raw_value(self): + # Bypass our own 'value' implementation + # Even if we are a subclass of c_ulonglong + my_addr = ctypes.addressof(self) + return ctypes.c_ulong.from_address(my_addr).value + + +class Remote_c_void_p32(RemotePtr32, c_void_p32): + pass + + +# base explanation: +# RemotePtr64 for the good `raw_value` implem +# RemoteCCharP for the good `value` implem +# c_char_p64 for the good _type_ (ctypes size) +class Remote_c_char_p32(c_char_p32, RemotePtr32, RemoteCCharP): + def __repr__(self): + return "".format(self.raw_value) + + +class Remote_w_char_p32(c_wchar_p32, RemotePtr32, RemoteWCharP): + def __repr__(self): + return "".format(self.raw_value) + + +class RemoteStructurePointer32(Remote_c_void_p32): + @property + def raw_value(self): + return self.value + + @classmethod + def from_buffer_with_target_and_ptr_type(cls, buffer, offset=0, target=None, ptr_type=None): + x = cls.from_buffer(buffer) + x.target = target + x.real_pointer_type = ptr_type + return x + + @property + def contents(self): + remote_pointed_type = transform_type_to_remote32bits(self.real_pointer_type._sub_ctypes_) + return remote_pointed_type(self.raw_value, self.target) + + +type_64_32_translation_table = { + ctypes.c_void_p: Remote_c_void_p32, + ctypes.c_char_p: Remote_c_char_p32, + ctypes.c_wchar_p: Remote_w_char_p32, +} + + class RemoteStructureUnion(object): """Target is a process object""" _reserved_name = ["_target", "_fields_", "_fields_dict_", "_base_addr", "_get_field_by_name", @@ -209,7 +285,10 @@ class RemoteStructureUnion(object): ctypes.c_wchar_p: RemoteWCharP, Remote_c_void_p64: Remote_c_void_p64, Remote_c_char_p64: Remote_c_char_p64, - Remote_w_char_p64: Remote_w_char_p64 + Remote_w_char_p64: Remote_w_char_p64, + Remote_c_void_p32: Remote_c_void_p32, + Remote_c_char_p32: Remote_c_char_p32, + Remote_w_char_p32: Remote_w_char_p32 } def __init__(self, base_addr, target): @@ -234,6 +313,8 @@ class RemoteStructureUnion(object): return RemoteStructurePointer.from_buffer_with_target_and_ptr_type(bytearray(s), target=self._target, ptr_type=ftype) if issubclass(ftype, RemotePtr64): # Pointer to remote64 bits process return RemoteStructurePointer64.from_buffer_with_target_and_ptr_type(bytearray(s), target=self._target, ptr_type=ftype) + if issubclass(ftype, RemotePtr32): # Pointer to remote32 bits process + return RemoteStructurePointer32.from_buffer_with_target_and_ptr_type(bytearray(s), target=self._target, ptr_type=ftype) if issubclass(ftype, RemoteStructureUnion): # Structure|Union already transfomed in remote return ftype(self._base_addr + fosset, self._target) if issubclass(ftype, ctypes.Structure): # Structure that must be transfomed @@ -290,37 +371,76 @@ class RemoteUnion(RemoteStructureUnion, ctypes.Union): remote_struct = RemoteStructure.from_structure +# ctypes 32 -> 64 methods +def MakePtr64(type): + class PointerToStruct64(Remote_c_void_p64): + _sub_ctypes_ = (type) + return PointerToStruct64 + +def transform_structure_to_remote64bits(structcls): + """Create a remote structure for a 64bits target process""" + new_fields = [] + for fname, ftype in structcls._fields_: + ftype = transform_type_to_remote64bits(ftype) + new_fields.append((fname, ftype)) + return RemoteStructure.from_fields(new_fields, base_cls=structcls) + +def transform_union_to_remote64bits(structcls): + """Create a remote union for a 64bits target process""" + new_fields = [] + for fname, ftype in structcls._fields_: + ftype = transform_type_to_remote64bits(ftype) + new_fields.append((fname, ftype)) + return RemoteUnion.from_fields(new_fields, base_cls=structcls) + +def transform_type_to_remote64bits(ftype): + if is_pointer_type(ftype): + return MakePtr64(ftype._type_) + if is_array_type(ftype): + return create_remote_array(transform_type_to_remote64bits(ftype._type_), ftype._length_) + if is_structure_type(ftype): + return transform_structure_to_remote64bits(ftype) + if is_union_type(ftype): + return transform_union_to_remote64bits(ftype) + # Normal types + return type_32_64_translation_table.get(ftype, ftype) + + +# ctypes 64 -> 32 methods +def MakePtr32(type): + class PointerToStruct32(Remote_c_void_p32): + _sub_ctypes_ = (type) + return PointerToStruct32 + +def transform_structure_to_remote32bits(structcls): + """Create a remote structure for a 32bits target process""" + new_fields = [] + for fname, ftype in structcls._fields_: + ftype = transform_type_to_remote32bits(ftype) + new_fields.append((fname, ftype)) + return RemoteStructure.from_fields(new_fields, base_cls=structcls) + +def transform_union_to_remote32bits(structcls): + """Create a remote union for a 32bits target process""" + new_fields = [] + for fname, ftype in structcls._fields_: + ftype = transform_type_to_remote32bits(ftype) + new_fields.append((fname, ftype)) + return RemoteUnion.from_fields(new_fields, base_cls=structcls) + +def transform_type_to_remote32bits(ftype): + if is_pointer_type(ftype): + return MakePtr32(ftype._type_) + if is_array_type(ftype): + return create_remote_array(transform_type_to_remote32bits(ftype._type_), ftype._length_) + if is_structure_type(ftype): + return transform_structure_to_remote32bits(ftype) + if is_union_type(ftype): + return transform_union_to_remote32bits(ftype) + # Normal types + return type_64_32_translation_table.get(ftype, ftype) + if ctypes.sizeof(ctypes.c_void_p) == 4: - # ctypes 32 -> 64 methods - def MakePtr(type): - class PointerToStruct64(Remote_c_void_p64): - _sub_ctypes_ = (type) - return PointerToStruct64 - - def transform_structure_to_remote64bits(structcls): - """Create a remote structure for a 64bits target process""" - new_fields = [] - for fname, ftype in structcls._fields_: - ftype = transform_type_to_remote64bits(ftype) - new_fields.append((fname, ftype)) - return RemoteStructure.from_fields(new_fields, base_cls=structcls) - - def transform_union_to_remote64bits(structcls): - """Create a remote structure for a 64bits target process""" - new_fields = [] - for fname, ftype in structcls._fields_: - ftype = transform_type_to_remote64bits(ftype) - new_fields.append((fname, ftype)) - return RemoteUnion.from_fields(new_fields, base_cls=structcls) - - def transform_type_to_remote64bits(ftype): - if is_pointer_type(ftype): - return MakePtr(ftype._type_) - if is_array_type(ftype): - return create_remote_array(transform_type_to_remote64bits(ftype._type_), ftype._length_) - if is_structure_type(ftype): - return transform_structure_to_remote64bits(ftype) - if is_union_type(ftype): - return transform_union_to_remote64bits(ftype) - # Normal types - return type_32_64_translation_table.get(ftype, ftype) + transform_type_to_remote = transform_type_to_remote32bits +if ctypes.sizeof(ctypes.c_void_p) == 8: + transform_type_to_remote = transform_type_to_remote64bits diff --git a/test/mytest.py b/test/mytest.py index 08e0b12..58f91c1 100644 --- a/test/mytest.py +++ b/test/mytest.py @@ -157,8 +157,8 @@ class WindowsTestCase(unittest.TestCase): k32 = mods[0] get_current_proc_id = k32.pe.exports['GetCurrentProcessId'] # TODO: check get_current_proc_id value (but we cannot do 64->32 injection for now) - if is_process_64_bits: - raise NotImplementedError("Python execution 64->32") + #if is_process_64_bits: + # raise NotImplementedError("Python execution 64->32") data = calc.virtual_alloc(0x1000) remote_python_code = """ import ctypes @@ -232,4 +232,6 @@ class WindowsTestCase(unittest.TestCase): if __name__ == '__main__': alltests = unittest.TestSuite() alltests.addTest(unittest.makeSuite(WindowsTestCase)) - unittest.TextTestRunner(verbosity=2).run(alltests) + alltests.debug() + tester = unittest.TextTestRunner(verbosity=2) + tester.run(alltests) diff --git a/utils/winutils.py b/utils/winutils.py index e9f31e9..fad4189 100644 --- a/utils/winutils.py +++ b/utils/winutils.py @@ -30,6 +30,7 @@ def get_remote_func_addr(target, dll_name, func_name): def is_wow_64(hProcess): + import ipdb;ipdb.set_trace() try: fnIsWow64Process = get_func_addr("kernel32.dll", "IsWow64Process") except winproxy.Kernel32Error: @@ -190,10 +191,14 @@ class VirtualProtected(object): class DisableWow64FsRedirection(object): """A context manager that disable the Wow64 Fs Redirection""" def __enter__(self): + if windows.current_process.bitness == 64: + return self self.OldValue = PVOID() winproxy.Wow64DisableWow64FsRedirection(ctypes.byref(self.OldValue)) return self def __exit__(self, exc_type, exc_value, traceback): + if windows.current_process.bitness == 64: + return False winproxy.Wow64RevertWow64FsRedirection(self.OldValue) return False diff --git a/winobject.py b/winobject.py index 1e12147..13c5c9c 100644 --- a/winobject.py +++ b/winobject.py @@ -158,7 +158,6 @@ class WinThread(THREADENTRY32, AutoHandle): @staticmethod def _from_handle(handle): tid = winproxy.GetThreadId(handle) - print(tid) try: return [t for t in System().threads if t.tid == tid][0] except IndexError: @@ -462,6 +461,8 @@ class WinProcess(PROCESSENTRY32, Process): def peb(self): if windows.current_process.bitness == 32 and self.bitness == 64: return RemotePEB64(self.get_peb_addr(), self) + if windows.current_process.bitness == 64 and self.bitness == 32: + return RemotePEB32(self.get_peb_addr(), self) return RemotePEB(self.get_peb_addr(), self) def exit(self, code=0): @@ -569,12 +570,20 @@ class PEB(Structure): import windows.remotectypes as rctypes +class RemoteLoadedModule(rctypes.RemoteStructure.from_structure(LoadedModule)): + @property + def pe(self): + """A PE representation of the module + + :type: :class:`windows.pe_parse.PEFile` + """ + return pe_parse.PEFile(self.baseaddr, target=self._target) + class RemotePEB(rctypes.RemoteStructure.from_structure(PEB)): - RemoteLoadedModule = rctypes.RemoteStructure.from_structure(LoadedModule) def ptr_flink_to_remote_module(self, ptr_value): - return self.RemoteLoadedModule(ptr_value - ctypes.sizeof(ctypes.c_void_p) * 2, self._target) + return RemoteLoadedModule(ptr_value - ctypes.sizeof(ctypes.c_void_p) * 2, self._target) @property def modules(self): @@ -623,3 +632,36 @@ if CurrentProcess().bitness == 32: list_entry_ptr = current_dll.InMemoryOrderLinks.Flink.raw_value current_dll = self.ptr_flink_to_remote_module(list_entry_ptr) return res + +if CurrentProcess().bitness == 64: + + class RemoteLoadedModule32(rctypes.transform_type_to_remote32bits(LoadedModule)): + @property + def pe(self): + """A PE representation of the module + + :type: :class:`windows.pe_parse.PEFile` + """ + return pe_parse.PEFile(self.baseaddr, target=self._target) + + class RemotePEB32(rctypes.transform_type_to_remote32bits(PEB)): + + def ptr_flink_to_remote_module(self, ptr_value): + return RemoteLoadedModule32(ptr_value - ctypes.sizeof(rctypes.c_void_p32) * 2, self._target) + + @property + def modules(self): + """The loaded modules present in the PEB + + :type: [:class:`LoadedModule`] -- List of loaded modules + """ + res = [] + #import pdb;pdb.set_trace() + list_entry_ptr = self.Ldr.contents.InMemoryOrderModuleList.Flink.raw_value + + current_dll = self.ptr_flink_to_remote_module(list_entry_ptr) + while current_dll.DllBase: + res.append(current_dll) + list_entry_ptr = current_dll.InMemoryOrderLinks.Flink.raw_value + current_dll = self.ptr_flink_to_remote_module(list_entry_ptr) + return res