1 /* radare2 - LGPL - Copyright 2018 - pancake */
2
3 #include <r_types.h>
4 #include <r_util.h>
5 #include <r_lib.h>
6 #include <r_bin.h>
7 #include <r_core.h>
8 #include <r_io.h>
9 #include <ht_pu.h>
10 // #include "../format/mach0/mach0_defines.h"
11 #define R_BIN_MACH064 1
12 #include "../format/mach0/mach0.h"
13 #include "objc/mach0_classes.h"
14
15 #define R_IS_PTR_AUTHENTICATED(x) B_IS_SET(x, 63)
16
17 typedef struct {
18 ut8 version;
19 ut64 slide;
20 ut8 *one_page_buf;
21 ut32 page_size;
22 ut64 start_of_data;
23 } RDyldRebaseInfo;
24
25 typedef struct {
26 ut64 start;
27 ut64 end;
28 RDyldRebaseInfo *info;
29 } RDyldRebaseInfosEntry;
30
31 typedef struct {
32 RDyldRebaseInfosEntry *entries;
33 size_t length;
34 } RDyldRebaseInfos;
35
36 typedef struct {
37 ut8 version;
38 ut64 slide;
39 ut8 *one_page_buf;
40 ut32 page_size;
41 ut64 start_of_data;
42 ut16 *page_starts;
43 ut32 page_starts_count;
44 ut64 delta_mask;
45 ut32 delta_shift;
46 ut64 auth_value_add;
47 } RDyldRebaseInfo3;
48
49 typedef struct {
50 ut8 version;
51 ut64 slide;
52 ut8 *one_page_buf;
53 ut32 page_size;
54 ut64 start_of_data;
55 ut16 *page_starts;
56 ut32 page_starts_count;
57 ut16 *page_extras;
58 ut32 page_extras_count;
59 ut64 delta_mask;
60 ut64 value_mask;
61 ut32 delta_shift;
62 ut64 value_add;
63 } RDyldRebaseInfo2;
64
65 typedef struct {
66 ut8 version;
67 ut64 slide;
68 ut8 *one_page_buf;
69 ut32 page_size;
70 ut64 start_of_data;
71 ut16 *toc;
72 ut32 toc_count;
73 ut8 *entries;
74 ut32 entries_size;
75 } RDyldRebaseInfo1;
76
77 typedef struct {
78 char *strings;
79 ut64 strings_size;
80 struct MACH0_(nlist) *nlists;
81 ut64 nlists_count;
82 cache_locsym_entry_t *entries;
83 ut64 entries_count;
84 } RDyldLocSym;
85
86 typedef struct _r_dyldcache {
87 ut8 magic[8];
88 RList *bins;
89 RBuffer *buf;
90 int (*original_io_read)(RIO *io, RIODesc *fd, ut8 *buf, int count);
91 RDyldRebaseInfos *rebase_infos;
92 cache_hdr_t *hdr;
93 cache_map_t *maps;
94 cache_accel_t *accel;
95 RDyldLocSym *locsym;
96 } RDyldCache;
97
98 typedef struct _r_bin_image {
99 char *file;
100 ut64 header_at;
101 } RDyldBinImage;
102
103 static RList * pending_bin_files = NULL;
104
105 static ut64 va2pa(uint64_t addr, cache_hdr_t *hdr, cache_map_t *maps, RBuffer *cache_buf, ut64 slide, ut32 *offset, ut32 *left);
106
free_bin(RDyldBinImage * bin)107 static void free_bin(RDyldBinImage *bin) {
108 if (!bin) {
109 return;
110 }
111
112 R_FREE (bin->file);
113 R_FREE (bin);
114 }
115
rebase_info3_free(RDyldRebaseInfo3 * rebase_info)116 static void rebase_info3_free(RDyldRebaseInfo3 *rebase_info) {
117 if (!rebase_info) {
118 return;
119 }
120
121 R_FREE (rebase_info->page_starts);
122 R_FREE (rebase_info);
123 }
124
rebase_info2_free(RDyldRebaseInfo2 * rebase_info)125 static void rebase_info2_free(RDyldRebaseInfo2 *rebase_info) {
126 if (!rebase_info) {
127 return;
128 }
129
130 R_FREE (rebase_info->page_starts);
131 R_FREE (rebase_info->page_extras);
132 R_FREE (rebase_info);
133 }
134
rebase_info1_free(RDyldRebaseInfo1 * rebase_info)135 static void rebase_info1_free(RDyldRebaseInfo1 *rebase_info) {
136 if (!rebase_info) {
137 return;
138 }
139
140 R_FREE (rebase_info->toc);
141 R_FREE (rebase_info->entries);
142 R_FREE (rebase_info);
143 }
144
rebase_info_free(RDyldRebaseInfo * rebase_info)145 static void rebase_info_free(RDyldRebaseInfo *rebase_info) {
146 if (!rebase_info) {
147 return;
148 }
149
150 R_FREE (rebase_info->one_page_buf);
151
152 ut8 version = rebase_info->version;
153
154 if (version == 1) {
155 rebase_info1_free ((RDyldRebaseInfo1*) rebase_info);
156 } else if (version == 2 || version == 4) {
157 rebase_info2_free ((RDyldRebaseInfo2*) rebase_info);
158 } else if (version == 3) {
159 rebase_info3_free ((RDyldRebaseInfo3*) rebase_info);
160 } else {
161 R_FREE (rebase_info);
162 }
163 }
164
r_dyld_locsym_new(RBuffer * cache_buf,cache_hdr_t * hdr)165 static RDyldLocSym *r_dyld_locsym_new(RBuffer *cache_buf, cache_hdr_t *hdr) {
166 if (!cache_buf || !hdr || !hdr->localSymbolsSize || !hdr->localSymbolsOffset) {
167 return NULL;
168 }
169
170 cache_locsym_info_t *info = NULL;
171 char *strings = NULL;
172 cache_locsym_entry_t *entries = NULL;
173 struct MACH0_(nlist) *nlists = NULL;
174
175 ut64 info_size = sizeof (cache_locsym_info_t);
176 info = R_NEW0 (cache_locsym_info_t);
177 if (!info) {
178 goto beach;
179 }
180 if (r_buf_fread_at (cache_buf, hdr->localSymbolsOffset, (ut8*) info, "6i", 1) != info_size) {
181 goto beach;
182 }
183
184 ut64 nlists_size = sizeof (struct MACH0_(nlist)) * info->nlistCount;
185 nlists = R_NEWS0 (struct MACH0_(nlist), info->nlistCount);
186 if (!nlists) {
187 goto beach;
188 }
189 if (r_buf_fread_at (cache_buf, hdr->localSymbolsOffset + info->nlistOffset, (ut8*) nlists, "iccsl",
190 info->nlistCount) != nlists_size) {
191 goto beach;
192 }
193
194 strings = malloc (info->stringsSize);
195 if (!strings) {
196 goto beach;
197 }
198 if (r_buf_read_at (cache_buf, hdr->localSymbolsOffset + info->stringsOffset, (ut8*) strings,
199 info->stringsSize) != info->stringsSize) {
200 goto beach;
201 }
202
203 ut64 entries_size = sizeof (cache_locsym_entry_t) * info->entriesCount;
204 entries = R_NEWS0 (cache_locsym_entry_t, info->entriesCount);
205 if (!entries) {
206 goto beach;
207 }
208 if (r_buf_fread_at (cache_buf, hdr->localSymbolsOffset + info->entriesOffset, (ut8*) entries, "3i",
209 info->entriesCount) != entries_size) {
210 goto beach;
211 }
212
213 RDyldLocSym * locsym = R_NEW0 (RDyldLocSym);
214 if (!locsym) {
215 goto beach;
216 }
217
218 locsym->nlists = nlists;
219 locsym->nlists_count = info->nlistCount;
220 locsym->strings = strings;
221 locsym->strings_size = info->stringsSize;
222 locsym->entries = entries;
223 locsym->entries_count = info->entriesCount;
224
225 free (info);
226
227 return locsym;
228
229 beach:
230 free (info);
231 free (strings);
232 free (entries);
233 free (nlists);
234
235 eprintf ("dyldcache: malformed local symbols metadata\n");
236 return NULL;
237 }
238
r_dyld_locsym_free(RDyldLocSym * locsym)239 static void r_dyld_locsym_free(RDyldLocSym *locsym) {
240 if (!locsym) {
241 return;
242 }
243 R_FREE (locsym->strings);
244 R_FREE (locsym->entries);
245 R_FREE (locsym->nlists);
246 free (locsym);
247 }
248
rebase_infos_get_slide(RDyldCache * cache)249 static ut64 rebase_infos_get_slide(RDyldCache *cache) {
250 if (!cache->rebase_infos || !cache->rebase_infos->length) {
251 return 0;
252 }
253
254 size_t i;
255 for (i = 0; i < cache->rebase_infos->length; i++) {
256 if (cache->rebase_infos->entries[i].info) {
257 return cache->rebase_infos->entries[i].info->slide;
258 }
259 }
260
261 return 0;
262 }
263
r_dyld_locsym_entries_by_offset(RDyldCache * cache,RList * symbols,SetU * hash,ut64 bin_header_offset)264 static void r_dyld_locsym_entries_by_offset(RDyldCache *cache, RList *symbols, SetU *hash, ut64 bin_header_offset) {
265 RDyldLocSym *locsym = cache->locsym;
266 if (!locsym->entries) {
267 return;
268 }
269
270 ut64 i;
271 for (i = 0; i != locsym->entries_count; i++) {
272 cache_locsym_entry_t *entry = &locsym->entries[i];
273 if (entry->dylibOffset != bin_header_offset) {
274 continue;
275 }
276
277 if (entry->nlistStartIndex >= locsym->nlists_count ||
278 entry->nlistStartIndex + entry->nlistCount > locsym->nlists_count) {
279 eprintf ("dyldcache: malformed local symbol entry\n");
280 break;
281 }
282
283 ut32 j;
284 for (j = 0; j != entry->nlistCount; j++) {
285 struct MACH0_(nlist) *nlist = &locsym->nlists[j + entry->nlistStartIndex];
286 if (set_u_contains (hash, (ut64)nlist->n_value)) {
287 continue;
288 }
289 set_u_add (hash, (ut64)nlist->n_value);
290 if (nlist->n_strx >= locsym->strings_size) {
291 continue;
292 }
293 char *symstr = &locsym->strings[nlist->n_strx];
294 RBinSymbol *sym = R_NEW0 (RBinSymbol);
295 if (!sym) {
296 return;
297 }
298 sym->type = "LOCAL";
299 sym->vaddr = nlist->n_value;
300 ut64 slide = rebase_infos_get_slide (cache);
301 sym->paddr = va2pa (nlist->n_value, cache->hdr, cache->maps, cache->buf, slide, NULL, NULL);
302
303 int len = locsym->strings_size - nlist->n_strx;
304 ut32 k;
305 for (k = 0; k < len; k++) {
306 if (((ut8) symstr[k] & 0xff) == 0xff || !symstr[k]) {
307 len = k;
308 break;
309 }
310 }
311 if (len > 0) {
312 sym->name = r_str_ndup (symstr, len);
313 } else {
314 sym->name = r_str_newf ("unk_local%d", k);
315 }
316
317 r_list_append (symbols, sym);
318 }
319 break;
320 }
321 }
322
r_dyldcache_free(RDyldCache * cache)323 static void r_dyldcache_free(RDyldCache *cache) {
324 if (!cache) {
325 return;
326 }
327
328 r_list_free (cache->bins);
329 cache->bins = NULL;
330 r_buf_free (cache->buf);
331 cache->buf = NULL;
332 if (cache->rebase_infos) {
333 int i;
334 for (i = 0; i < cache->rebase_infos->length; i++) {
335 rebase_info_free (cache->rebase_infos->entries[i].info);
336 cache->rebase_infos->entries[i].info = NULL;
337 }
338 R_FREE (cache->rebase_infos->entries);
339 R_FREE (cache->rebase_infos);
340 }
341 R_FREE (cache->hdr);
342 R_FREE (cache->maps);
343 R_FREE (cache->accel);
344 r_dyld_locsym_free (cache->locsym);
345 R_FREE (cache);
346 }
347
va2pa(uint64_t addr,cache_hdr_t * hdr,cache_map_t * maps,RBuffer * cache_buf,ut64 slide,ut32 * offset,ut32 * left)348 static ut64 va2pa(uint64_t addr, cache_hdr_t *hdr, cache_map_t *maps, RBuffer *cache_buf, ut64 slide, ut32 *offset, ut32 *left) {
349 ut64 res = UT64_MAX;
350 uint32_t i;
351
352 addr -= slide;
353
354 for (i = 0; i < hdr->mappingCount; i++) {
355 if (addr >= maps[i].address && addr < maps[i].address + maps[i].size) {
356 res = maps[i].fileOffset + addr - maps[i].address;
357 if (offset) {
358 *offset = addr - maps[i].address;
359 }
360 if (left) {
361 *left = maps[i].size - (addr - maps[i].address);
362 }
363 break;
364 }
365 }
366
367 return res;
368 }
369
bin_obj_va2pa(ut64 p,ut32 * offset,ut32 * left,RBinFile * bf)370 static ut64 bin_obj_va2pa(ut64 p, ut32 *offset, ut32 *left, RBinFile *bf) {
371 if (!bf || !bf->o || !bf->o->bin_obj) {
372 return 0;
373 }
374
375 RDyldCache *cache = (RDyldCache*) ((struct MACH0_(obj_t)*)bf->o->bin_obj)->user;
376 if (!cache) {
377 return 0;
378 }
379
380 ut64 slide = rebase_infos_get_slide (cache);
381 ut64 res = va2pa (p, cache->hdr, cache->maps, cache->buf, slide, offset, left);
382 if (res == UT64_MAX) {
383 res = 0;
384 }
385 return res;
386 }
387
MACH0_(obj_t)388 static struct MACH0_(obj_t) *bin_to_mach0(RBinFile *bf, RDyldBinImage *bin) {
389 if (!bin || !bf) {
390 return NULL;
391 }
392
393 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
394 if (!cache) {
395 return NULL;
396 }
397
398 struct MACH0_(opts_t) opts;
399 MACH0_(opts_set_default) (&opts, bf);
400 opts.header_at = bin->header_at;
401 struct MACH0_(obj_t) *mach0 = MACH0_(new_buf) (cache->buf, &opts);
402 mach0->user = cache;
403 mach0->va2pa = &bin_obj_va2pa;
404 return mach0;
405 }
406
prot2perm(int x)407 static int prot2perm(int x) {
408 int r = 0;
409 if (x & 1) {
410 r |= 4;
411 }
412 if (x & 2) {
413 r |= 2;
414 }
415 if (x & 4) {
416 r |= 1;
417 }
418 return r;
419 }
420
dumb_ctzll(ut64 x)421 static ut32 dumb_ctzll(ut64 x) {
422 ut64 result = 0;
423 int i, j;
424 for (i = 0; i < 64; i += 8) {
425 ut8 byte = (x >> i) & 0xff;
426 if (!byte) {
427 result += 8;
428 } else {
429 for (j = 0; j < 8; j++) {
430 if (!((byte >> j) & 1)) {
431 result++;
432 } else {
433 break;
434 }
435 }
436 break;
437 }
438 }
439 return result;
440 }
441
estimate_slide(RBinFile * bf,RDyldCache * cache,ut64 value_mask)442 static ut64 estimate_slide(RBinFile *bf, RDyldCache *cache, ut64 value_mask) {
443 ut64 slide = 0;
444 ut64 *classlist = malloc (64);
445 if (!classlist) {
446 goto beach;
447 }
448
449 RListIter *iter;
450 RDyldBinImage *bin;
451 r_list_foreach (cache->bins, iter, bin) {
452 bool found_sample = false;
453
454 struct MACH0_(opts_t) opts;
455 opts.verbose = bf->rbin->verbose;
456 opts.header_at = bin->header_at;
457
458 struct MACH0_(obj_t) *mach0 = MACH0_(new_buf) (cache->buf, &opts);
459 if (!mach0) {
460 goto beach;
461 }
462
463 struct section_t *sections = NULL;
464 if (!(sections = MACH0_(get_sections) (mach0))) {
465 MACH0_(mach0_free) (mach0);
466 goto beach;
467 }
468
469 int i;
470 int incomplete = 2;
471 int classlist_idx = 0, data_idx = 0;
472 for (i = 0; !sections[i].last && incomplete; i++) {
473 if (sections[i].size == 0) {
474 continue;
475 }
476 if (strstr (sections[i].name, "__objc_classlist")) {
477 incomplete--;
478 classlist_idx = i;
479 continue;
480 }
481 if (strstr (sections[i].name, "__objc_data")) {
482 incomplete--;
483 data_idx = i;
484 continue;
485 }
486 }
487
488 if (incomplete) {
489 goto next_bin;
490 }
491
492 int classlist_sample_size = R_MIN (64, sections[classlist_idx].size);
493 int n_classes = classlist_sample_size / 8;
494
495 if (r_buf_fread_at (cache->buf, sections[classlist_idx].offset, (ut8*) classlist, "l", n_classes) < classlist_sample_size) {
496 goto next_bin;
497 }
498
499 ut64 data_addr = sections[data_idx].addr;
500 ut64 data_tail = data_addr & 0xfff;
501 ut64 data_tail_end = (data_addr + sections[data_idx].size) & 0xfff;
502 for (i = 0; i < n_classes; i++) {
503 ut64 cl_tail = classlist[i] & 0xfff;
504 if (cl_tail >= data_tail && cl_tail < data_tail_end) {
505 ut64 off = cl_tail - data_tail;
506 slide = ((classlist[i] - off) & value_mask) - (data_addr & value_mask);
507 found_sample = true;
508 break;
509 }
510 }
511
512 next_bin:
513 MACH0_(mach0_free) (mach0);
514 R_FREE (sections);
515
516 if (found_sample) {
517 break;
518 }
519 }
520
521 beach:
522 R_FREE (classlist);
523 return slide;
524 }
525
get_rebase_info(RBinFile * bf,RDyldCache * cache,ut64 slideInfoOffset,ut64 slideInfoSize,ut64 start_of_data,ut64 slide)526 static RDyldRebaseInfo *get_rebase_info(RBinFile *bf, RDyldCache *cache, ut64 slideInfoOffset, ut64 slideInfoSize, ut64 start_of_data, ut64 slide) {
527 ut8 *tmp_buf_1 = NULL;
528 ut8 *tmp_buf_2 = NULL;
529 ut8 *one_page_buf = NULL;
530 RBuffer *cache_buf = cache->buf;
531
532 ut64 offset = slideInfoOffset;
533 ut32 slide_info_version = 0;
534 if (r_buf_read_at (cache_buf, offset, (ut8*) &slide_info_version, 4) != 4) {
535 return NULL;
536 }
537
538 if (slide_info_version == 3) {
539 cache_slide3_t slide_info;
540 ut64 size = sizeof (cache_slide3_t);
541 if (r_buf_fread_at (cache_buf, offset, (ut8*) &slide_info, "4i1l", 1) < 20) {
542 return NULL;
543 }
544
545 ut64 page_starts_offset = offset + size;
546 ut64 page_starts_size = slide_info.page_starts_count * 2;
547
548 if (page_starts_size + size > slideInfoSize) {
549 return NULL;
550 }
551
552 if (page_starts_size > 0) {
553 tmp_buf_1 = malloc (page_starts_size);
554 if (!tmp_buf_1) {
555 goto beach;
556 }
557 if (r_buf_fread_at (cache_buf, page_starts_offset, tmp_buf_1, "s", slide_info.page_starts_count) != page_starts_size) {
558 goto beach;
559 }
560 }
561
562 if (slide_info.page_size > 0) {
563 one_page_buf = malloc (slide_info.page_size);
564 if (!one_page_buf) {
565 goto beach;
566 }
567 }
568
569 RDyldRebaseInfo3 *rebase_info = R_NEW0 (RDyldRebaseInfo3);
570 if (!rebase_info) {
571 goto beach;
572 }
573
574 rebase_info->version = 3;
575 rebase_info->delta_mask = 0x3ff8000000000000ULL;
576 rebase_info->delta_shift = 51;
577 rebase_info->start_of_data = start_of_data;
578 rebase_info->page_starts = (ut16*) tmp_buf_1;
579 rebase_info->page_starts_count = slide_info.page_starts_count;
580 rebase_info->auth_value_add = slide_info.auth_value_add;
581 rebase_info->page_size = slide_info.page_size;
582 rebase_info->one_page_buf = one_page_buf;
583 if (slide == UT64_MAX) {
584 rebase_info->slide = estimate_slide (bf, cache, 0x7ffffffffffffULL);
585 if (rebase_info->slide) {
586 eprintf ("dyldcache is slid: 0x%"PFMT64x"\n", rebase_info->slide);
587 }
588 } else {
589 rebase_info->slide = slide;
590 }
591
592 return (RDyldRebaseInfo*) rebase_info;
593 } else if (slide_info_version == 2 || slide_info_version == 4) {
594 cache_slide2_t slide_info;
595 ut64 size = sizeof (cache_slide2_t);
596 if (r_buf_fread_at (cache_buf, offset, (ut8*) &slide_info, "6i2l", 1) != size) {
597 return NULL;
598 }
599
600 if (slide_info.page_starts_offset == 0 ||
601 slide_info.page_starts_offset > slideInfoSize ||
602 slide_info.page_starts_offset + slide_info.page_starts_count * 2 > slideInfoSize) {
603 return NULL;
604 }
605
606 if (slide_info.page_extras_offset == 0 ||
607 slide_info.page_extras_offset > slideInfoSize ||
608 slide_info.page_extras_offset + slide_info.page_extras_count * 2 > slideInfoSize) {
609 return NULL;
610 }
611
612 if (slide_info.page_starts_count > 0) {
613 ut64 size = slide_info.page_starts_count * 2;
614 ut64 at = slideInfoOffset + slide_info.page_starts_offset;
615 tmp_buf_1 = malloc (size);
616 if (!tmp_buf_1) {
617 goto beach;
618 }
619 if (r_buf_fread_at (cache_buf, at, tmp_buf_1, "s", slide_info.page_starts_count) != size) {
620 goto beach;
621 }
622 }
623
624 if (slide_info.page_extras_count > 0) {
625 ut64 size = slide_info.page_extras_count * 2;
626 ut64 at = slideInfoOffset + slide_info.page_extras_offset;
627 tmp_buf_2 = malloc (size);
628 if (!tmp_buf_2) {
629 goto beach;
630 }
631 if (r_buf_fread_at (cache_buf, at, tmp_buf_2, "s", slide_info.page_extras_count) != size) {
632 goto beach;
633 }
634 }
635
636 if (slide_info.page_size > 0) {
637 one_page_buf = malloc (slide_info.page_size);
638 if (!one_page_buf) {
639 goto beach;
640 }
641 }
642
643 RDyldRebaseInfo2 *rebase_info = R_NEW0 (RDyldRebaseInfo2);
644 if (!rebase_info) {
645 goto beach;
646 }
647
648 rebase_info->version = slide_info_version;
649 rebase_info->start_of_data = start_of_data;
650 rebase_info->page_starts = (ut16*) tmp_buf_1;
651 rebase_info->page_starts_count = slide_info.page_starts_count;
652 rebase_info->page_extras = (ut16*) tmp_buf_2;
653 rebase_info->page_extras_count = slide_info.page_extras_count;
654 rebase_info->value_add = slide_info.value_add;
655 rebase_info->delta_mask = slide_info.delta_mask;
656 rebase_info->value_mask = ~rebase_info->delta_mask;
657 rebase_info->delta_shift = dumb_ctzll (rebase_info->delta_mask) - 2;
658 rebase_info->page_size = slide_info.page_size;
659 rebase_info->one_page_buf = one_page_buf;
660 if (slide == UT64_MAX) {
661 rebase_info->slide = estimate_slide (bf, cache, rebase_info->value_mask);
662 if (rebase_info->slide) {
663 eprintf ("dyldcache is slid: 0x%"PFMT64x"\n", rebase_info->slide);
664 }
665 } else {
666 rebase_info->slide = slide;
667 }
668
669 return (RDyldRebaseInfo*) rebase_info;
670 } else if (slide_info_version == 1) {
671 cache_slide1_t slide_info;
672 ut64 size = sizeof (cache_slide1_t);
673 if (r_buf_fread_at (cache_buf, offset, (ut8*) &slide_info, "6i", 1) != size) {
674 return NULL;
675 }
676
677 if (slide_info.toc_offset == 0 ||
678 slide_info.toc_offset > slideInfoSize ||
679 slide_info.toc_offset + slide_info.toc_count * 2 > slideInfoSize) {
680 return NULL;
681 }
682
683 if (slide_info.entries_offset == 0 ||
684 slide_info.entries_offset > slideInfoSize ||
685 slide_info.entries_offset + slide_info.entries_count * slide_info.entries_size > slideInfoSize) {
686 return NULL;
687 }
688
689 if (slide_info.toc_count > 0) {
690 ut64 size = slide_info.toc_count * 2;
691 ut64 at = slideInfoOffset + slide_info.toc_offset;
692 tmp_buf_1 = malloc (size);
693 if (!tmp_buf_1) {
694 goto beach;
695 }
696 if (r_buf_fread_at (cache_buf, at, tmp_buf_1, "s", slide_info.toc_count) != size) {
697 goto beach;
698 }
699 }
700
701 if (slide_info.entries_count > 0) {
702 ut64 size = (ut64) slide_info.entries_count * (ut64) slide_info.entries_size;
703 ut64 at = slideInfoOffset + slide_info.entries_offset;
704 tmp_buf_2 = malloc (size);
705 if (!tmp_buf_2) {
706 goto beach;
707 }
708 if (r_buf_read_at (cache_buf, at, tmp_buf_2, size) != size) {
709 goto beach;
710 }
711 }
712
713 one_page_buf = malloc (4096);
714 if (!one_page_buf) {
715 goto beach;
716 }
717
718 RDyldRebaseInfo1 *rebase_info = R_NEW0 (RDyldRebaseInfo1);
719 if (!rebase_info) {
720 goto beach;
721 }
722
723 rebase_info->version = 1;
724 rebase_info->start_of_data = start_of_data;
725 rebase_info->one_page_buf = one_page_buf;
726 rebase_info->page_size = 4096;
727 rebase_info->toc = (ut16*) tmp_buf_1;
728 rebase_info->toc_count = slide_info.toc_count;
729 rebase_info->entries = tmp_buf_2;
730 rebase_info->entries_size = slide_info.entries_size;
731 if (slide == UT64_MAX) {
732 rebase_info->slide = estimate_slide (bf, cache, UT64_MAX);
733 if (rebase_info->slide) {
734 eprintf ("dyldcache is slid: 0x%"PFMT64x"\n", rebase_info->slide);
735 }
736 } else {
737 rebase_info->slide = slide;
738 }
739
740 return (RDyldRebaseInfo*) rebase_info;
741 } else {
742 eprintf ("unsupported slide info version %d\n", slide_info_version);
743 return NULL;
744 }
745
746 beach:
747 R_FREE (tmp_buf_1);
748 R_FREE (tmp_buf_2);
749 R_FREE (one_page_buf);
750 return NULL;
751 }
752
get_rebase_infos(RBinFile * bf,RDyldCache * cache)753 static RDyldRebaseInfos *get_rebase_infos(RBinFile *bf, RDyldCache *cache) {
754 RBuffer *cache_buf = cache->buf;
755
756 RDyldRebaseInfos *result = R_NEW0 (RDyldRebaseInfos);
757 if (!result) {
758 return NULL;
759 }
760
761 if (!cache->hdr->slideInfoOffset || !cache->hdr->slideInfoSize) {
762 ut64 slide_infos_offset;
763 size_t n_slide_infos;
764 if ((slide_infos_offset = r_buf_read_le32_at (cache_buf, 0x138)) == UT32_MAX) {
765 goto beach;
766 }
767 if ((n_slide_infos = r_buf_read_le32_at (cache_buf, 0x13c)) == UT32_MAX) {
768 goto beach;
769 }
770
771 RDyldRebaseInfosEntry * infos = R_NEWS0 (RDyldRebaseInfosEntry, n_slide_infos);
772 if (!infos) {
773 goto beach;
774 }
775
776 size_t i, j;
777 RDyldRebaseInfo *prev_info = NULL;
778 for (i = 0, j = 0; i < n_slide_infos; i++) {
779 ut64 offset = slide_infos_offset + i * sizeof (cache_mapping_slide);
780 cache_mapping_slide entry;
781 if (r_buf_fread_at (cache_buf, offset, (ut8*)&entry, "6lii", 1) != sizeof (cache_mapping_slide)) {
782 free (infos);
783 goto beach;
784 }
785
786 if (entry.slideInfoOffset && entry.slideInfoSize) {
787 infos[j].start = entry.fileOffset;
788 infos[j].end = entry.fileOffset + entry.size;
789 ut64 slide = prev_info ? prev_info->slide : UT64_MAX;
790 infos[j].info = get_rebase_info (bf, cache, entry.slideInfoOffset, entry.slideInfoSize, entry.fileOffset, slide);
791 prev_info = infos[j].info;
792 j++;
793 }
794 }
795
796 if (!j) {
797 free (infos);
798 goto beach;
799 }
800
801 if (j != n_slide_infos) {
802 RDyldRebaseInfosEntry * pruned_infos = R_NEWS0 (RDyldRebaseInfosEntry, j);
803 if (!pruned_infos) {
804 free (infos);
805 goto beach;
806 }
807
808 memcpy (pruned_infos, infos, sizeof (RDyldRebaseInfosEntry) * j);
809 free (infos);
810 infos = pruned_infos;
811 }
812
813 result->entries = infos;
814 result->length = j;
815 return result;
816 }
817
818 if (cache->hdr->mappingCount > 1) {
819 RDyldRebaseInfosEntry * infos = R_NEWS0 (RDyldRebaseInfosEntry, 1);
820 if (!infos) {
821 return NULL;
822 }
823
824 infos[0].start = cache->maps[1].fileOffset;
825 infos[0].end = infos[0].start + cache->maps[1].size;
826 infos[0].info = get_rebase_info (bf, cache, cache->hdr->slideInfoOffset, cache->hdr->slideInfoSize, infos[0].start, UT64_MAX);
827
828 result->entries = infos;
829 result->length = 1;
830 return result;
831 }
832
833 beach:
834 free (result);
835 return NULL;
836 }
837
check_buffer(RBuffer * buf)838 static bool check_buffer(RBuffer *buf) {
839 if (r_buf_size (buf) < 32) {
840 return false;
841 }
842
843 ut8 hdr[4];
844 ut8 arch[9] = { 0 };
845 int rarch = r_buf_read_at (buf, 9, arch, sizeof (arch) - 1);
846 int rhdr = r_buf_read_at (buf, 0, hdr, sizeof (hdr));
847 if (rhdr != sizeof (hdr) || memcmp (hdr, "dyld", 4)) {
848 return false;
849 }
850 if (rarch > 0 && arch[0] && !strstr ((const char *)arch, "arm64")) {
851 return false;
852 }
853 return true;
854 }
855
read_cache_images(RBuffer * cache_buf,cache_hdr_t * hdr)856 static cache_img_t *read_cache_images(RBuffer *cache_buf, cache_hdr_t *hdr) {
857 if (!cache_buf || !hdr || !hdr->imagesCount || !hdr->imagesOffset) {
858 return NULL;
859 }
860
861 ut64 size = sizeof (cache_img_t) * hdr->imagesCount;
862 cache_img_t *images = R_NEWS0 (cache_img_t, hdr->imagesCount);
863 if (!images) {
864 return NULL;
865 }
866
867 if (r_buf_fread_at (cache_buf, hdr->imagesOffset, (ut8*) images, "3l2i", hdr->imagesCount) != size) {
868 R_FREE (images);
869 return NULL;
870 }
871
872 return images;
873 }
874
read_cache_imgextra(RBuffer * cache_buf,cache_hdr_t * hdr,cache_accel_t * accel)875 static cache_imgxtr_t *read_cache_imgextra(RBuffer *cache_buf, cache_hdr_t *hdr, cache_accel_t *accel) {
876 if (!cache_buf || !hdr || !hdr->imagesCount || !accel || !accel->imageExtrasCount || !accel->imagesExtrasOffset) {
877 return NULL;
878 }
879
880 ut64 size = sizeof (cache_imgxtr_t) * accel->imageExtrasCount;
881 cache_imgxtr_t *images = R_NEWS0 (cache_imgxtr_t, accel->imageExtrasCount);
882 if (!images) {
883 return NULL;
884 }
885
886 if (r_buf_fread_at (cache_buf, accel->imagesExtrasOffset, (ut8*) images, "ll4i", accel->imageExtrasCount) != size) {
887 R_FREE (images);
888 return NULL;
889 }
890
891 return images;
892 }
893
get_lib_name(RBuffer * cache_buf,cache_img_t * img)894 static char *get_lib_name(RBuffer *cache_buf, cache_img_t *img) {
895 char file[256];
896 char *lib_name = file;
897 if (r_buf_read_at (cache_buf, img->pathFileOffset, (ut8*) &file, sizeof (file)) == sizeof (file)) {
898 file[255] = 0;
899 /*char * last_slash = strrchr (file, '/');
900 if (last_slash && *last_slash) {
901 lib_name = last_slash + 1;
902 }*/
903 return strdup (lib_name);
904 }
905 return strdup ("FAIL");
906 }
907
string_contains(const void * a,const void * b)908 static int string_contains(const void *a, const void *b) {
909 return !strstr ((const char*) a, (const char*) b);
910 }
911
create_path_to_index(RBuffer * cache_buf,cache_img_t * img,cache_hdr_t * hdr)912 static HtPU *create_path_to_index(RBuffer *cache_buf, cache_img_t *img, cache_hdr_t *hdr) {
913 HtPU *path_to_idx = ht_pu_new0 ();
914 if (!path_to_idx) {
915 return NULL;
916 }
917 for (size_t i = 0; i != hdr->imagesCount; i++) {
918 char file[256];
919 if (r_buf_read_at (cache_buf, img[i].pathFileOffset, (ut8*) &file, sizeof (file)) != sizeof (file)) {
920 continue;
921 }
922 file[255] = 0;
923 ht_pu_insert (path_to_idx, file, (ut64)i);
924 }
925
926 return path_to_idx;
927 }
928
carve_deps_at_address(RBuffer * cache_buf,cache_img_t * img,cache_hdr_t * hdr,cache_map_t * maps,HtPU * path_to_idx,ut64 address,int * deps)929 static void carve_deps_at_address(RBuffer *cache_buf, cache_img_t *img, cache_hdr_t *hdr, cache_map_t *maps, HtPU *path_to_idx, ut64 address, int *deps) {
930 ut64 pa = va2pa (address, hdr, maps, cache_buf, 0, NULL, NULL);
931 if (pa == UT64_MAX) {
932 return;
933 }
934 struct MACH0_(mach_header) mh;
935 if (r_buf_fread_at (cache_buf, pa, (ut8*) &mh, "8i", 1) != sizeof (struct MACH0_(mach_header))) {
936 return;
937 }
938 if (mh.magic != MH_MAGIC_64 || mh.sizeofcmds == 0) {
939 return;
940 }
941 ut64 cmds_at = pa + sizeof (struct MACH0_(mach_header));
942 ut8 *cmds = malloc (mh.sizeofcmds + 1);
943 if (!cmds || r_buf_read_at (cache_buf, cmds_at, cmds, mh.sizeofcmds) != mh.sizeofcmds) {
944 goto beach;
945 }
946 cmds[mh.sizeofcmds] = 0;
947 ut8 *cursor = cmds;
948 ut8 *end = cmds + mh.sizeofcmds;
949 while (cursor < end) {
950 ut32 cmd = r_read_le32 (cursor);
951 ut32 cmdsize = r_read_le32 (cursor + sizeof (ut32));
952 if (cmd == LC_LOAD_DYLIB ||
953 cmd == LC_LOAD_WEAK_DYLIB ||
954 cmd == LC_REEXPORT_DYLIB ||
955 cmd == LC_LOAD_UPWARD_DYLIB) {
956 bool found;
957 if (cursor + 24 >= end) {
958 break;
959 }
960 const char *key = (const char *) cursor + 24;
961 size_t dep_index = (size_t)ht_pu_find (path_to_idx, key, &found);
962 if (!found || dep_index >= hdr->imagesCount) {
963 eprintf ("WARNING: alien dep '%s'\n", key);
964 continue;
965 }
966 deps[dep_index]++;
967 eprintf ("-> %s\n", key);
968 }
969 cursor += cmdsize;
970 }
971
972 beach:
973 free (cmds);
974 }
975
create_cache_bins(RBinFile * bf,RBuffer * cache_buf,cache_hdr_t * hdr,cache_map_t * maps,cache_accel_t * accel)976 static RList *create_cache_bins(RBinFile *bf, RBuffer *cache_buf, cache_hdr_t *hdr, cache_map_t *maps, cache_accel_t *accel) {
977 RList *bins = r_list_newf ((RListFree)free_bin);
978 if (!bins) {
979 return NULL;
980 }
981
982 cache_img_t *img = read_cache_images (cache_buf, hdr);
983 if (!img) {
984 r_list_free (bins);
985 return NULL;
986 }
987
988 int i;
989 int *deps = NULL;
990 char *target_libs = NULL;
991 target_libs = r_sys_getenv ("R_DYLDCACHE_FILTER");
992 RList *target_lib_names = NULL;
993 ut16 *depArray = NULL;
994 cache_imgxtr_t *extras = NULL;
995 if (target_libs) {
996 target_lib_names = r_str_split_list (target_libs, ":", 0);
997 if (!target_lib_names) {
998 goto error;
999 }
1000
1001 deps = R_NEWS0 (int, hdr->imagesCount);
1002 if (!deps) {
1003 goto error;
1004 }
1005
1006 HtPU *path_to_idx = NULL;
1007 if (accel) {
1008 depArray = R_NEWS0 (ut16, accel->depListCount);
1009 if (!depArray) {
1010 goto error;
1011 }
1012
1013 if (r_buf_fread_at (cache_buf, accel->depListOffset, (ut8*) depArray, "s", accel->depListCount) != accel->depListCount * 2) {
1014 goto error;
1015 }
1016
1017 extras = read_cache_imgextra (cache_buf, hdr, accel);
1018 if (!extras) {
1019 goto error;
1020 }
1021 } else {
1022 path_to_idx = create_path_to_index (cache_buf, img, hdr);
1023 }
1024
1025 for (i = 0; i < hdr->imagesCount; i++) {
1026 char *lib_name = get_lib_name (cache_buf, &img[i]);
1027 if (!lib_name) {
1028 break;
1029 }
1030 if (strstr (lib_name, "libobjc.A.dylib")) {
1031 deps[i]++;
1032 }
1033 if (!r_list_find (target_lib_names, lib_name, string_contains)) {
1034 R_FREE (lib_name);
1035 continue;
1036 }
1037 eprintf ("FILTER: %s\n", lib_name);
1038 R_FREE (lib_name);
1039 deps[i]++;
1040
1041 if (extras && depArray) {
1042 ut32 j;
1043 for (j = extras[i].dependentsStartArrayIndex; depArray[j] != 0xffff; j++) {
1044 ut16 dep_index = depArray[j] & 0x7fff;
1045 deps[dep_index]++;
1046
1047 char *dep_name = get_lib_name (cache_buf, &img[dep_index]);
1048 if (!dep_name) {
1049 break;
1050 }
1051 eprintf ("-> %s\n", dep_name);
1052 free (dep_name);
1053 }
1054 } else if (path_to_idx) {
1055 carve_deps_at_address (cache_buf, img, hdr, maps, path_to_idx, img[i].address, deps);
1056 }
1057 }
1058
1059 ht_pu_free (path_to_idx);
1060 R_FREE (depArray);
1061 R_FREE (extras);
1062 R_FREE (target_libs);
1063 r_list_free (target_lib_names);
1064 target_lib_names = NULL;
1065 }
1066
1067 for (i = 0; i < hdr->imagesCount; i++) {
1068 if (deps && !deps[i]) {
1069 continue;
1070 }
1071 ut64 pa = va2pa (img[i].address, hdr, maps, cache_buf, 0, NULL, NULL);
1072 if (pa == UT64_MAX) {
1073 continue;
1074 }
1075 ut8 magicbytes[4];
1076 r_buf_read_at (cache_buf, pa, magicbytes, 4);
1077 int magic = r_read_le32 (magicbytes);
1078 switch (magic) {
1079 case MH_MAGIC:
1080 // parse_mach0 (ret, *ptr, bf);
1081 break;
1082 case MH_MAGIC_64:
1083 {
1084 char file[256];
1085 RDyldBinImage *bin = R_NEW0 (RDyldBinImage);
1086 if (!bin) {
1087 goto error;
1088 }
1089 bin->header_at = pa;
1090 if (r_buf_read_at (cache_buf, img[i].pathFileOffset, (ut8*) &file, sizeof (file)) == sizeof (file)) {
1091 file[255] = 0;
1092 char *last_slash = strrchr (file, '/');
1093 if (last_slash && *last_slash) {
1094 if (last_slash > file) {
1095 char *scan = last_slash - 1;
1096 while (scan > file && *scan != '/') {
1097 scan--;
1098 }
1099 if (*scan == '/') {
1100 bin->file = strdup (scan + 1);
1101 } else {
1102 bin->file = strdup (last_slash + 1);
1103 }
1104 } else {
1105 bin->file = strdup (last_slash + 1);
1106 }
1107 } else {
1108 bin->file = strdup (file);
1109 }
1110 }
1111 r_list_append (bins, bin);
1112 break;
1113 }
1114 default:
1115 eprintf ("Unknown sub-bin\n");
1116 break;
1117 }
1118 }
1119
1120 goto beach;
1121 error:
1122 if (bins) {
1123 r_list_free (bins);
1124 }
1125 bins = NULL;
1126 beach:
1127 R_FREE (depArray);
1128 R_FREE (extras);
1129 R_FREE (target_libs);
1130 if (target_lib_names) {
1131 r_list_free (target_lib_names);
1132 }
1133 R_FREE (deps);
1134 R_FREE (img);
1135 return bins;
1136 }
1137
rebase_bytes_v1(RDyldRebaseInfo1 * rebase_info,ut8 * buf,ut64 offset,int count,ut64 start_of_write)1138 static void rebase_bytes_v1(RDyldRebaseInfo1 *rebase_info, ut8 *buf, ut64 offset, int count, ut64 start_of_write) {
1139 int in_buf = 0;
1140 while (in_buf < count) {
1141 ut64 offset_in_data = offset - rebase_info->start_of_data;
1142 ut64 page_index = offset_in_data / rebase_info->page_size;
1143 ut64 page_offset = offset_in_data % rebase_info->page_size;
1144 ut64 to_next_page = rebase_info->page_size - page_offset;
1145 ut64 entry_index = page_offset / 32;
1146 ut64 offset_in_entry = (page_offset % 32) / 4;
1147
1148 if (entry_index >= rebase_info->entries_size) {
1149 in_buf += to_next_page;
1150 offset += to_next_page;
1151 continue;
1152 }
1153
1154 if (page_index >= rebase_info->toc_count) {
1155 break;
1156 }
1157
1158 ut8 *entry = &rebase_info->entries[rebase_info->toc[page_index] * rebase_info->entries_size];
1159 ut8 b = entry[entry_index];
1160
1161 if (b & (1 << offset_in_entry)) {
1162 ut64 value = r_read_le64 (buf + in_buf);
1163 value += rebase_info->slide;
1164 r_write_le64 (buf + in_buf, value);
1165 in_buf += 8;
1166 offset += 8;
1167 } else {
1168 in_buf += 4;
1169 offset += 4;
1170 }
1171 }
1172 }
1173
rebase_bytes_v2(RDyldRebaseInfo2 * rebase_info,ut8 * buf,ut64 offset,int count,ut64 start_of_write)1174 static void rebase_bytes_v2(RDyldRebaseInfo2 *rebase_info, ut8 *buf, ut64 offset, int count, ut64 start_of_write) {
1175 int in_buf = 0;
1176 while (in_buf < count) {
1177 ut64 offset_in_data = offset - rebase_info->start_of_data;
1178 ut64 page_index = offset_in_data / rebase_info->page_size;
1179 ut64 page_offset = offset_in_data % rebase_info->page_size;
1180 ut64 to_next_page = rebase_info->page_size - page_offset;
1181
1182 if (page_index >= rebase_info->page_starts_count) {
1183 goto next_page;
1184 }
1185 ut16 page_flag = rebase_info->page_starts[page_index];
1186
1187 if (page_flag == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE) {
1188 goto next_page;
1189 }
1190
1191 if (!(page_flag & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA)) {
1192 ut64 first_rebase_off = rebase_info->page_starts[page_index] * 4;
1193 if (first_rebase_off >= page_offset && first_rebase_off < page_offset + count) {
1194 ut32 delta = 1;
1195 while (delta) {
1196 ut64 position = in_buf + first_rebase_off - page_offset;
1197 if (position >= count) {
1198 break;
1199 }
1200 ut64 raw_value = r_read_le64 (buf + position);
1201 delta = ((raw_value & rebase_info->delta_mask) >> rebase_info->delta_shift);
1202 if (position >= start_of_write) {
1203 ut64 new_value = raw_value & rebase_info->value_mask;
1204 if (new_value != 0) {
1205 new_value += rebase_info->value_add;
1206 new_value += rebase_info->slide;
1207 }
1208 r_write_le64 (buf + position, new_value);
1209 }
1210 first_rebase_off += delta;
1211 }
1212 }
1213 }
1214 next_page:
1215 in_buf += to_next_page;
1216 offset += to_next_page;
1217 }
1218 }
1219
rebase_bytes_v3(RDyldRebaseInfo3 * rebase_info,ut8 * buf,ut64 offset,int count,ut64 start_of_write)1220 static void rebase_bytes_v3(RDyldRebaseInfo3 *rebase_info, ut8 *buf, ut64 offset, int count, ut64 start_of_write) {
1221 int in_buf = 0;
1222 while (in_buf < count) {
1223 ut64 offset_in_data = offset - rebase_info->start_of_data;
1224 ut64 page_index = offset_in_data / rebase_info->page_size;
1225 ut64 page_offset = offset_in_data % rebase_info->page_size;
1226 ut64 to_next_page = rebase_info->page_size - page_offset;
1227
1228 if (page_index >= rebase_info->page_starts_count) {
1229 goto next_page;
1230 }
1231 ut64 delta = rebase_info->page_starts[page_index];
1232
1233 if (delta == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE) {
1234 goto next_page;
1235 }
1236
1237 ut64 first_rebase_off = delta;
1238 if (first_rebase_off >= page_offset && first_rebase_off < page_offset + count) {
1239 do {
1240 ut64 position = in_buf + first_rebase_off - page_offset;
1241 if (position >= count) {
1242 break;
1243 }
1244 ut64 raw_value = r_read_le64 (buf + position);
1245 delta = ((raw_value & rebase_info->delta_mask) >> rebase_info->delta_shift) * 8;
1246 if (position >= start_of_write) {
1247 ut64 new_value = 0;
1248 if (R_IS_PTR_AUTHENTICATED (raw_value)) {
1249 new_value = (raw_value & 0xFFFFFFFFULL) + rebase_info->auth_value_add;
1250 // TODO: don't throw auth info away
1251 } else {
1252 new_value = ((raw_value << 13) & 0xFF00000000000000ULL) | (raw_value & 0x7ffffffffffULL);
1253 new_value &= 0x00FFFFFFFFFFFFFFULL;
1254 }
1255 if (new_value != 0) {
1256 new_value += rebase_info->slide;
1257 }
1258 r_write_le64 (buf + position, new_value);
1259 }
1260 first_rebase_off += delta;
1261 } while (delta);
1262 }
1263 next_page:
1264 in_buf += to_next_page;
1265 offset += to_next_page;
1266 }
1267 }
1268
rebase_info_by_range(RDyldRebaseInfos * infos,ut64 offset,int count)1269 static RDyldRebaseInfo *rebase_info_by_range(RDyldRebaseInfos *infos, ut64 offset, int count) {
1270 int imid;
1271 int imin = 0;
1272 int imax = infos->length - 1;
1273
1274 while (imin < imax) {
1275 imid = (imin + imax) / 2;
1276 RDyldRebaseInfosEntry *entry = &infos->entries[imid];
1277 if ((entry->end) <= offset) {
1278 imin = imid + 1;
1279 } else {
1280 imax = imid;
1281 }
1282 }
1283
1284 RDyldRebaseInfosEntry *minEntry = &infos->entries[imin];
1285 if ((imax == imin) && (minEntry->start <= offset + count) && (minEntry->end >= offset)) {
1286 return minEntry->info;
1287 }
1288 return NULL;
1289 }
1290
rebase_bytes(RDyldRebaseInfo * rebase_info,ut8 * buf,ut64 offset,int count,ut64 start_of_write)1291 static void rebase_bytes(RDyldRebaseInfo *rebase_info, ut8 *buf, ut64 offset, int count, ut64 start_of_write) {
1292 if (!rebase_info || !buf) {
1293 return;
1294 }
1295
1296 if (rebase_info->version == 3) {
1297 rebase_bytes_v3 ((RDyldRebaseInfo3*) rebase_info, buf, offset, count, start_of_write);
1298 } else if (rebase_info->version == 2 || rebase_info->version == 4) {
1299 rebase_bytes_v2 ((RDyldRebaseInfo2*) rebase_info, buf, offset, count, start_of_write);
1300 } else if (rebase_info->version == 1) {
1301 rebase_bytes_v1 ((RDyldRebaseInfo1*) rebase_info, buf, offset, count, start_of_write);
1302 }
1303 }
1304
dyldcache_io_read(RIO * io,RIODesc * fd,ut8 * buf,int count)1305 static int dyldcache_io_read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
1306 r_return_val_if_fail (io, -1);
1307 RCore *core = (RCore*) io->corebind.core;
1308
1309 if (!core || !core->bin || !core->bin->binfiles) {
1310 return -1;
1311 }
1312
1313 RDyldCache *cache = NULL;
1314 RListIter *iter;
1315 RBinFile *bf;
1316 r_list_foreach (core->bin->binfiles, iter, bf) {
1317 if (bf->fd == fd->fd ) {
1318 if (!strncmp ((char*) bf->o->bin_obj, "dyldcac", 7)) {
1319 cache = bf->o->bin_obj;
1320 } else {
1321 cache = ((struct MACH0_(obj_t)*) bf->o->bin_obj)->user;
1322 }
1323 if (pending_bin_files) {
1324 RListIter *to_remove = r_list_contains (pending_bin_files, bf);
1325 if (to_remove) {
1326 r_list_delete (pending_bin_files, to_remove);
1327 if (r_list_empty (pending_bin_files)) {
1328 r_list_free (pending_bin_files);
1329 pending_bin_files = NULL;
1330 }
1331 }
1332 }
1333 break;
1334 }
1335 }
1336 if (!cache) {
1337 r_list_foreach (pending_bin_files, iter, bf) {
1338 if (bf->fd == fd->fd && bf->o) {
1339 if (!strncmp ((char*) bf->o->bin_obj, "dyldcac", 7)) {
1340 cache = bf->o->bin_obj;
1341 } else {
1342 cache = ((struct MACH0_(obj_t)*) bf->o->bin_obj)->user;
1343 }
1344 break;
1345 }
1346 }
1347 }
1348 if (!cache || !cache->original_io_read) {
1349 if (fd->plugin->read == &dyldcache_io_read) {
1350 return -1;
1351 }
1352 return fd->plugin->read (io, fd, buf, count);
1353 }
1354
1355 RDyldRebaseInfo *rebase_info = rebase_info_by_range (cache->rebase_infos, io->off, count);
1356
1357 int result = 0;
1358
1359 if (rebase_info && count > 0) {
1360 ut64 offset_in_data = io->off - rebase_info->start_of_data;
1361 ut64 page_offset = offset_in_data % rebase_info->page_size;
1362
1363 ut64 internal_offset = io->off & ~(rebase_info->page_size - 1);
1364 ut64 internal_end = io->off + count;
1365 int rounded_count = internal_end - internal_offset;
1366
1367 ut8 *internal_buf = rebase_info->one_page_buf;
1368 if (rounded_count > rebase_info->page_size) {
1369 internal_buf = malloc (rounded_count);
1370 if (!internal_buf) {
1371 eprintf ("Cannot allocate memory for 'internal_buf'\n");
1372 return -1;
1373 }
1374 }
1375
1376 ut64 original_off = io->off;
1377 io->off = internal_offset;
1378
1379 int internal_result = cache->original_io_read (io, fd, internal_buf, rounded_count);
1380
1381 io->off = original_off;
1382
1383 if (internal_result >= page_offset + count) {
1384 rebase_bytes (rebase_info, internal_buf, internal_offset, internal_result, page_offset);
1385 result = R_MIN (count, internal_result);
1386 memcpy (buf, internal_buf + page_offset, result);
1387 } else {
1388 eprintf ("ERROR rebasing\n");
1389 result = cache->original_io_read (io, fd, buf, count);
1390 }
1391
1392 if (internal_buf != rebase_info->one_page_buf) {
1393 R_FREE (internal_buf);
1394 }
1395 } else {
1396 result = cache->original_io_read (io, fd, buf, count);
1397 }
1398
1399 return result;
1400 }
1401
swizzle_io_read(RDyldCache * cache,RIO * io)1402 static void swizzle_io_read(RDyldCache *cache, RIO *io) {
1403 if (!io || !io->desc || !io->desc->plugin) {
1404 return;
1405 }
1406
1407 RIOPlugin *plugin = io->desc->plugin;
1408 cache->original_io_read = plugin->read;
1409 plugin->read = &dyldcache_io_read;
1410 }
1411
read_cache_header(RBuffer * cache_buf)1412 static cache_hdr_t *read_cache_header(RBuffer *cache_buf) {
1413 if (!cache_buf) {
1414 return NULL;
1415 }
1416
1417 cache_hdr_t *hdr = R_NEW0 (cache_hdr_t);
1418 if (!hdr) {
1419 return NULL;
1420 }
1421
1422 ut64 size = sizeof (cache_hdr_t);
1423 if (r_buf_fread_at (cache_buf, 0, (ut8*) hdr, "16c4i7l16clii4l", 1) != size) {
1424 R_FREE (hdr);
1425 return NULL;
1426 }
1427
1428 return hdr;
1429 }
1430
read_cache_maps(RBuffer * cache_buf,cache_hdr_t * hdr)1431 static cache_map_t *read_cache_maps(RBuffer *cache_buf, cache_hdr_t *hdr) {
1432 if (!cache_buf || !hdr || !hdr->mappingCount || !hdr->mappingOffset) {
1433 return NULL;
1434 }
1435
1436 ut64 size = sizeof (cache_map_t) * hdr->mappingCount;
1437 cache_map_t *maps = R_NEWS0 (cache_map_t, hdr->mappingCount);
1438 if (!maps) {
1439 return NULL;
1440 }
1441
1442 if (r_buf_fread_at (cache_buf, hdr->mappingOffset, (ut8*) maps, "3l2i", hdr->mappingCount) != size) {
1443 R_FREE (maps);
1444 return NULL;
1445 }
1446
1447 return maps;
1448 }
1449
read_cache_accel(RBuffer * cache_buf,cache_hdr_t * hdr,cache_map_t * maps)1450 static cache_accel_t *read_cache_accel(RBuffer *cache_buf, cache_hdr_t *hdr, cache_map_t *maps) {
1451 if (!cache_buf || !hdr || !hdr->accelerateInfoSize || !hdr->accelerateInfoAddr) {
1452 return NULL;
1453 }
1454
1455 ut64 offset = va2pa (hdr->accelerateInfoAddr, hdr, maps, cache_buf, 0, NULL, NULL);
1456 if (!offset) {
1457 return NULL;
1458 }
1459
1460 ut64 size = sizeof (cache_accel_t);
1461 cache_accel_t *accel = R_NEW0 (cache_accel_t);
1462 if (!accel) {
1463 return NULL;
1464 }
1465
1466 if (r_buf_fread_at (cache_buf, offset, (ut8*) accel, "16il", 1) != size) {
1467 R_FREE (accel);
1468 return NULL;
1469 }
1470
1471 accel->imagesExtrasOffset += offset;
1472 accel->bottomUpListOffset += offset;
1473 accel->dylibTrieOffset += offset;
1474 accel->initializersOffset += offset;
1475 accel->dofSectionsOffset += offset;
1476 accel->reExportListOffset += offset;
1477 accel->depListOffset += offset;
1478 accel->rangeTableOffset += offset;
1479
1480 return accel;
1481 }
1482
load_buffer(RBinFile * bf,void ** bin_obj,RBuffer * buf,ut64 loadaddr,Sdb * sdb)1483 static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadaddr, Sdb *sdb) {
1484 RDyldCache *cache = R_NEW0 (RDyldCache);
1485 memcpy (cache->magic, "dyldcac", 7);
1486 cache->buf = r_buf_ref (buf);
1487 cache->hdr = read_cache_header (cache->buf);
1488 if (!cache->hdr) {
1489 r_dyldcache_free (cache);
1490 return false;
1491 }
1492 cache->maps = read_cache_maps (cache->buf, cache->hdr);
1493 if (!cache->maps) {
1494 r_dyldcache_free (cache);
1495 return false;
1496 }
1497 cache->accel = read_cache_accel (cache->buf, cache->hdr, cache->maps);
1498 cache->locsym = r_dyld_locsym_new (cache->buf, cache->hdr);
1499 if (!cache->locsym) {
1500 r_dyldcache_free (cache);
1501 return false;
1502 }
1503 cache->bins = create_cache_bins (bf, cache->buf, cache->hdr, cache->maps, cache->accel);
1504 if (!cache->bins) {
1505 r_dyldcache_free (cache);
1506 return false;
1507 }
1508 cache->rebase_infos = get_rebase_infos (bf, cache);
1509 if (cache->rebase_infos) {
1510 if (!rebase_infos_get_slide (cache)) {
1511 if (!pending_bin_files) {
1512 pending_bin_files = r_list_new ();
1513 if (!pending_bin_files) {
1514 r_dyldcache_free (cache);
1515 return false;
1516 }
1517 }
1518 r_list_push (pending_bin_files, bf);
1519 swizzle_io_read (cache, bf->rbin->iob.io);
1520 }
1521 }
1522 *bin_obj = cache;
1523 return true;
1524 }
1525
entries(RBinFile * bf)1526 static RList *entries(RBinFile *bf) {
1527 RBinAddr *ptr = NULL;
1528 RList *ret = r_list_newf (free);
1529 if (!ret) {
1530 return NULL;
1531 }
1532 if ((ptr = R_NEW0 (RBinAddr))) {
1533 r_list_append (ret, ptr);
1534 }
1535 return ret;
1536 }
1537
info(RBinFile * bf)1538 static RBinInfo *info(RBinFile *bf) {
1539 RBinInfo *ret = NULL;
1540
1541 if (!bf || !bf->o) {
1542 return NULL;
1543 }
1544
1545 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
1546 if (!cache) {
1547 return NULL;
1548 }
1549
1550 bool big_endian = 0;
1551 if (!(ret = R_NEW0 (RBinInfo))) {
1552 return NULL;
1553 }
1554 ret->file = strdup (bf->file);
1555 ret->bclass = strdup ("dyldcache");
1556 ret->rclass = strdup ("ios");
1557 ret->os = strdup ("iOS");
1558 ret->arch = strdup ("arm"); // XXX
1559 ret->machine = strdup (ret->arch);
1560 ret->subsystem = strdup ("xnu");
1561 ret->type = strdup ("library-cache");
1562 bool dyld64 = strstr(cache->hdr->magic, "arm64") != NULL;
1563 ret->bits = dyld64? 64: 32;
1564 ret->has_va = true;
1565 ret->big_endian = big_endian;
1566 ret->dbg_info = 0;
1567 return ret;
1568 }
1569
1570 #if 0
1571 static void parse_mach0 (RList *ret, ut64 paddr, RBinFile *bf) {
1572 // TODO
1573 }
1574 #endif
1575
baddr(RBinFile * bf)1576 static ut64 baddr(RBinFile *bf) {
1577 // XXX hardcoded
1578 return 0x180000000;
1579 }
1580
symbols_from_bin(RList * ret,RBinFile * bf,RDyldBinImage * bin,SetU * hash)1581 void symbols_from_bin(RList *ret, RBinFile *bf, RDyldBinImage *bin, SetU *hash) {
1582 struct MACH0_(obj_t) *mach0 = bin_to_mach0 (bf, bin);
1583 if (!mach0) {
1584 return;
1585 }
1586
1587 // const RList*symbols = MACH0_(get_symbols_list) (mach0);
1588 const struct symbol_t *symbols = MACH0_(get_symbols) (mach0);
1589 if (!symbols) {
1590 return;
1591 }
1592 int i;
1593 for (i = 0; !symbols[i].last; i++) {
1594 if (!symbols[i].name[0] || symbols[i].addr < 100) {
1595 continue;
1596 }
1597 if (strstr (symbols[i].name, "<redacted>")) {
1598 continue;
1599 }
1600 RBinSymbol *sym = R_NEW0 (RBinSymbol);
1601 if (!sym) {
1602 break;
1603 }
1604 sym->name = strdup (symbols[i].name);
1605 sym->vaddr = symbols[i].addr;
1606 sym->forwarder = "NONE";
1607 sym->bind = (symbols[i].type == R_BIN_MACH0_SYMBOL_TYPE_LOCAL)? R_BIN_BIND_LOCAL_STR: R_BIN_BIND_GLOBAL_STR;
1608 sym->type = R_BIN_TYPE_FUNC_STR;
1609 sym->paddr = symbols[i].offset + bf->o->boffset;
1610 sym->size = symbols[i].size;
1611 sym->ordinal = i;
1612
1613 set_u_add (hash, sym->vaddr);
1614 r_list_append (ret, sym);
1615 }
1616 MACH0_(mach0_free) (mach0);
1617 }
1618
__is_data_section(const char * name)1619 static bool __is_data_section(const char *name) {
1620 if (strstr (name, "_cstring")) {
1621 return true;
1622 }
1623 if (strstr (name, "_os_log")) {
1624 return true;
1625 }
1626 if (strstr (name, "_objc_methname")) {
1627 return true;
1628 }
1629 if (strstr (name, "_objc_classname")) {
1630 return true;
1631 }
1632 if (strstr (name, "_objc_methtype")) {
1633 return true;
1634 }
1635 return false;
1636 }
1637
sections_from_bin(RList * ret,RBinFile * bf,RDyldBinImage * bin)1638 static void sections_from_bin(RList *ret, RBinFile *bf, RDyldBinImage *bin) {
1639 struct MACH0_(obj_t) *mach0 = bin_to_mach0 (bf, bin);
1640 if (!mach0) {
1641 return;
1642 }
1643
1644 struct section_t *sections = NULL;
1645 if (!(sections = MACH0_(get_sections) (mach0))) {
1646 return;
1647 }
1648
1649 int i;
1650 for (i = 0; !sections[i].last; i++) {
1651 RBinSection *ptr = R_NEW0 (RBinSection);
1652 if (!ptr) {
1653 break;
1654 }
1655 if (bin->file) {
1656 ptr->name = r_str_newf ("%s.%s", bin->file, (char*)sections[i].name);
1657 } else {
1658 ptr->name = r_str_newf ("%s", (char*)sections[i].name);
1659 }
1660 if (strstr (ptr->name, "la_symbol_ptr")) {
1661 int len = sections[i].size / 8;
1662 ptr->format = r_str_newf ("Cd %d[%d]", 8, len);
1663 }
1664 ptr->is_data = __is_data_section (ptr->name);
1665 ptr->size = sections[i].size;
1666 ptr->vsize = sections[i].vsize;
1667 ptr->paddr = sections[i].offset + bf->o->boffset;
1668 ptr->vaddr = sections[i].addr;
1669 if (!ptr->vaddr) {
1670 ptr->vaddr = ptr->paddr;
1671 }
1672 ptr->perm = sections[i].perm;
1673 r_list_append (ret, ptr);
1674 }
1675 free (sections);
1676 MACH0_(mach0_free) (mach0);
1677 }
1678
sections(RBinFile * bf)1679 static RList *sections(RBinFile *bf) {
1680 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
1681 if (!cache) {
1682 return NULL;
1683 }
1684
1685 RList *ret = r_list_newf (free);
1686 if (!ret) {
1687 return NULL;
1688 }
1689
1690 RListIter *iter;
1691 RDyldBinImage *bin;
1692 r_list_foreach (cache->bins, iter, bin) {
1693 sections_from_bin (ret, bf, bin);
1694 }
1695
1696 RBinSection *ptr = NULL;
1697 int i;
1698 for (i = 0; i < cache->hdr->mappingCount; i++) {
1699 if (!(ptr = R_NEW0 (RBinSection))) {
1700 return NULL;
1701 }
1702 ptr->name = r_str_newf ("cache_map.%d", i);
1703 ptr->size = cache->maps[i].size;
1704 ptr->vsize = ptr->size;
1705 ptr->paddr = cache->maps[i].fileOffset;
1706 ptr->vaddr = cache->maps[i].address;
1707 ptr->add = true;
1708 ptr->is_segment = true;
1709 ptr->perm = prot2perm (cache->maps[i].initProt);
1710 r_list_append (ret, ptr);
1711 }
1712
1713 ut64 slide = rebase_infos_get_slide (cache);
1714 if (slide) {
1715 RBinSection *section;
1716 r_list_foreach (ret, iter, section) {
1717 section->vaddr += slide;
1718 }
1719 }
1720
1721 return ret;
1722 }
1723
symbols(RBinFile * bf)1724 static RList *symbols(RBinFile *bf) {
1725 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
1726 if (!cache) {
1727 return NULL;
1728 }
1729
1730 RList *ret = r_list_newf (free);
1731 if (!ret) {
1732 return NULL;
1733 }
1734
1735 RListIter *iter;
1736 RDyldBinImage *bin;
1737 r_list_foreach (cache->bins, iter, bin) {
1738 SetU *hash = set_u_new ();
1739 if (!hash) {
1740 r_list_free (ret);
1741 return NULL;
1742 }
1743 symbols_from_bin (ret, bf, bin, hash);
1744 r_dyld_locsym_entries_by_offset (cache, ret, hash, bin->header_at);
1745 set_u_free (hash);
1746 }
1747
1748 ut64 slide = rebase_infos_get_slide (cache);
1749 if (slide) {
1750 RBinSymbol *sym;
1751 r_list_foreach (ret, iter, sym) {
1752 sym->vaddr += slide;
1753 }
1754 }
1755
1756 return ret;
1757 }
1758
1759 /* static void unswizzle_io_read(RDyldCache *cache, RIO *io) {
1760 if (!io || !io->desc || !io->desc->plugin || !cache->original_io_read) {
1761 return;
1762 }
1763
1764 RIOPlugin *plugin = io->desc->plugin;
1765 plugin->read = cache->original_io_read;
1766 cache->original_io_read = NULL;
1767 } */
1768
destroy(RBinFile * bf)1769 static void destroy(RBinFile *bf) {
1770 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
1771 // unswizzle_io_read (cache, bf->rbin->iob.io); // XXX io may be dead here
1772 r_dyldcache_free (cache);
1773 }
1774
classes(RBinFile * bf)1775 static RList *classes(RBinFile *bf) {
1776 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
1777 if (!cache) {
1778 return NULL;
1779 }
1780
1781 RList *ret = r_list_newf (free);
1782 if (!ret) {
1783 return NULL;
1784 }
1785
1786 RListIter *iter;
1787 RDyldBinImage *bin;
1788
1789 RBuffer *orig_buf = bf->buf;
1790 ut32 num_of_unnamed_class = 0;
1791 r_list_foreach (cache->bins, iter, bin) {
1792 struct MACH0_(obj_t) *mach0 = bin_to_mach0 (bf, bin);
1793 if (!mach0) {
1794 goto beach;
1795 }
1796
1797 struct section_t *sections = NULL;
1798 if (!(sections = MACH0_(get_sections) (mach0))) {
1799 MACH0_(mach0_free) (mach0);
1800 goto beach;
1801 }
1802
1803 int i;
1804 for (i = 0; !sections[i].last; i++) {
1805 if (sections[i].size == 0) {
1806 continue;
1807 }
1808
1809 bool is_classlist = strstr (sections[i].name, "__objc_classlist");
1810 bool is_catlist = strstr (sections[i].name, "__objc_catlist");
1811
1812 if (!is_classlist && !is_catlist) {
1813 continue;
1814 }
1815
1816 ut8 *pointers = malloc (sections[i].size);
1817 if (r_buf_read_at (cache->buf, sections[i].offset, pointers, sections[i].size) < sections[i].size) {
1818 R_FREE (pointers);
1819 continue;
1820 }
1821 ut8 *cursor = pointers;
1822 ut8 *pointers_end = pointers + sections[i].size;
1823
1824 for (; cursor < pointers_end; cursor += 8) {
1825 ut64 pointer_to_class = r_read_le64 (cursor);
1826
1827 RBinClass *klass;
1828 if (!(klass = R_NEW0 (RBinClass)) ||
1829 !(klass->methods = r_list_new ()) ||
1830 !(klass->fields = r_list_new ())) {
1831 R_FREE (klass);
1832 R_FREE (pointers);
1833 R_FREE (sections);
1834 MACH0_(mach0_free) (mach0);
1835 goto beach;
1836 }
1837
1838 bf->o->bin_obj = mach0;
1839 bf->buf = cache->buf;
1840 if (is_classlist) {
1841 MACH0_(get_class_t) ((ut64) pointer_to_class, bf, klass, false, NULL);
1842 } else {
1843 MACH0_(get_category_t) ((ut64) pointer_to_class, bf, klass, NULL);
1844 }
1845 bf->o->bin_obj = cache;
1846 bf->buf = orig_buf;
1847
1848 if (!klass->name) {
1849 klass->name = r_str_newf ("UnnamedClass%u", num_of_unnamed_class);
1850 if (!klass->name) {
1851 R_FREE (klass);
1852 R_FREE (pointers);
1853 R_FREE (sections);
1854 MACH0_(mach0_free) (mach0);
1855 goto beach;
1856 }
1857 num_of_unnamed_class++;
1858 }
1859 r_list_append (ret, klass);
1860 }
1861
1862 R_FREE (pointers);
1863 }
1864
1865 R_FREE (sections);
1866 MACH0_(mach0_free) (mach0);
1867 }
1868
1869 return ret;
1870
1871 beach:
1872 r_list_free (ret);
1873 return NULL;
1874 }
1875
header(RBinFile * bf)1876 static void header(RBinFile *bf) {
1877 if (!bf || !bf->o) {
1878 return;
1879 }
1880
1881 RDyldCache *cache = (RDyldCache*) bf->o->bin_obj;
1882 if (!cache) {
1883 return;
1884 }
1885
1886 RBin *bin = bf->rbin;
1887 ut64 slide = rebase_infos_get_slide (cache);
1888 PrintfCallback p = bin->cb_printf;
1889
1890 PJ *pj = pj_new ();
1891 if (!pj) {
1892 return;
1893 }
1894
1895 pj_o (pj);
1896 pj_k (pj, "header");
1897 pj_o (pj);
1898 pj_ks (pj, "magic", cache->hdr->magic);
1899 pj_kn (pj, "mappingOffset", cache->hdr->mappingOffset);
1900 pj_kn (pj, "mappingCount", cache->hdr->mappingCount);
1901 pj_kn (pj, "imagesOffset", cache->hdr->imagesOffset);
1902 pj_kn (pj, "imagesCount", cache->hdr->imagesCount);
1903 pj_kn (pj, "dyldBaseAddress", cache->hdr->dyldBaseAddress);
1904 pj_kn (pj, "codeSignatureOffset", cache->hdr->codeSignatureOffset);
1905 pj_kn (pj, "codeSignatureSize", cache->hdr->codeSignatureSize);
1906 pj_kn (pj, "slideInfoOffset", cache->hdr->slideInfoOffset);
1907 pj_kn (pj, "slideInfoSize", cache->hdr->slideInfoSize);
1908 pj_kn (pj, "localSymbolsOffset", cache->hdr->localSymbolsOffset);
1909 pj_kn (pj, "localSymbolsSize", cache->hdr->localSymbolsSize);
1910 char uuidstr[128];
1911 r_hex_bin2str ((ut8*)cache->hdr->uuid, 16, uuidstr);
1912 pj_ks (pj, "uuid", uuidstr);
1913 pj_ks (pj, "cacheType", (cache->hdr->cacheType == 0) ? "development" : "production");
1914 pj_kn (pj, "branchPoolsOffset", cache->hdr->branchPoolsOffset);
1915 pj_kn (pj, "branchPoolsCount", cache->hdr->branchPoolsCount);
1916 pj_kn (pj, "accelerateInfoAddr", cache->hdr->accelerateInfoAddr + slide);
1917 pj_kn (pj, "accelerateInfoSize", cache->hdr->accelerateInfoSize);
1918 pj_kn (pj, "imagesTextOffset", cache->hdr->imagesTextOffset);
1919 pj_kn (pj, "imagesTextCount", cache->hdr->imagesTextCount);
1920 pj_end (pj);
1921
1922 if (cache->accel) {
1923 pj_k (pj, "accelerator");
1924 pj_o (pj);
1925 pj_kn (pj, "version", cache->accel->version);
1926 pj_kn (pj, "imageExtrasCount", cache->accel->imageExtrasCount);
1927 pj_kn (pj, "imagesExtrasOffset", cache->accel->imagesExtrasOffset);
1928 pj_kn (pj, "bottomUpListOffset", cache->accel->bottomUpListOffset);
1929 pj_kn (pj, "dylibTrieOffset", cache->accel->dylibTrieOffset);
1930 pj_kn (pj, "dylibTrieSize", cache->accel->dylibTrieSize);
1931 pj_kn (pj, "initializersOffset", cache->accel->initializersOffset);
1932 pj_kn (pj, "initializersCount", cache->accel->initializersCount);
1933 pj_kn (pj, "dofSectionsOffset", cache->accel->dofSectionsOffset);
1934 pj_kn (pj, "dofSectionsCount", cache->accel->dofSectionsCount);
1935 pj_kn (pj, "reExportListOffset", cache->accel->reExportListOffset);
1936 pj_kn (pj, "reExportCount", cache->accel->reExportCount);
1937 pj_kn (pj, "depListOffset", cache->accel->depListOffset);
1938 pj_kn (pj, "depListCount", cache->accel->depListCount);
1939 pj_kn (pj, "rangeTableOffset", cache->accel->rangeTableOffset);
1940 pj_kn (pj, "rangeTableCount", cache->accel->rangeTableCount);
1941 pj_kn (pj, "dyldSectionAddr", cache->accel->dyldSectionAddr + slide);
1942 pj_end (pj);
1943 }
1944
1945 if (cache->rebase_infos) {
1946 size_t i;
1947 pj_k (pj, "slideInfo");
1948 pj_a (pj);
1949 for (i = 0; i < cache->rebase_infos->length; i++) {
1950 RDyldRebaseInfo * rebase_info = cache->rebase_infos->entries[i].info;
1951 pj_o (pj);
1952 pj_kn (pj, "start", cache->rebase_infos->entries[i].start);
1953 pj_kn (pj, "end", cache->rebase_infos->entries[i].end);
1954 if (rebase_info) {
1955 ut8 version = rebase_info->version;
1956 pj_kn (pj, "version", version);
1957 pj_kn (pj, "slide", slide);
1958 if (version == 3) {
1959 RDyldRebaseInfo3 *info3 = (RDyldRebaseInfo3*) rebase_info;
1960 pj_kn (pj, "page_starts_count", info3->page_starts_count);
1961 pj_kn (pj, "page_size", info3->page_size);
1962 pj_kn (pj, "auth_value_add", info3->auth_value_add);
1963 } else if (version == 2 || version == 4) {
1964 RDyldRebaseInfo2 *info2 = (RDyldRebaseInfo2*) rebase_info;
1965 pj_kn (pj, "page_starts_count", info2->page_starts_count);
1966 pj_kn (pj, "page_extras_count", info2->page_extras_count);
1967 pj_kn (pj, "delta_mask", info2->delta_mask);
1968 pj_kn (pj, "value_mask", info2->value_mask);
1969 pj_kn (pj, "delta_shift", info2->delta_shift);
1970 pj_kn (pj, "page_size", info2->page_size);
1971 } else if (version == 1) {
1972 RDyldRebaseInfo1 *info1 = (RDyldRebaseInfo1*) rebase_info;
1973 pj_kn (pj, "toc_count", info1->toc_count);
1974 pj_kn (pj, "entries_size", info1->entries_size);
1975 pj_kn (pj, "page_size", 4096);
1976 }
1977 }
1978 pj_end (pj);
1979 }
1980 pj_end (pj);
1981 }
1982
1983 if (cache->hdr->imagesTextCount) {
1984 pj_k (pj, "images");
1985 pj_a (pj);
1986 ut64 total_size = cache->hdr->imagesTextCount * sizeof (cache_text_info_t);
1987 cache_text_info_t * text_infos = malloc (total_size);
1988 if (!text_infos) {
1989 goto beach;
1990 }
1991 if (r_buf_fread_at (cache->buf, cache->hdr->imagesTextOffset, (ut8*)text_infos, "16clii", cache->hdr->imagesTextCount) != total_size) {
1992 free (text_infos);
1993 goto beach;
1994 }
1995 size_t i;
1996 for (i = 0; i != cache->hdr->imagesTextCount; i++) {
1997 cache_text_info_t * text_info = &text_infos[i];
1998 r_hex_bin2str ((ut8*)text_info->uuid, 16, uuidstr);
1999 pj_o (pj);
2000 pj_ks (pj, "uuid", uuidstr);
2001 pj_kn (pj, "address", text_info->loadAddress + slide);
2002 pj_kn (pj, "textSegmentSize", text_info->textSegmentSize);
2003 char file[256];
2004 if (r_buf_read_at (cache->buf, text_info->pathOffset, (ut8*) &file, sizeof (file)) == sizeof (file)) {
2005 file[255] = 0;
2006 pj_ks (pj, "path", file);
2007 char *last_slash = strrchr (file, '/');
2008 if (last_slash && *last_slash) {
2009 pj_ks (pj, "name", last_slash + 1);
2010 } else {
2011 pj_ks (pj, "name", file);
2012 }
2013 }
2014 pj_end (pj);
2015 }
2016 pj_end (pj);
2017 free (text_infos);
2018 }
2019
2020 pj_end (pj);
2021 p ("%s", pj_string (pj));
2022
2023 beach:
2024 pj_free (pj);
2025 }
2026
2027 RBinPlugin r_bin_plugin_dyldcache = {
2028 .name = "dyldcache",
2029 .desc = "dyldcache bin plugin",
2030 .license = "LGPL3",
2031 .load_buffer = &load_buffer,
2032 .entries = &entries,
2033 .baddr = &baddr,
2034 .symbols = &symbols,
2035 .sections = §ions,
2036 .check_buffer = &check_buffer,
2037 .destroy = &destroy,
2038 .classes = &classes,
2039 .header = &header,
2040 .info = &info,
2041 };
2042
2043 #ifndef R2_PLUGIN_INCORE
2044 R_API RLibStruct radare_plugin = {
2045 .type = R_LIB_TYPE_BIN,
2046 .data = &r_bin_plugin_dyldcache,
2047 .version = R2_VERSION
2048 };
2049 #endif
2050