From 4ba46979d9144435aab90b37409fc9cdc1a5fcfc Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Mon, 20 Jul 2015 13:56:45 +0200 Subject: [PATCH] Fix hook with new assembler + fix python3 compat for hook --- generated_def/auto_doc_tst.py | 22 ++++++++ generated_def/winfuncs.py | 10 +++- generated_def/winstructs.py | 55 +++++++++++++++++++- native_exec/native_function.py | 93 ++++++++++++++++------------------ native_exec/simple_x64.py | 3 ++ native_exec/simple_x86.py | 60 ++++++++++++++++++---- pe_parse.py | 4 +- winobject.py | 14 +++-- 8 files changed, 193 insertions(+), 68 deletions(-) create mode 100644 generated_def/auto_doc_tst.py diff --git a/generated_def/auto_doc_tst.py b/generated_def/auto_doc_tst.py new file mode 100644 index 0000000..613ae10 --- /dev/null +++ b/generated_def/auto_doc_tst.py @@ -0,0 +1,22 @@ +def pretty_print_ctypes_type(t): + format = "{0}" + if issubclass(t, ctypes.Array): + format = "[{0}" + "* {0}]".format(t._length_) + t = t._type_ + + if issubclass(t, ctypes._Pointer): + format = format.format("Pointer({0})") + t = t._type_ + + if issubclass(t, ctypes.Structure): + return format.format(":class:`{0}`".format(t.__name__)) + return t + + +def autodoc_ctypes_struct(struct): + doc = ["fields:"] + for name, type in struct._fields_: + doc.append(" {0} -> {1}".format(name, pretty_print_ctypes_type(type))) + + struct.__doc__ = "\n\n".join(doc) + return struct \ No newline at end of file diff --git a/generated_def/winfuncs.py b/generated_def/winfuncs.py index 7b106c3..6b0bb3b 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'] +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'] # ExitProcess(uExitCode): ExitProcessPrototype = WINFUNCTYPE(VOID, UINT) @@ -269,3 +269,11 @@ WaitForSingleObjectParams = ((1, 'hHandle'), (1, 'dwMilliseconds')) GetThreadIdPrototype = WINFUNCTYPE(DWORD, HANDLE) GetThreadIdParams = ((1, 'Thread'),) +# LoadLibraryExA(lpFileName, hFile, dwFlags): +LoadLibraryExAPrototype = WINFUNCTYPE(HMODULE, LPCSTR, HANDLE, DWORD) +LoadLibraryExAParams = ((1, 'lpFileName'), (1, 'hFile'), (1, 'dwFlags')) + +# LoadLibraryExW(lpFileName, hFile, dwFlags): +LoadLibraryExWPrototype = WINFUNCTYPE(HMODULE, LPCWSTR, HANDLE, DWORD) +LoadLibraryExWParams = ((1, 'lpFileName'), (1, 'hFile'), (1, 'dwFlags')) + diff --git a/generated_def/winstructs.py b/generated_def/winstructs.py index 588ad83..7c0bb13 100644 --- a/generated_def/winstructs.py +++ b/generated_def/winstructs.py @@ -28,7 +28,7 @@ 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_X86'] +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'] enums = ['_SYSTEM_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE'] @@ -945,6 +945,38 @@ class _EXCEPTION_POINTERS32(Structure): PEXCEPTION_POINTERS32 = POINTER(_EXCEPTION_POINTERS32) EXCEPTION_POINTERS32 = _EXCEPTION_POINTERS32 +# Struct _DEBUG_PROCESSOR_IDENTIFICATION_ALPHA definitions +class _DEBUG_PROCESSOR_IDENTIFICATION_ALPHA(Structure): + _fields_ = [ + ("Type", ULONG), + ("Revision", ULONG), + ] +DEBUG_PROCESSOR_IDENTIFICATION_ALPHA = _DEBUG_PROCESSOR_IDENTIFICATION_ALPHA +PDEBUG_PROCESSOR_IDENTIFICATION_ALPHA = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_ALPHA) + +# Struct _DEBUG_PROCESSOR_IDENTIFICATION_AMD64 definitions +class _DEBUG_PROCESSOR_IDENTIFICATION_AMD64(Structure): + _fields_ = [ + ("Family", ULONG), + ("Model", ULONG), + ("Stepping", ULONG), + ("VendorString", CHAR * 16), + ] +DEBUG_PROCESSOR_IDENTIFICATION_AMD64 = _DEBUG_PROCESSOR_IDENTIFICATION_AMD64 +PDEBUG_PROCESSOR_IDENTIFICATION_AMD64 = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_AMD64) + +# Struct _DEBUG_PROCESSOR_IDENTIFICATION_IA64 definitions +class _DEBUG_PROCESSOR_IDENTIFICATION_IA64(Structure): + _fields_ = [ + ("Model", ULONG), + ("Revision", ULONG), + ("Family", ULONG), + ("ArchRev", ULONG), + ("VendorString", CHAR * 16), + ] +PDEBUG_PROCESSOR_IDENTIFICATION_IA64 = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_IA64) +DEBUG_PROCESSOR_IDENTIFICATION_IA64 = _DEBUG_PROCESSOR_IDENTIFICATION_IA64 + # Struct _DEBUG_PROCESSOR_IDENTIFICATION_X86 definitions class _DEBUG_PROCESSOR_IDENTIFICATION_X86(Structure): _fields_ = [ @@ -956,3 +988,24 @@ class _DEBUG_PROCESSOR_IDENTIFICATION_X86(Structure): DEBUG_PROCESSOR_IDENTIFICATION_X86 = _DEBUG_PROCESSOR_IDENTIFICATION_X86 PDEBUG_PROCESSOR_IDENTIFICATION_X86 = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_X86) +# Struct _DEBUG_PROCESSOR_IDENTIFICATION_ARM definitions +class _DEBUG_PROCESSOR_IDENTIFICATION_ARM(Structure): + _fields_ = [ + ("Type", ULONG), + ("Revision", ULONG), + ] +DEBUG_PROCESSOR_IDENTIFICATION_ARM = _DEBUG_PROCESSOR_IDENTIFICATION_ARM +PDEBUG_PROCESSOR_IDENTIFICATION_ARM = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_ARM) + +# Struct _DEBUG_PROCESSOR_IDENTIFICATION_ALL definitions +class _DEBUG_PROCESSOR_IDENTIFICATION_ALL(Union): + _fields_ = [ + ("Alpha", DEBUG_PROCESSOR_IDENTIFICATION_ALPHA), + ("Amd64", DEBUG_PROCESSOR_IDENTIFICATION_AMD64), + ("Ia64", DEBUG_PROCESSOR_IDENTIFICATION_IA64), + ("X86", DEBUG_PROCESSOR_IDENTIFICATION_X86), + ("Arm", DEBUG_PROCESSOR_IDENTIFICATION_ARM), + ] +PDEBUG_PROCESSOR_IDENTIFICATION_ALL = POINTER(_DEBUG_PROCESSOR_IDENTIFICATION_ALL) +DEBUG_PROCESSOR_IDENTIFICATION_ALL = _DEBUG_PROCESSOR_IDENTIFICATION_ALL + diff --git a/native_exec/native_function.py b/native_exec/native_function.py index f11fbaf..8e33ce5 100644 --- a/native_exec/native_function.py +++ b/native_exec/native_function.py @@ -1,12 +1,13 @@ import ctypes import mmap import platform +import sys import windows import windows.k32testing as k32api from . import simple_x86 as x86 -#from . import simple_x64 as x64 +from . import simple_x64 as x64 class PyObj(ctypes.Structure): _fields_ = [("ob_refcnt", ctypes.c_size_t), @@ -96,15 +97,16 @@ class CustomAllocator(object): addr = self.maps[-1].addr + self.cur_offset self.cur_offset += size return addr + +allocator = CustomAllocator() def get_functions(): - # Windows only with python27.dll | improve this ? - import sys - import windows - - PyGILState_Ensure = windows.utils.get_func_addr('python27', 'PyGILState_Ensure') - PyObject_CallObject = windows.utils.get_func_addr('python27', 'PyObject_CallObject') - PyGILState_Release = windows.utils.get_func_addr('python27', 'PyGILState_Release') + version = sys.version_info + python_dll = "python" + str(version.major) + str(version.minor) + + PyGILState_Ensure = windows.utils.get_func_addr(python_dll, 'PyGILState_Ensure'.encode()) + PyObject_CallObject = windows.utils.get_func_addr(python_dll, 'PyObject_CallObject'.encode()) + PyGILState_Release = windows.utils.get_func_addr(python_dll, 'PyGILState_Release'.encode()) return [PyGILState_Ensure, PyObject_CallObject, PyGILState_Release] def analyse_callback(callback): @@ -115,18 +117,14 @@ def analyse_callback(callback): raise ValueError("Need a ctypes PyCFuncPtr") return obj_id - - + # For windows 32 bits with stdcall def generate_stub_32(callback): - - allocator = windows.current_process.allocator obj_id = analyse_callback(callback) + c_callback = get_callback_address_32(callback) - c_callback = ctypes.c_ulong.from_address(id(callback._objects['0']) + 3 * ctypes.sizeof(ctypes.c_void_p)).value - gstate_save_addr = allocator.reserve_int() - return_addr_save_addr = allocator.reserve_int() - + gstate_save_addr = x86.create_displacement(disp=allocator.reserve_int()) + return_addr_save_addr = x86.create_displacement(disp=allocator.reserve_int()) save_ebx = x86.create_displacement(disp=allocator.reserve_int()) save_ecx = x86.create_displacement(disp=allocator.reserve_int()) save_edx = x86.create_displacement(disp=allocator.reserve_int()) @@ -136,7 +134,6 @@ def generate_stub_32(callback): ensure, objcall, release = get_functions() code = x86.MultipleInstr() - ### Shellcode ### code += x86.Mov(save_ebx, 'EBX') code += x86.Mov(save_ecx, 'ECX') @@ -182,26 +179,20 @@ def generate_stub_32(callback): code += x86.Ret() return code -# For windows 32 bits with stdcall + def generate_stub_64(callback): - - allocator = windows.current_process.allocator obj_id = analyse_callback(callback) - + c_callback = get_callback_address_64(callback) REG_LEN = ctypes.sizeof(ctypes.c_void_p) - - c_callback = ctypes.c_ulong.from_address(id(callback._objects['0']) + 3 * ctypes.sizeof(ctypes.c_void_p)).value - register_to_save = ("RBX", "RCX", "RDX", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15") push_all_save_register = x64.MultipleInstr([x64.Push(reg) for reg in register_to_save]) - pop_all_save_register = x64.MultipleInstr([x64.Pop(reg) for reg in register_to_save]) + pop_all_save_register = x64.MultipleInstr([x64.Pop(reg) for reg in reversed(register_to_save)]) # Reserve parallel `stack` save_register_space = allocator.reserve_int(len(register_to_save) + 1) save_register_space += REG_LEN # The + 1 is for the second-stack xchg save_register_space_end = save_register_space + (ctypes.sizeof(ctypes.c_void_p) * (len(register_to_save) )) - save_rbx = save_register_space_end - REG_LEN save_rcx = save_register_space_end - REG_LEN - REG_LEN save_rdx = save_register_space_end - REG_LEN - (REG_LEN * 2) @@ -210,35 +201,29 @@ def generate_stub_64(callback): save_r8 = save_register_space_end - REG_LEN - (REG_LEN * 5) save_r9 = save_register_space_end - REG_LEN - (REG_LEN * 6) + gstate_save_addr = x64.create_displacement(disp=allocator.reserve_int()) + return_addr_save_addr = x64.create_displacement(disp=allocator.reserve_int()) + return_value_save_addr = x64.create_displacement(disp=allocator.reserve_int()) - gstate_save_addr = create_displacement(disp=allocator.reserve_int()) - return_addr_save_addr = create_displacement(disp=allocator.reserve_int()) - return_value_save_addr = create_displacement(disp=allocator.reserve_int()) - - Reserve_space_for_call = x64.MultipleInstr([Push('RDI')] * 4) - Clean_space_for_call = x64.MultipleInstr([Pop('RDI')] * 4) - Do_stack_alignement = MultipleInstr([x64.Push('RDI')] * 1) - Remove_stack_alignement = MultipleInstr([x64.Pop('RDI')] * 1) - + Reserve_space_for_call = x64.MultipleInstr([x64.Push('RDI')] * 4) + Clean_space_for_call = x64.MultipleInstr([x64.Pop('RDI')] * 4) + Do_stack_alignement = x64.MultipleInstr([x64.Push('RDI')] * 1) + Remove_stack_alignement = x64.MultipleInstr([x64.Pop('RDI')] * 1) ensure, objcall, release = get_functions() ### Shellcode ### - code = MultipleInstr() + code = x64.MultipleInstr() code += x64.Mov('RAX', save_register_space_end) # A lazy working xchg RSP <-> RAX code += x64.Push('RAX') code += x64.Push('RSP') code += x64.Pop('RAX') code += x64.Pop('RSP') - code += push_all_save_register - # Re-set RSP to its real value code += x64.Push('RAX') code += x64.Pop('RSP') - - code += x64.Pop('RAX') # Remove the Push_RAX of lazy xchg # GOOO code += x64.Mov('RAX', ensure) @@ -256,15 +241,14 @@ def generate_stub_64(callback): code += x64.Mov('RCX', x64.create_displacement('RAX')) code += x64.Mov('RAX', save_rdx) code += x64.Mov('RDX', x64.create_displacement('RAX')) - code += x64.Mov('RAX', save_r8) - code += x64.Mov('R9', x64.create_displacement('RAX')) code += x64.Mov('RAX', save_r9) + code += x64.Mov('R9', x64.create_displacement('RAX')) + code += x64.Mov('RAX', save_r8) code += x64.Mov('R8', x64.create_displacement('RAX')) # Call python code code += x64.Mov('RAX', c_callback) code += Reserve_space_for_call code += x64.Call('RAX') # no need for stack alignement here as we poped the return addr - code += Clean_space_for_call # Save return value code += x64.Mov(return_value_save_addr, 'RAX') @@ -272,7 +256,7 @@ def generate_stub_64(callback): code += x64.Mov('RAX', return_addr_save_addr) code += x64.Push('RAX') # Call release(gstate_save) - code += x64.Mov_RAX_DX('RAX', gstate_save_addr) + code += x64.Mov('RAX', gstate_save_addr) code += x64.Push('RAX') code += x64.Pop('RCX') code += x64.Mov('RAX', release) @@ -288,16 +272,13 @@ def generate_stub_64(callback): code += x64.Push('RSP') code += x64.Pop('RAX') code += x64.Pop('RSP') - code += pop_all_save_register - # Re-set RSP to its real value code += x64.Push('RAX') code += x64.Pop('RSP') code += x64.Pop('RAX') # Remove the Push_RAX of lazy xchg - # Restore return value - code += x64.Mov_RAX_DX('RAX', return_value_save_addr) + code += x64.Mov('RAX', return_value_save_addr) code += x64.Ret() return code @@ -309,7 +290,7 @@ def generate_callback_stub(callback, types): stub = generate_stub_32(c_callable) else: stub = generate_stub_64(c_callable) - stub_addr = windows.current_process.allocator.write_code(stub.get_code()) + stub_addr = allocator.write_code(stub.get_code()) generate_callback_stub.l.append((stub, c_callable)) return stub_addr @@ -324,5 +305,17 @@ def create_function(code, types): :rtype: function """ func_type = ctypes.CFUNCTYPE(*types) - addr = windows.current_process.allocator.write_code(code) + addr = allocator.write_code(code) return func_type(addr) + +# Return First argument for 32 bits code +raw_code = x86.MultipleInstr() +raw_code += x86.Mov('EAX', x86.create_displacement(base='ESP', disp=4)) +raw_code += x86.Ret() +get_callback_address_32 = create_function(raw_code.get_code(), [ctypes.c_void_p]) + +# Return First argument for 64 bits code +raw_code = x64.MultipleInstr() +raw_code += x64.Mov('RAX', 'RCX') +raw_code += x64.Ret() +get_callback_address_64 = create_function(raw_code.get_code(), [ctypes.c_void_p]) diff --git a/native_exec/simple_x64.py b/native_exec/simple_x64.py index 0e500a0..6fde65d 100644 --- a/native_exec/simple_x64.py +++ b/native_exec/simple_x64.py @@ -331,6 +331,9 @@ class Call(Instruction): class Ret(Instruction): encoding = [(RawBits.from_int(8, 0xc3),)] +class Int3(Instruction): + encoding = [(RawBits.from_int(8, 0xcc),)] + class Mov(Instruction): default_32_bits = True encoding = [(RawBits.from_int(8, 0x89), ModRM(ModRM_REG64__REG64, ModRM_REG__DEREF_REG)), (RawBits.from_int(5, 0xb8 >> 3), X64RegisterSelector(), Imm64()), diff --git a/native_exec/simple_x86.py b/native_exec/simple_x86.py index b995add..607d736 100644 --- a/native_exec/simple_x86.py +++ b/native_exec/simple_x86.py @@ -92,7 +92,10 @@ class RawBits(BitArray): class Imm32(object): def accept_arg(self, previous, args): - x = int(args[0]) + try: + x = int(args[0]) + except TypeError: + return (None, None) return (1, BitArray.from_int(32, X86.to_little_endian(x))) class ModRM(object): @@ -132,7 +135,10 @@ class X86(object): if not X86.is_mem_acces(mem_access): raise ValueError("mem_access_has_only") for f in mem_access._fields: - if getattr(mem_access, f) and f not in names: + v = getattr(mem_access, f) + if v and f not in names: + return False + if v is None and f in names: return False return True @@ -169,7 +175,7 @@ class ModRM_REG__DEREF_REG(object): class ModRM_REG__DEREF_REG_IMM(object): @classmethod def match(cls, arg1, arg2): - return X86.is_reg(arg1) and X86.is_mem_acces(arg2) and X86.mem_access_has_only(arg2, ["base", "disp"]) + return X86.is_reg(arg1) and X86.is_mem_acces(arg2) and X86.mem_access_has_only(arg2, ["base", "disp"]) and arg2.base != "ESP" def __init__(self, arg1, arg2, reversed): self.mod = BitArray(2, "10") @@ -178,16 +184,45 @@ class ModRM_REG__DEREF_REG_IMM(object): self.after = BitArray.from_int(32, X86.to_little_endian(arg2.disp)) self.direction = not reversed -class ModRM_REG_IMM(object): +class ModRM_REG__DEREF_SIB(object): + # Only handle reg, [esp+x] now :( @classmethod def match(cls, arg1, arg2): - return arg1 in x86_regs and arg2 in x86_regs + return X86.is_reg(arg1) and X86.is_mem_acces(arg2) and X86.mem_access_has_only(arg2, ["base", "disp"]) and arg2.base == "ESP" - def __init__(self, arg1, arg2): - self.mod = BitArray(2, "11") - self.reg = X86RegisterSelector.get_reg_bits(arg2) - self.rm = X86RegisterSelector.get_reg_bits(arg1) - self.direction = 0 + def __init__(self, arg1, arg2, reversed): + self.mod = BitArray(2, "10") + self.reg = X86RegisterSelector.get_reg_bits(arg1) + self.rm = BitArray(3, "100") + + # Todo -> def sib_from_displacement + sib = BitArray(8, "00100100") + + self.after = sib + BitArray.from_int(32, X86.to_little_endian(arg2.disp)) + self.direction = not reversed + +#class ModRM_REG_IMM(object): +# @classmethod +# def match(cls, arg1, arg2): +# return arg1 in x86_regs and arg2 in x86_regs +# +# def __init__(self, arg1, arg2): +# self.mod = BitArray(2, "11") +# self.reg = X86RegisterSelector.get_reg_bits(arg2) +# self.rm = X86RegisterSelector.get_reg_bits(arg1) +# self.direction = 0 + +class ModRM_REG__DEREF_IMM(object): + @classmethod + def match(cls, arg1, arg2): + return X86.is_reg(arg1) and X86.is_mem_acces(arg2) and X86.mem_access_has_only(arg2, ["disp"]) + + def __init__(self, arg1, arg2, reversed): + self.mod = BitArray(2, "00") + self.reg = X86RegisterSelector.get_reg_bits(arg1) + self.rm = BitArray(3, "101") + self.after = BitArray.from_int(32, X86.to_little_endian(arg2.disp)) + self.direction = not reversed class Instruction(object): @@ -219,7 +254,7 @@ class Pop(Instruction): encoding = [(RawBits.from_int(5, 0x58 >> 3), X86RegisterSelector())] class Mov(Instruction): - encoding = [(RawBits.from_int(8, 0x89), ModRM(ModRM_REG__REG, ModRM_REG__DEREF_REG, ModRM_REG__DEREF_REG_IMM)), + encoding = [(RawBits.from_int(8, 0x89), ModRM(ModRM_REG__REG, ModRM_REG__DEREF_REG, ModRM_REG__DEREF_REG_IMM, ModRM_REG__DEREF_IMM, ModRM_REG__DEREF_SIB)), (RawBits.from_int(5, 0xb8 >> 3), X86RegisterSelector(), Imm32())] class Call(Instruction): @@ -228,6 +263,9 @@ class Call(Instruction): class Ret(Instruction): encoding = [(RawBits.from_int(8, 0xc3),)] +class Int3(Instruction): + encoding = [(RawBits.from_int(8, 0xcc),)] + class MultipleInstr(object): diff --git a/pe_parse.py b/pe_parse.py index f9489dc..785eb0f 100644 --- a/pe_parse.py +++ b/pe_parse.py @@ -39,7 +39,7 @@ def PEFile(baseaddr): class StringRVa(RVA): @property def str(self): - return ctypes.c_char_p(self.addr).value + return ctypes.c_char_p(self.addr).value.decode() def __repr__(self): return "".format(self.value, self.str) @@ -147,7 +147,7 @@ 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 + iat_entry.name = name.decode() iat_entry.ord = ord res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT) return res diff --git a/winobject.py b/winobject.py index af59195..d1c4861 100644 --- a/winobject.py +++ b/winobject.py @@ -38,7 +38,7 @@ class AutoHandle(object): return self._handle def __del__(self): - if hasattr(self, "_handle"): + if hasattr(self, "_handle") and self._handle: kernel32proxy.CloseHandle(self._handle) class System(object): @@ -219,9 +219,14 @@ class CurrentThread(AutoHandle): def _get_handle(self): return kernel32proxy.GetCurrentThread() + def __del__(self): + pass + def exit(self, code=0): """Exit the thread""" return kernel32proxy.ExitThread(code) + + class CurrentProcess(Process): """The current process""" @@ -231,7 +236,7 @@ class CurrentProcess(Process): # ret get_peb_64_code = codecs.decode(b"65488B042560000000C3", 'hex') - allocator = native_exec.native_function.CustomAllocator() + allocator = native_exec.native_function.allocator def get_peb_builtin(self): @@ -246,6 +251,9 @@ class CurrentProcess(Process): def _get_handle(self): return kernel32proxy.GetCurrentProcess() + + def __del__(self): + pass @property def pid(self): @@ -418,7 +426,7 @@ class LoadedModule(LDR_DATA_TABLE_ENTRY): :type: str """ - return self.FullDllName.Buffer + return self.FullDllName.Buffer.decode() def __repr__(self): return '<{0} "{1}" at {2}>'.format(self.__class__.__name__, self.name, hex(id(self)))