mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
138 lines
5.3 KiB
Python
138 lines
5.3 KiB
Python
import struct
|
|
import ctypes
|
|
import codecs
|
|
import windows
|
|
import windows.k32testing as kernel32proxy
|
|
import windows.native_exec.simple_x64 as x64
|
|
from generated_def.winstructs import *
|
|
|
|
# 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("<I", 0) + chr(CS_64bits) + "\x00\x00"
|
|
|
|
def execute_64bits_code_from_syswow(shellcode):
|
|
"""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")
|
|
addr = windows.k32testing.VirtualAlloc(dwSize=0x1000)
|
|
# 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("<I", shell_code_addr) + chr(CS_64bits) + "\x00\x00"
|
|
jump_addr = ret_addr + len(ret)
|
|
# Return to 32bits stub
|
|
shellcode += genere_return_32bits_stub(ret_addr)
|
|
# WRITE ALL THE STUBS
|
|
windows.current_process.write_memory(ret_addr, ret)
|
|
windows.current_process.write_memory(jump_addr, jump)
|
|
windows.current_process.write_memory(shell_code_addr, shellcode)
|
|
# Execute
|
|
exec_stub = ctypes.CFUNCTYPE(HRESULT)(jump_addr)
|
|
return exec_stub()
|
|
|
|
def NtCreateThreadEx_32_to_64(process, addr, param):
|
|
NtCreateThreadEx = get_NtCreateThreadEx_syswow_addr()
|
|
create_thread = x64.MultipleInstr()
|
|
# Save registers
|
|
#create_thread += Push('RAX')
|
|
create_thread += x64.Push('RBX')
|
|
create_thread += x64.Push('RCX')
|
|
create_thread += x64.Push('RDX')
|
|
create_thread += x64.Push('RSI')
|
|
create_thread += x64.Push('RDI')
|
|
create_thread += x64.Push('R8')
|
|
create_thread += x64.Push('R9')
|
|
create_thread += x64.Push('R10')
|
|
create_thread += x64.Push('R11')
|
|
create_thread += x64.Push('R12')
|
|
create_thread += x64.Push('R13')
|
|
# Setup args
|
|
create_thread += x64.Push(0)
|
|
create_thread += x64.Mov('RCX', 'RSP') #Arg1
|
|
create_thread += x64.Mov('RDX', 0x1fffff) #Arg2
|
|
create_thread += x64.Mov('R8', 0) #Arg3
|
|
create_thread += x64.Mov('R9', process.handle) #Arg4
|
|
create_thread += x64.Mov('RAX', 0)
|
|
create_thread += x64.Push('RAX') #Arg11
|
|
create_thread += x64.Push('RAX') #Arg10
|
|
create_thread += x64.Push('RAX') #Arg9
|
|
create_thread += x64.Push('RAX') #Arg8
|
|
create_thread += x64.Push('RAX') #Arg7
|
|
create_thread += x64.Mov('RAX', param)
|
|
create_thread += x64.Push('RAX') #Arg6
|
|
create_thread += x64.Mov('RAX', addr)
|
|
create_thread += x64.Push('RAX') #Arg5
|
|
# reserve space for register (calling convention)
|
|
create_thread += x64.Push('R9')
|
|
create_thread += x64.Push('R8')
|
|
create_thread += x64.Push('RDX')
|
|
create_thread += x64.Push('RCX')
|
|
# Call
|
|
create_thread += x64.Mov('R13', NtCreateThreadEx)
|
|
create_thread += x64.Call('R13')
|
|
# Clean stack
|
|
create_thread += x64.Add('RSP' , 12 * 8)
|
|
create_thread += x64.Pop('R13')
|
|
create_thread += x64.Pop('R12')
|
|
create_thread += x64.Pop('R11')
|
|
create_thread += x64.Pop('R10')
|
|
create_thread += x64.Pop('R9')
|
|
create_thread += x64.Pop('R8')
|
|
create_thread += x64.Pop('RDI')
|
|
create_thread += x64.Pop('RSI')
|
|
create_thread += x64.Pop('RDX')
|
|
create_thread += x64.Pop('RCX')
|
|
create_thread += x64.Pop('RBX')
|
|
|
|
return execute_64bits_code_from_syswow(create_thread.get_code())
|
|
|
|
|
|
def get_NtCreateThreadEx_syswow_addr():
|
|
if get_NtCreateThreadEx_syswow_addr.value is not None:
|
|
return get_NtCreateThreadEx_syswow_addr.value
|
|
peb64 = get_current_process_syswow_peb()
|
|
ntdll64 = [m for m in peb64.modules if m.name == "ntdll.dll"]
|
|
if not ntdll64:
|
|
raise ValueError("Could not find ntdll.dll in syswow peb")
|
|
ntdll64 = ntdll64[0]
|
|
try:
|
|
get_NtCreateThreadEx_syswow_addr.value = ntdll64.pe.exports['NtCreateThreadEx']
|
|
except KeyError:
|
|
raise ValueError("Could not find NtCreateThreadEx in syswow ntdll.dll")
|
|
return get_NtCreateThreadEx_syswow_addr.value
|
|
get_NtCreateThreadEx_syswow_addr.value = None
|
|
|
|
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()
|
|
current_process.write_memory(dest, "\x00" * 8)
|
|
windows.syswow64.execute_64bits_code_from_syswow(get_peb_64_code)
|
|
peb_addr = struct.unpack("<Q", current_process.read_memory(dest, 8))[0]
|
|
return peb_addr
|
|
|
|
def get_current_process_syswow_peb():
|
|
current_process = windows.current_process
|
|
class CurrentProcessReadSyswow():
|
|
def read_memory(self, addr, size):
|
|
buffer_addr = ctypes.create_string_buffer(size)
|
|
kernel32proxy.NtWow64ReadVirtualMemory64(current_process.handle, addr, buffer_addr, size)
|
|
return buffer_addr[:]
|
|
bitness = 64
|
|
peb_addr = get_current_process_syswow_peb_addr()
|
|
return windows.winobject.RemotePEB64(peb_addr, CurrentProcessReadSyswow()) |