import struct import ctypes from ctypes import byref import codecs import functools import windows import windows.native_exec.simple_x64 as x64 from generated_def.winstructs import * from windows.winproxy import NeededParameter, OptionalExport, NtdllProxy, error_ntstatus # Special code for syswow64 process CS_32bits = 0x23 CS_64bits = 0x33 def genere_return_32bits_stub(ret_addr): ret_32b = x64.MultipleInstr() ret_32b += x64.Mov('RCX', (CS_32bits << 32) + ret_addr) ret_32b += x64.Push('RCX') ret_32b += x64.Retf32() # 32 bits return addr return ret_32b.get_code() # The format of a jump to 64bits mode dummy_jump = "\xea" + struct.pack(" ret | 8 -> ljump size_to_alloc = len(shellcode) + len(genere_return_32bits_stub(0xffffffff)) + 1 + 8 addr = windows.current_process.allocator.reserve_size(size_to_alloc) # post-exec 32bits stub (xor eax, eax; ret) ret = "\xC3" ret_addr = addr shell_code_addr = ret_addr + len(ret) + len(dummy_jump) # ljmp jump = "\xea" + struct.pack("= 1: code_64b += x64.Mov('RCX', x64.create_displacement(disp=argument_buffer)) if nb_args >= 2: code_64b += x64.Mov('RDX', x64.create_displacement(disp=argument_buffer + (8 * 1))) if nb_args >= 3: code_64b += x64.Mov('R8', x64.create_displacement(disp=argument_buffer + (8 * 2))) if nb_args >= 4: code_64b += x64.Mov('R9', x64.create_displacement(disp=argument_buffer + (8 * 3))) for i in range(nb_args_on_stack): code_64b += x64.Mov('RAX', x64.create_displacement(disp=argument_buffer + 8 * (nb_args - 1 - i))) code_64b += x64.Push('RAX') # reserve space for register (calling convention) code_64b += x64.Push('R9') code_64b += x64.Push('R8') code_64b += x64.Push('RDX') code_64b += x64.Push('RCX') # Call code_64b += x64.Mov('R13', target_addr) code_64b += x64.Call('R13') # Realign stack :) code_64b += x64.Add('RSP', x64.deref(alignement_information)) # Clean stack code_64b += x64.Add('RSP', (4 + nb_args_on_stack) * 8) code_64b += x64.Pop('R13') code_64b += x64.Pop('R12') code_64b += x64.Pop('R11') code_64b += x64.Pop('R10') code_64b += x64.Pop('R9') code_64b += x64.Pop('R8') code_64b += x64.Pop('RDI') code_64b += x64.Pop('RSI') code_64b += x64.Pop('RDX') code_64b += x64.Pop('RCX') code_64b += x64.Pop('RBX') return try_generate_stub_target(code_64b.get_code(), argument_buffer, target) def try_generate_stub_target(shellcode, argument_buffer, target): """shellcode must NOT end by a ret""" if not windows.current_process.is_wow_64: raise ValueError("Calling execute_64bits_code_from_syswow from non-syswow process") size_to_alloc = len(shellcode) + len(genere_return_32bits_stub(0xffffffff)) + 1 + 8 addr = windows.current_process.allocator.reserve_size(size_to_alloc) # post-exec 32bits stub (ret) ret = "\xC3" ret_addr = addr shell_code_addr = ret_addr + len(ret) + len(dummy_jump) # ljmp jump = "\xea" + struct.pack("".format(self.winproxy_function.__name__, param_name)) if self.raw_call is None: self.raw_call = generate_syswow64_call(self.winproxy_function) return self.raw_call(*args) setattr(python_proxy, "ctypes_function", perform_call) return python_proxy @Syswow64ApiProxy(windows.winproxy.NtCreateThreadEx) def NtCreateThreadEx_32_to_64(ThreadHandle=None, DesiredAccess=0x1fffff, ObjectAttributes=0, ProcessHandle=NeededParameter, lpStartAddress=NeededParameter, lpParameter=NeededParameter, CreateSuspended=0, dwStackSize=0, Unknown1=0, Unknown2=0, Unknown3=0): if ThreadHandle is None: ThreadHandle = byref(HANDLE()) return NtCreateThreadEx_32_to_64.ctypes_function(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, lpStartAddress, lpParameter, CreateSuspended, dwStackSize, Unknown1, Unknown2, Unknown3) ProcessBasicInformation = 0 @Syswow64ApiProxy(windows.winproxy.NtQueryInformationProcess) def NtQueryInformationProcess_32_to_64(ProcessHandle, ProcessInformationClass=ProcessBasicInformation, ProcessInformation=NeededParameter, ProcessInformationLength=0, ReturnLength=None): if ProcessInformation is not None and ProcessInformationLength == 0: ProcessInformationLength = ctypes.sizeof(ProcessInformation) if type(ProcessInformation) == PROCESS_BASIC_INFORMATION: ProcessInformation = byref(ProcessInformation) if ReturnLength is None: ReturnLength = byref(ULONG()) return NtQueryInformationProcess_32_to_64.ctypes_function(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength) @Syswow64ApiProxy(windows.winproxy.NtQueryInformationThread) def NtQueryInformationThread_32_to_64(ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength=0, ReturnLength=None): if ReturnLength is None: ReturnLength = byref(ULONG()) if ThreadInformation is not None and ThreadInformationLength == 0: ThreadInformationLength = ctypes.sizeof(ThreadInformation) return NtQueryInformationThread_32_to_64.ctypes_function(ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength) @Syswow64ApiProxy(windows.winproxy.NtQueryVirtualMemory) def NtQueryVirtualMemory_32_to_64(ProcessHandle, BaseAddress, MemoryInformationClass=MemoryBasicInformation, MemoryInformation=NeededParameter, MemoryInformationLength=0, ReturnLength=None): if ReturnLength is None: ReturnLength = byref(ULONG()) if MemoryInformation is not None and MemoryInformationLength == 0: MemoryInformationLength = ctypes.sizeof(MemoryInformation) if type(MemoryInformation) == MEMORY_BASIC_INFORMATION64: MemoryInformation = byref(MemoryInformation) return NtQueryVirtualMemory_32_to_64.ctypes_function(ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength) @Syswow64ApiProxy(windows.winproxy.NtGetContextThread) def NtGetContextThread_32_to_64(hThread, lpContext): if type(lpContext) == windows.vectored_exception.EnhancedCONTEXT64: lpContext = byref(lpContext) return NtGetContextThread_32_to_64.ctypes_function(hThread, lpContext)