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 = &sections,
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