From 7ddcb492ed79114bedca535083e2d8a423892a38 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Thu, 3 Sep 2015 12:57:15 +0200 Subject: [PATCH] Add new def + pe_parse with remotectypes test --- generated_def/winfuncs.py | 25 +++++++- generated_def/winstructs.py | 76 +++++++++++++++++++++++- pe_parse.py | 115 +++++++++++++++++++++++++++--------- 3 files changed, 186 insertions(+), 30 deletions(-) diff --git a/generated_def/winfuncs.py b/generated_def/winfuncs.py index 6b0bb3b..23aaf0a 100644 --- a/generated_def/winfuncs.py +++ b/generated_def/winfuncs.py @@ -3,7 +3,7 @@ from ctypes import * from ctypes.wintypes import * from .winstructs import * -functions = ['ExitProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtQuerySystemInformation', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualProtect', 'VirtualQuery', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateThread', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'SetThreadContext', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion', 'GetCurrentThread', 'GetCurrentThreadId', 'GetCurrentProcessorNumber', 'AllocConsole', 'GetStdHandle', 'SetStdHandle', 'SetThreadAffinityMask', 'WriteFile', 'GetExtendedTcpTable', 'GetExtendedUdpTable', 'SetTcpEntry', 'AddVectoredContinueHandler', 'AddVectoredExceptionHandler', 'TerminateThread', 'ExitThread', 'RemoveVectoredExceptionHandler', 'ResumeThread', 'SuspendThread', 'WaitForSingleObject', 'GetThreadId', 'LoadLibraryExA', 'LoadLibraryExW'] +functions = ['ExitProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtQuerySystemInformation', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualProtect', 'VirtualQuery', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateThread', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'SetThreadContext', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion', 'GetCurrentThread', 'GetCurrentThreadId', 'GetCurrentProcessorNumber', 'AllocConsole', 'GetStdHandle', 'SetStdHandle', 'SetThreadAffinityMask', 'WriteFile', 'GetExtendedTcpTable', 'GetExtendedUdpTable', 'SetTcpEntry', 'AddVectoredContinueHandler', 'AddVectoredExceptionHandler', 'TerminateThread', 'ExitThread', 'RemoveVectoredExceptionHandler', 'ResumeThread', 'SuspendThread', 'WaitForSingleObject', 'GetThreadId', 'LoadLibraryExA', 'LoadLibraryExW', 'SymInitialize', 'SymFromName', 'SymLoadModuleEx', 'SymSetOptions', 'SymGetTypeInfo', 'DeviceIoControl'] # ExitProcess(uExitCode): ExitProcessPrototype = WINFUNCTYPE(VOID, UINT) @@ -277,3 +277,26 @@ LoadLibraryExAParams = ((1, 'lpFileName'), (1, 'hFile'), (1, 'dwFlags')) LoadLibraryExWPrototype = WINFUNCTYPE(HMODULE, LPCWSTR, HANDLE, DWORD) LoadLibraryExWParams = ((1, 'lpFileName'), (1, 'hFile'), (1, 'dwFlags')) +# SymInitialize(hProcess, UserSearchPath, fInvadeProcess): +SymInitializePrototype = WINFUNCTYPE(BOOL, HANDLE, LPCSTR, BOOL) +SymInitializeParams = ((1, 'hProcess'), (1, 'UserSearchPath'), (1, 'fInvadeProcess')) + +# SymFromName(hProcess, Name, Symbol): +SymFromNamePrototype = WINFUNCTYPE(BOOL, HANDLE, LPCSTR, PSYMBOL_INFO) +SymFromNameParams = ((1, 'hProcess'), (1, 'Name'), (1, 'Symbol')) + +# SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, Data, Flags): +SymLoadModuleExPrototype = WINFUNCTYPE(DWORD64, HANDLE, HANDLE, LPCSTR, LPCSTR, DWORD64, DWORD, PMODLOAD_DATA, DWORD) +SymLoadModuleExParams = ((1, 'hProcess'), (1, 'hFile'), (1, 'ImageName'), (1, 'ModuleName'), (1, 'BaseOfDll'), (1, 'DllSize'), (1, 'Data'), (1, 'Flags')) + +# SymSetOptions(SymOptions): +SymSetOptionsPrototype = WINFUNCTYPE(DWORD, DWORD) +SymSetOptionsParams = ((1, 'SymOptions'),) + +# SymGetTypeInfo(hProcess, ModBase, TypeId, GetType, pInfo): +SymGetTypeInfoPrototype = WINFUNCTYPE(BOOL, HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID) +SymGetTypeInfoParams = ((1, 'hProcess'), (1, 'ModBase'), (1, 'TypeId'), (1, 'GetType'), (1, 'pInfo')) + +# DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped): +DeviceIoControlPrototype = WINFUNCTYPE(BOOL, HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) +DeviceIoControlParams = ((1, 'hDevice'), (1, 'dwIoControlCode'), (1, 'lpInBuffer'), (1, 'nInBufferSize'), (1, 'lpOutBuffer'), (1, 'nOutBufferSize'), (1, 'lpBytesReturned'), (1, 'lpOverlapped')) diff --git a/generated_def/winstructs.py b/generated_def/winstructs.py index 7c0bb13..980d9c8 100644 --- a/generated_def/winstructs.py +++ b/generated_def/winstructs.py @@ -28,9 +28,9 @@ PHANDLE = POINTER(HANDLE) 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', '_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'] +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', '_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'] -enums = ['_SYSTEM_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE'] +enums = ['_SYSTEM_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE', '_IMAGEHLP_SYMBOL_TYPE_INFO'] # Enum _SYSTEM_INFORMATION_CLASS definitions _SYSTEM_INFORMATION_CLASS = DWORD @@ -155,6 +155,44 @@ MIB_TCP_STATE_CLOSING = 0x9 MIB_TCP_STATE_LAST_ACK = 0xa MIB_TCP_STATE_TIME_WAIT = 0xb MIB_TCP_STATE_DELETE_TCB = 0xc +# Enum _IMAGEHLP_SYMBOL_TYPE_INFO definitions +_IMAGEHLP_SYMBOL_TYPE_INFO = DWORD +IMAGEHLP_SYMBOL_TYPE_INFO = _IMAGEHLP_SYMBOL_TYPE_INFO + +TI_GET_SYMTAG = 0x0 +TI_GET_SYMNAME = 0x1 +TI_GET_LENGTH = 0x2 +TI_GET_TYPE = 0x3 +TI_GET_TYPEID = 0x4 +TI_GET_BASETYPE = 0x5 +TI_GET_ARRAYINDEXTYPEID = 0x6 +TI_FINDCHILDREN = 0x7 +TI_GET_DATAKIND = 0x8 +TI_GET_ADDRESSOFFSET = 0x9 +TI_GET_OFFSET = 0xa +TI_GET_VALUE = 0xb +TI_GET_COUNT = 0xc +TI_GET_CHILDRENCOUNT = 0xd +TI_GET_BITPOSITION = 0xe +TI_GET_VIRTUALBASECLASS = 0xf +TI_GET_VIRTUALTABLESHAPEID = 0x10 +TI_GET_VIRTUALBASEPOINTEROFFSET = 0x11 +TI_GET_CLASSPARENTID = 0x12 +TI_GET_NESTED = 0x13 +TI_GET_SYMINDEX = 0x14 +TI_GET_LEXICALPARENT = 0x15 +TI_GET_ADDRESS = 0x16 +TI_GET_THISADJUST = 0x17 +TI_GET_UDTKIND = 0x18 +TI_IS_EQUIV_TO = 0x19 +TI_GET_CALLING_CONVENTION = 0x1a +TI_IS_CLOSE_EQUIV_TO = 0x1b +TI_GTIEX_REQS_VALID = 0x1c +TI_GET_VIRTUALBASEOFFSET = 0x1d +TI_GET_VIRTUALBASEDISPINDEX = 0x1e +TI_GET_IS_REFERENCE = 0x1f +TI_GET_INDIRECTVIRTUALBASECLASS = 0x20 +IMAGEHLP_SYMBOL_TYPE_INFO_MAX = 0x21 # Struct _LIST_ENTRY definitions # Self referencing struct tricks class _LIST_ENTRY(Structure): pass @@ -1009,3 +1047,37 @@ class _DEBUG_PROCESSOR_IDENTIFICATION_ALL(Union): PDEBUG_PROCESSOR_IDENTIFICATION_ALL = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_ALL) DEBUG_PROCESSOR_IDENTIFICATION_ALL = _DEBUG_PROCESSOR_IDENTIFICATION_ALL +# Struct _SYMBOL_INFO definitions +class _SYMBOL_INFO(Structure): + _fields_ = [ + ("SizeOfStruct", ULONG), + ("TypeIndex", ULONG), + ("Reserved", ULONG64 * 2), + ("Index", ULONG), + ("Size", ULONG), + ("ModBase", ULONG64), + ("Flags", ULONG), + ("Value", ULONG64), + ("Address", ULONG64), + ("Register", ULONG), + ("Scope", ULONG), + ("Tag", ULONG), + ("NameLen", ULONG), + ("MaxNameLen", ULONG), + ("Name", CHAR * 1), + ] +SYMBOL_INFO = _SYMBOL_INFO +PSYMBOL_INFO = POINTER(_SYMBOL_INFO) + +# Struct _MODLOAD_DATA definitions +class _MODLOAD_DATA(Structure): + _fields_ = [ + ("ssize", DWORD), + ("ssig", DWORD), + ("data", PVOID), + ("size", DWORD), + ("flags", DWORD), + ] +PMODLOAD_DATA = POINTER(_MODLOAD_DATA) +MODLOAD_DATA = _MODLOAD_DATA + diff --git a/pe_parse.py b/pe_parse.py index 785eb0f..9ba389e 100644 --- a/pe_parse.py +++ b/pe_parse.py @@ -1,8 +1,11 @@ +import sys import ctypes +import struct import windows import windows.hooks as hooks from windows.generated_def.winstructs import * +import windows.remotectypes as rctypes # This must go to windefs IMAGE_DIRECTORY_ENTRY_EXPORT = 0 @@ -22,8 +25,27 @@ def RedefineCtypesStruct(struct, replacement): def transform_ctypes_fields(struct, replacement): return [(name, replacement.get(name, type)) for name, type in struct._fields_] -def PEFile(baseaddr): - if windows.current_process.bitness == 32: +def PEFile(baseaddr, target=None): + 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 + 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 else: IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG64 @@ -32,14 +54,30 @@ def PEFile(baseaddr): @property def addr(self): return baseaddr + self.value - + def __repr__(self): return "".format(self.value, hex(self.addr)) + + #class RVA(ctypes.Structure): + # _fields_ = [("Whatever", DWORD)] + # @property + # def addr(self): + # return baseaddr + self.Whatever + # + # def __repr__(self): + # return "".format(self.Whatever, hex(self.addr)) class StringRVa(RVA): - @property - def str(self): - return ctypes.c_char_p(self.addr).value.decode() + if proc_bitness == 32 and ctypes_structure_transformer == rctypes.transform_type_to_remote64bits: + @property + def str(self): + #return rctypes.rctypes.Remote_c_char_p64.from_buffer_with_target(struct.pack("".format(self.value, self.str) @@ -47,7 +85,6 @@ def PEFile(baseaddr): def __int__(self): return self.value - class IMPORT_BY_NAME(ctypes.Structure): _fields_ = [ ("Hint", WORD), @@ -66,7 +103,7 @@ def PEFile(baseaddr): @classmethod def create(cls, addr, ord, name): - self = cls.from_address(addr) + self = create_structure_at(cls, addr) self.addr = addr self.ord = ord self.name = name @@ -95,7 +132,7 @@ def PEFile(baseaddr): self.baseaddr = baseaddr def get_DOS_HEADER(self): - return IMAGE_DOS_HEADER.from_address(baseaddr) + return create_structure_at(IMAGE_DOS_HEADER, baseaddr) def get_NT_HEADER(self): return self.get_DOS_HEADER().get_NT_HEADER() @@ -111,12 +148,15 @@ def PEFile(baseaddr): if import_datadir.VirtualAddress == 0: return [] import_descriptor_addr = RVA(import_datadir.VirtualAddress).addr - current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr) + current_import_descriptor = create_structure_at(self.IMAGE_IMPORT_DESCRIPTOR, import_descriptor_addr) + #current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr) res = [] while current_import_descriptor.FirstThunk: + print(current_import_descriptor.FirstThunk) res.append(current_import_descriptor) import_descriptor_addr += ctypes.sizeof(self.IMAGE_IMPORT_DESCRIPTOR) - current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr) + #current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr) + current_import_descriptor = create_structure_at(self.IMAGE_IMPORT_DESCRIPTOR, import_descriptor_addr) return res def get_EXPORT_DIRECTORY(self): @@ -124,7 +164,8 @@ def PEFile(baseaddr): if export_directory_rva == 0: return None export_directory_addr = baseaddr + export_directory_rva - return self._IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr) + return create_structure_at(self._IMAGE_EXPORT_DIRECTORY, export_directory_addr) + #return self._IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr) @property @@ -147,7 +188,8 @@ def PEFile(baseaddr): IAT = import_descriptor.get_IAT() if INT is not None: for iat_entry, (ord, name) in zip(IAT, INT): - iat_entry.name = name.decode() + # str(name.decode()) -> python2 and python3 compatible for str result + iat_entry.name = str(name.decode()) if name else name iat_entry.ord = ord res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT) return res @@ -157,30 +199,44 @@ def PEFile(baseaddr): _fields_ = transform_ctypes_fields(IMAGE_IMPORT_DESCRIPTOR, {"Name" : StringRVa, "OriginalFirstThunk" : RVA, "FirstThunk" : RVA}) def get_INT(self): + if not self.OriginalFirstThunk.value: return None int_addr = self.OriginalFirstThunk.addr - int_entry = THUNK_DATA.from_address(int_addr) + #int_entry = THUNK_DATA.from_address(int_addr) + int_entry = create_structure_at(THUNK_DATA, int_addr) res = [] while int_entry.Ordinal: if int_entry.Ordinal & IMAGE_ORDINAL_FLAG: res += [(int_entry.Ordinal & 0x7fffffff, None)] else: - import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData) - name = ctypes.c_char_p(ctypes.addressof(import_by_name) + IMPORT_BY_NAME.Name.offset).value + #import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData) + + import_by_name = create_structure_at(IMPORT_BY_NAME, baseaddr + int_entry.AddressOfData) + + if proc_bitness == 32 and ctypes_structure_transformer == rctypes.transform_type_to_remote64bits: + name = rctypes.Remote_c_char_p64(baseaddr + int_entry.AddressOfData + type(import_by_name).Name.offset, target=target).value + #name = rctypes.Remote_c_char_p64.from_buffer_with_target(bytearray(struct.pack("