Rizin
unix-like reverse engineering framework and cli tools
bin_mach0.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_types.h>
5 #include <rz_util.h>
6 #include <rz_lib.h>
7 #include <rz_bin.h>
8 #include <rz_core.h>
9 #include "../i/private.h"
10 #include "mach0/mach0.h"
11 #include "objc/mach0_classes.h"
12 #include <ht_uu.h>
13 
14 // wip settings
15 
16 static RzBinInfo *info(RzBinFile *bf);
17 
18 static Sdb *get_sdb(RzBinFile *bf) {
19  RzBinObject *o = bf->o;
20  if (!o) {
21  return NULL;
22  }
23  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)o->bin_obj;
24  return bin ? bin->kv : NULL;
25 }
26 
27 static char *entitlements(RzBinFile *bf, bool json) {
28  rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, NULL);
29  struct MACH0_(obj_t) *bin = bf->o->bin_obj;
30  if (!bin->signature) {
31  return NULL;
32  }
33  if (json) {
34  PJ *pj = pj_new();
35  pj_s(pj, (const char *)bin->signature);
36  return pj_drain(pj);
37  } else {
38  return rz_str_dup(NULL, (const char *)bin->signature);
39  }
40 }
41 
42 static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
43  rz_return_val_if_fail(bf && obj && buf, false);
44  struct MACH0_(opts_t) opts;
46  (&opts, bf);
47  struct MACH0_(obj_t) *res = MACH0_(new_buf)(buf, &opts);
48  if (res) {
49  sdb_ns_set(sdb, "info", res->kv);
50  obj->bin_obj = res;
51  return true;
52  }
53  return false;
54 }
55 
56 static void destroy(RzBinFile *bf) {
58  (bf->o->bin_obj);
59 }
60 
61 static ut64 baddr(RzBinFile *bf) {
62  rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, UT64_MAX);
63  struct MACH0_(obj_t) *bin = bf->o->bin_obj;
64  return MACH0_(get_baddr)(bin);
65 }
66 
68  return MACH0_(get_virtual_files)(bf);
69 }
70 
71 static RzList *maps(RzBinFile *bf) {
72  return MACH0_(get_maps)(bf);
73 }
74 
75 static RzList *sections(RzBinFile *bf) {
76  return MACH0_(get_segments)(bf);
77 }
78 
79 static RzBinAddr *newEntry(ut64 hpaddr, ut64 paddr, int type, int bits) {
80  RzBinAddr *ptr = RZ_NEW0(RzBinAddr);
81  if (ptr) {
82  ptr->paddr = paddr;
83  ptr->vaddr = paddr;
84  ptr->hpaddr = hpaddr;
85  ptr->bits = bits;
86  ptr->type = type;
87  // realign due to thumb
88  if (bits == 16 && ptr->vaddr & 1) {
89  ptr->paddr--;
90  ptr->vaddr--;
91  }
92  }
93  return ptr;
94 }
95 
96 static void process_constructors(RzBinFile *bf, RzList *ret, int bits) {
97  RzList *secs = sections(bf);
99  RzBinSection *sec;
100  int i, type;
101  rz_list_foreach (secs, iter, sec) {
102  type = -1;
103  if (strstr(sec->name, "_mod_fini_func")) {
105  } else if (strstr(sec->name, "_mod_init_func")) {
107  }
108  if (type != -1) {
109  ut8 *buf = calloc(sec->size, 1);
110  if (!buf) {
111  continue;
112  }
113  int read = rz_buf_read_at(bf->buf, sec->paddr, buf, sec->size);
114  if (read < sec->size) {
115  RZ_LOG_ERROR("process_constructors: cannot process section %s\n", sec->name);
116  continue;
117  }
118  if (bits == 32) {
119  for (i = 0; i + 3 < sec->size; i += 4) {
120  ut32 addr32 = rz_read_le32(buf + i);
121  RzBinAddr *ba = newEntry(sec->paddr + i, (ut64)addr32, type, bits);
122  if (ba) {
123  rz_list_append(ret, ba);
124  }
125  }
126  } else {
127  for (i = 0; i + 7 < sec->size; i += 8) {
128  ut64 addr64 = rz_read_le64(buf + i);
129  RzBinAddr *ba = newEntry(sec->paddr + i, addr64, type, bits);
130  if (ba) {
131  rz_list_append(ret, ba);
132  }
133  }
134  }
135  free(buf);
136  }
137  }
138 }
139 
140 static RzList *entries(RzBinFile *bf) {
141  rz_return_val_if_fail(bf && bf->o, NULL);
142 
143  RzBinAddr *ptr = NULL;
144  struct addr_t *entry = NULL;
145 
146  RzList *ret = rz_list_newf(free);
147  if (!ret) {
148  return NULL;
149  }
150 
151  int bits = MACH0_(get_bits)(bf->o->bin_obj);
152  if (!(entry = MACH0_(get_entrypoint)(bf->o->bin_obj))) {
153  return ret;
154  }
155  if ((ptr = RZ_NEW0(RzBinAddr))) {
156  ptr->paddr = entry->offset + bf->o->boffset;
157  ptr->vaddr = entry->addr;
158  ptr->hpaddr = entry->haddr;
159  ptr->bits = bits;
160  // realign due to thumb
161  if (bits == 16) {
162  if (ptr->vaddr & 1) {
163  ptr->paddr--;
164  ptr->vaddr--;
165  }
166  }
167  rz_list_append(ret, ptr);
168  }
169 
170  process_constructors(bf, ret, bits);
171  // constructors
172  free(entry);
173  return ret;
174 }
175 
176 static void _handle_arm_thumb(struct MACH0_(obj_t) * bin, RzBinSymbol **p) {
177  RzBinSymbol *ptr = *p;
178  if (bin) {
179  if (ptr->paddr & 1) {
180  ptr->paddr--;
181  ptr->vaddr--;
182  ptr->bits = 16;
183  }
184  }
185 }
186 
187 #if FEATURE_SYMLIST
188 static RzList *symbols(RzBinFile *bf) {
189  RzBinObject *obj = bf ? bf->o : NULL;
190  return (RzList *)MACH0_(get_symbols_list)(obj->bin_obj);
191 }
192 #else
193 static RzList *symbols(RzBinFile *bf) {
194  struct MACH0_(obj_t) * bin;
195  int i;
196  const struct symbol_t *syms = NULL;
197  RzBinSymbol *ptr = NULL;
198  RzBinObject *obj = bf ? bf->o : NULL;
200 #if 0
201  const char *lang = "c"; // XXX deprecate this
202 #endif
203  int wordsize = 0;
204  if (!ret) {
205  return NULL;
206  }
207  if (!obj || !obj->bin_obj) {
208  free(ret);
209  return NULL;
210  }
211  bool isStripped = false;
212  wordsize = MACH0_(get_bits)(obj->bin_obj);
213 
214  // OLD CODE
215  if (!(syms = MACH0_(get_symbols)(obj->bin_obj))) {
216  return ret;
217  }
218  SetU *symcache = set_u_new();
219  bin = (struct MACH0_(obj_t) *)obj->bin_obj;
220  for (i = 0; !syms[i].last; i++) {
221  if (syms[i].name == NULL || syms[i].name[0] == '\0' || syms[i].addr < 100) {
222  continue;
223  }
224  if (!(ptr = RZ_NEW0(RzBinSymbol))) {
225  break;
226  }
227  ptr->name = strdup((char *)syms[i].name);
228  ptr->is_imported = syms[i].is_imported;
229  if (ptr->name[0] == '_' && !ptr->is_imported) {
230  char *dn = rz_bin_demangle(bf, ptr->name, ptr->name, ptr->vaddr, false);
231  if (dn) {
232  ptr->dname = dn;
233  char *p = strchr(dn, '.');
234  if (p) {
235  if (IS_UPPER(ptr->name[0])) {
236  ptr->classname = strdup(ptr->name);
237  ptr->classname[p - ptr->name] = 0;
238  } else if (IS_UPPER(p[1])) {
239  ptr->classname = strdup(p + 1);
240  p = strchr(ptr->classname, '.');
241  if (p) {
242  *p = 0;
243  }
244  }
245  }
246  }
247  }
248  ptr->forwarder = "NONE";
250  ptr->type = RZ_BIN_TYPE_FUNC_STR;
251  ptr->vaddr = syms[i].addr;
252  ptr->paddr = syms[i].offset + obj->boffset;
253  ptr->size = syms[i].size;
254  ptr->bits = syms[i].bits;
255  if (bin->hdr.cputype == CPU_TYPE_ARM && wordsize < 64) {
256  _handle_arm_thumb(bin, &ptr);
257  }
258  ptr->ordinal = i;
259  bin->dbg_info = strncmp(ptr->name, "radr://", 7) ? 0 : 1;
260  set_u_add(symcache, ptr->vaddr);
261 #if 0
262  if (!strncmp (ptr->name, "__Z", 3)) {
263  lang = "c++";
264  }
265  if (!strncmp (ptr->name, "type.", 5)) {
266  lang = "go";
267  } else if (!strcmp (ptr->name, "_rust_oom")) {
268  lang = "rust";
269  }
270 #endif
271  rz_list_append(ret, ptr);
272  }
273  // functions from LC_FUNCTION_STARTS
274  if (bin->func_start) {
275  ut64 value = 0, address = 0;
276  const ut8 *temp = bin->func_start;
277  const ut8 *temp_end = bin->func_start + bin->func_size;
278  while (temp + 3 < temp_end && *temp) {
279  temp = rz_uleb128_decode(temp, NULL, &value);
280  address += value;
281  ptr = RZ_NEW0(RzBinSymbol);
282  if (!ptr) {
283  break;
284  }
285  ptr->vaddr = bin->baddr + address;
286  ptr->paddr = address;
287  ptr->size = 0;
288  ptr->name = rz_str_newf("func.%08" PFMT64x, ptr->vaddr);
289  ptr->type = RZ_BIN_TYPE_FUNC_STR;
290  ptr->forwarder = "NONE";
292  ptr->ordinal = i++;
293  if (bin->hdr.cputype == CPU_TYPE_ARM && wordsize < 64) {
294  _handle_arm_thumb(bin, &ptr);
295  }
296  rz_list_append(ret, ptr);
297  // if any func is not found in syms then we can consider it is stripped
298  if (!isStripped) {
299  if (!set_u_contains(symcache, ptr->vaddr)) {
300  isStripped = true;
301  }
302  }
303  }
304  }
305 #if 0
306 // this must be done in bobj.c not here
307  if (bin->has_blocks_ext) {
308  lang = !strcmp (lang, "c++") ? "c++ blocks ext." : "c blocks ext.";
309  }
310  bin->lang = lang;
311 #endif
312  if (isStripped) {
313  bin->dbg_info |= RZ_BIN_DBG_STRIPPED;
314  }
315  set_u_free(symcache);
316  return ret;
317 }
318 #endif // FEATURE_SYMLIST
319 
320 static RzBinImport *import_from_name(RzBin *rbin, const char *orig_name, HtPP *imports_by_name) {
321  if (imports_by_name) {
322  bool found = false;
323  RzBinImport *ptr = ht_pp_find(imports_by_name, orig_name, &found);
324  if (found) {
325  return ptr;
326  }
327  }
328 
329  RzBinImport *ptr = NULL;
330  if (!(ptr = RZ_NEW0(RzBinImport))) {
331  return NULL;
332  }
333 
334  char *name = (char *)orig_name;
335  const char *_objc_class = "_OBJC_CLASS_$";
336  const int _objc_class_len = strlen(_objc_class);
337  const char *_objc_metaclass = "_OBJC_METACLASS_$";
338  const int _objc_metaclass_len = strlen(_objc_metaclass);
339  char *type = "FUNC";
340 
341  if (!strncmp(name, _objc_class, _objc_class_len)) {
342  name += _objc_class_len;
343  type = "OBJC_CLASS";
344  } else if (!strncmp(name, _objc_metaclass, _objc_metaclass_len)) {
345  name += _objc_metaclass_len;
346  type = "OBJC_METACLASS";
347  }
348 
349  // Remove the extra underscore that every import seems to have in Mach-O.
350  if (*name == '_') {
351  name++;
352  }
353  ptr->name = strdup(name);
354  ptr->bind = "NONE";
355  ptr->type = rz_str_constpool_get(&rbin->constpool, type);
356 
357  if (imports_by_name) {
358  ht_pp_insert(imports_by_name, orig_name, ptr);
359  }
360 
361  return ptr;
362 }
363 
364 static RzList *imports(RzBinFile *bf) {
365  RzBinObject *obj = bf ? bf->o : NULL;
366  struct MACH0_(obj_t) *bin = bf ? bf->o->bin_obj : NULL;
367  const char *name;
368  RzBinImport *ptr = NULL;
369  int i;
370 
371  if (!obj || !bin || !obj->bin_obj) {
372  return NULL;
373  }
375  struct import_t *imports = MACH0_(get_imports)(bf->o->bin_obj);
376  if (!ret || !imports) {
377  rz_list_free(ret);
378  free(imports);
379  return NULL;
380  }
381  bin->has_canary = false;
382  bin->has_retguard = -1;
383  bin->has_sanitizers = false;
384  bin->has_blocks_ext = false;
385  for (i = 0; !imports[i].last; i++) {
386  if (!(ptr = import_from_name(bf->rbin, imports[i].name, NULL))) {
387  break;
388  }
389  name = ptr->name;
390  ptr->ordinal = imports[i].ord;
391  if (bin->imports_by_ord && ptr->ordinal < bin->imports_by_ord_size) {
392  bin->imports_by_ord[ptr->ordinal] = ptr;
393  }
394  if (!strcmp(name, "__stack_chk_fail")) {
395  bin->has_canary = true;
396  }
397  if (!strcmp(name, "__asan_init") ||
398  !strcmp(name, "__tsan_init")) {
399  bin->has_sanitizers = true;
400  }
401  if (!strcmp(name, "_NSConcreteGlobalBlock")) {
402  bin->has_blocks_ext = true;
403  }
404  rz_list_append(ret, ptr);
405  }
406  free(imports);
407  return ret;
408 }
409 
410 static RzList *relocs(RzBinFile *bf) {
411  RzList *ret = NULL;
412  struct MACH0_(obj_t) *bin = NULL;
413  RzBinObject *obj = bf ? bf->o : NULL;
414  if (bf && bf->o) {
415  bin = bf->o->bin_obj;
416  }
417  if (!obj || !obj->bin_obj || !(ret = rz_list_newf(free))) {
418  return NULL;
419  }
420  ret->free = free;
421 
423  if (!(relocs = MACH0_(get_relocs)(bf->o->bin_obj))) {
424  return ret;
425  }
426 
427  RzSkipListNode *it;
428  struct reloc_t *reloc;
429  rz_skiplist_foreach (relocs, it, reloc) {
430  RzBinReloc *ptr = NULL;
431  if (!(ptr = RZ_NEW0(RzBinReloc))) {
432  break;
433  }
434  ptr->type = reloc->type;
435  ptr->additive = 0;
436  if (reloc->name[0]) {
437  RzBinImport *imp;
438  if (!(imp = import_from_name(bf->rbin, (char *)reloc->name, bin->imports_by_name))) {
439  free(ptr);
440  break;
441  }
442  ptr->import = imp;
443  } else if (reloc->ord >= 0 && bin->imports_by_ord && reloc->ord < bin->imports_by_ord_size) {
444  ptr->import = bin->imports_by_ord[reloc->ord];
445  } else {
446  ptr->import = NULL;
447  }
448  ptr->addend = reloc->addend;
449  ptr->vaddr = reloc->addr;
450  ptr->paddr = reloc->offset;
451  ptr->target_vaddr = reloc->target;
452  rz_list_append(ret, ptr);
453  }
454 
455  return ret;
456 }
457 
458 static RzList *libs(RzBinFile *bf) {
459  int i;
460  char *ptr = NULL;
461  struct lib_t *libs;
462  RzList *ret = NULL;
463  RzBinObject *obj = bf ? bf->o : NULL;
464 
465  if (!obj || !obj->bin_obj || !(ret = rz_list_newf(free))) {
466  return NULL;
467  }
468  if ((libs = MACH0_(get_libs)(obj->bin_obj))) {
469  for (i = 0; !libs[i].last; i++) {
470  ptr = strdup(libs[i].name);
471  rz_list_append(ret, ptr);
472  }
473  free(libs);
474  }
475  return ret;
476 }
477 
478 static RzBinInfo *info(RzBinFile *bf) {
479  struct MACH0_(obj_t) *bin = NULL;
480  char *str;
481 
482  rz_return_val_if_fail(bf && bf->o, NULL);
483  RzBinInfo *ret = RZ_NEW0(RzBinInfo);
484  if (!ret) {
485  return NULL;
486  }
487 
488  bin = bf->o->bin_obj;
489  if (bf->file) {
490  ret->file = strdup(bf->file);
491  }
492  if ((str = MACH0_(get_class)(bf->o->bin_obj))) {
493  ret->bclass = str;
494  }
495  if (bin) {
496  ret->has_canary = bin->has_canary;
497  ret->has_retguard = -1;
498  ret->has_sanitizers = bin->has_sanitizers;
499  ret->dbg_info = bin->dbg_info;
500  ret->lang = bin->lang;
501  }
502  ret->intrp = rz_str_dup(NULL, MACH0_(get_intrp)(bf->o->bin_obj));
503  ret->compiler = rz_str_dup(NULL, "");
504  ret->rclass = strdup("mach0");
505  ret->os = strdup(MACH0_(get_os)(bf->o->bin_obj));
506  ret->subsystem = strdup("darwin");
507  ret->arch = strdup(MACH0_(get_cputype)(bf->o->bin_obj));
508  ret->machine = MACH0_(get_cpusubtype)(bf->o->bin_obj);
509  ret->type = MACH0_(get_filetype)(bf->o->bin_obj);
510  ret->big_endian = MACH0_(is_big_endian)(bf->o->bin_obj);
511  ret->bits = 32;
512  if (bf && bf->o && bf->o->bin_obj) {
513  ret->has_crypto = ((struct MACH0_(obj_t) *)
514  bf->o->bin_obj)
515  ->has_crypto;
516  ret->bits = MACH0_(get_bits)(bf->o->bin_obj);
517  }
518  ret->has_va = true;
519  ret->has_pi = MACH0_(is_pie)(bf->o->bin_obj);
520  ret->has_nx = MACH0_(has_nx)(bf->o->bin_obj);
521 
522  return ret;
523 }
524 
525 static RzList *classes(RzBinFile *bf) {
526  return MACH0_(parse_classes)(bf, NULL);
527 }
528 
529 #if !RZ_BIN_MACH064
530 
531 static bool check_buffer(RzBuffer *b) {
532  if (rz_buf_size(b) >= 4) {
533  ut8 buf[4] = { 0 };
534  if (rz_buf_read_at(b, 0, buf, 4)) {
535  if (!memcmp(buf, "\xce\xfa\xed\xfe", 4) ||
536  !memcmp(buf, "\xfe\xed\xfa\xce", 4)) {
537  return true;
538  }
539  }
540  }
541  return false;
542 }
543 
544 static RzBuffer *create(RzBin *bin, const ut8 *code, int clen, const ut8 *data, int dlen, RzBinArchOptions *opt) {
545  const bool use_pagezero = true;
546  const bool use_main = true;
547  const bool use_dylinker = true;
548  const bool use_libsystem = true;
549  const bool use_linkedit = true;
550  ut32 filesize, codeva, datava;
551  ut32 ncmds, cmdsize, magiclen;
552  ut32 p_codefsz = 0, p_codeva = 0, p_codesz = 0, p_codepa = 0;
553  ut32 p_datafsz = 0, p_datava = 0, p_datasz = 0, p_datapa = 0;
554  ut32 p_cmdsize = 0, p_entry = 0, p_tmp = 0;
555  ut32 baddr = 0x1000;
556 
557  rz_return_val_if_fail(bin && opt, NULL);
558 
559  bool is_arm = strstr(opt->arch, "arm");
561 #ifndef RZ_BIN_MACH064
562  if (opt->bits == 64) {
563  RZ_LOG_ERROR("Please use mach064 instead of mach0\n");
564  free(buf);
565  return NULL;
566  }
567 #endif
568 
569 #define B(x, y) rz_buf_append_bytes(buf, (const ut8 *)(x), y)
570 #define D(x) rz_buf_append_ut32(buf, x)
571 #define Z(x) rz_buf_append_nbytes(buf, x)
572 #define W(x, y, z) rz_buf_write_at(buf, x, (const ut8 *)(y), z)
573 #define WZ(x, y) \
574  p_tmp = rz_buf_size(buf); \
575  Z(x); \
576  W(p_tmp, y, strlen(y))
577 
578  /* MACH0 HEADER */
579  B("\xce\xfa\xed\xfe", 4); // header
580  // 64bit header B ("\xce\xfa\xed\xfe", 4); // header
581  if (is_arm) {
582  D(12); // cpu type (arm)
583  D(3); // subtype (all?)
584  } else {
585  /* x86-32 */
586  D(7); // cpu type (x86)
587  // D(0x1000007); // x86-64
588  D(3); // subtype (i386-all)
589  }
590  D(2); // filetype (executable)
591 
592  if (data && dlen > 0) {
593  ncmds = 3;
594  cmdsize = 0;
595  } else {
596  ncmds = 2;
597  cmdsize = 0;
598  }
599  if (use_pagezero) {
600  ncmds++;
601  }
602  if (use_dylinker) {
603  ncmds++;
604  if (use_linkedit) {
605  ncmds += 3;
606  }
607  if (use_libsystem) {
608  ncmds++;
609  }
610  }
611 
612  /* COMMANDS */
613  D(ncmds); // ncmds
614  p_cmdsize = rz_buf_size(buf);
615  D(-1); // cmdsize
616  D(0); // flags
617  // D (0x01200085); // alternative flags found in some a.out..
618  magiclen = rz_buf_size(buf);
619 
620  if (use_pagezero) {
621  /* PAGEZERO */
622  D(1); // cmd.LC_SEGMENT
623  D(56); // sizeof (cmd)
624  WZ(16, "__PAGEZERO");
625  D(0); // vmaddr
626  D(0x00001000); // vmsize XXX
627  D(0); // fileoff
628  D(0); // filesize
629  D(0); // maxprot
630  D(0); // initprot
631  D(0); // nsects
632  D(0); // flags
633  }
634 
635  /* TEXT SEGMENT */
636  D(1); // cmd.LC_SEGMENT
637  D(124); // sizeof (cmd)
638  WZ(16, "__TEXT");
639  D(baddr); // vmaddr
640  D(0x1000); // vmsize XXX
641  D(0); // fileoff
642  p_codefsz = rz_buf_size(buf);
643  D(-1); // filesize
644  D(7); // maxprot
645  D(5); // initprot
646  D(1); // nsects
647  D(0); // flags
648  WZ(16, "__text");
649  WZ(16, "__TEXT");
650  p_codeva = rz_buf_size(buf); // virtual address
651  D(-1);
652  p_codesz = rz_buf_size(buf); // size of code (end-start)
653  D(-1);
654  p_codepa = rz_buf_size(buf); // code - baddr
655  D(-1); //_start-0x1000);
656  D(0); // align // should be 2 for 64bit
657  D(0); // reloff
658  D(0); // nrelocs
659  D(0); // flags
660  D(0); // reserved
661  D(0); // ??
662 
663  if (data && dlen > 0) {
664  /* DATA SEGMENT */
665  D(1); // cmd.LC_SEGMENT
666  D(124); // sizeof (cmd)
667  p_tmp = rz_buf_size(buf);
668  Z(16);
669  W(p_tmp, "__TEXT", 6); // segment name
670  D(0x2000); // vmaddr
671  D(0x1000); // vmsize
672  D(0); // fileoff
673  p_datafsz = rz_buf_size(buf);
674  D(-1); // filesize
675  D(6); // maxprot
676  D(6); // initprot
677  D(1); // nsects
678  D(0); // flags
679 
680  WZ(16, "__data");
681  WZ(16, "__DATA");
682 
683  p_datava = rz_buf_size(buf);
684  D(-1);
685  p_datasz = rz_buf_size(buf);
686  D(-1);
687  p_datapa = rz_buf_size(buf);
688  D(-1); //_start-0x1000);
689  D(2); // align
690  D(0); // reloff
691  D(0); // nrelocs
692  D(0); // flags
693  D(0); // reserved
694  D(0);
695  }
696 
697  if (use_dylinker) {
698  if (use_linkedit) {
699  /* LINKEDIT */
700  D(1); // cmd.LC_SEGMENT
701  D(56); // sizeof (cmd)
702  WZ(16, "__LINKEDIT");
703  D(0x3000); // vmaddr
704  D(0x00001000); // vmsize XXX
705  D(0x1000); // fileoff
706  D(0); // filesize
707  D(7); // maxprot
708  D(1); // initprot
709  D(0); // nsects
710  D(0); // flags
711 
712  /* LC_SYMTAB */
713  D(2); // cmd.LC_SYMTAB
714  D(24); // sizeof (cmd)
715  D(0x1000); // symtab offset
716  D(0); // symtab size
717  D(0x1000); // strtab offset
718  D(0); // strtab size
719 
720  /* LC_DYSYMTAB */
721  D(0xb); // cmd.LC_DYSYMTAB
722  D(80); // sizeof (cmd)
723  Z(18 * sizeof(ut32)); // empty
724  }
725 
726  const char *dyld = "/usr/lib/dyld";
727  const int dyld_len = strlen(dyld) + 1;
728  D(0xe); /* LC_DYLINKER */
729  D((4 * 3) + dyld_len);
730  D(dyld_len - 2);
731  WZ(dyld_len, dyld); // path
732 
733  if (use_libsystem) {
734  /* add libSystem at least ... */
735  const char *lib = "/usr/lib/libSystem.B.dylib";
736  const int lib_len = strlen(lib) + 1;
737  D(0xc); /* LC_LOAD_DYLIB */
738  D(24 + lib_len); // cmdsize
739  D(24); // offset where the lib string start
740  D(0x2);
741  D(0x1);
742  D(0x1);
743  WZ(lib_len, lib);
744  }
745  }
746 
747  if (use_main) {
748  /* LC_MAIN */
749  D(0x80000028); // cmd.LC_MAIN
750  D(24); // sizeof (cmd)
751  D(baddr); // entryoff
752  D(0); // stacksize
753  D(0); // ???
754  D(0); // ???
755  } else {
756  /* THREAD STATE */
757  D(5); // LC_UNIXTHREAD
758  D(80); // sizeof (cmd)
759  if (is_arm) {
760  /* arm */
761  D(1); // i386-thread-state
762  D(17); // thread-state-count
763  p_entry = rz_buf_size(buf) + (16 * sizeof(ut32));
764  Z(17 * sizeof(ut32));
765  // mach0-arm has one byte more
766  } else {
767  /* x86-32 */
768  D(1); // i386-thread-state
769  D(16); // thread-state-count
770  p_entry = rz_buf_size(buf) + (10 * sizeof(ut32));
771  Z(16 * sizeof(ut32));
772  }
773  }
774 
775  /* padding to make mach_loader checks happy */
776  /* binaries must be at least of 4KB :( not tiny anymore */
777  WZ(4096 - rz_buf_size(buf), "");
778 
779  cmdsize = rz_buf_size(buf) - magiclen;
780  codeva = rz_buf_size(buf) + baddr;
781  datava = rz_buf_size(buf) + clen + baddr;
782  if (p_entry != 0) {
783  W(p_entry, &codeva, 4); // set PC
784  }
785 
786  /* fill header variables */
787  W(p_cmdsize, &cmdsize, 4);
788  filesize = magiclen + cmdsize + clen + dlen;
789  // TEXT SEGMENT should span the whole file //
790  W(p_codefsz, &filesize, 4);
791  W(p_codefsz - 8, &filesize, 4); // vmsize = filesize
792  W(p_codeva, &codeva, 4);
793  // clen = 4096;
794  W(p_codesz, &clen, 4);
795  p_tmp = codeva - baddr;
796  W(p_codepa, &p_tmp, 4);
797 
798  B(code, clen);
799 
800  if (data && dlen > 0) {
801  /* append data */
802  W(p_datafsz, &filesize, 4);
803  W(p_datava, &datava, 4);
804  W(p_datasz, &dlen, 4);
805  p_tmp = datava - baddr;
806  W(p_datapa, &p_tmp, 4);
807  B(data, dlen);
808  }
809 
810  return buf;
811 }
812 
814  ut64 addr;
815  RzBinAddr *ret = NULL;
816  switch (sym) {
818  addr = MACH0_(get_main)(bf->o->bin_obj);
819  if (addr == UT64_MAX || !(ret = RZ_NEW0(RzBinAddr))) {
820  return NULL;
821  }
822  // if (bf->o->info && bf->o->info->bits == 16) {
823  // align for thumb
824  ret->vaddr = ((addr >> 1) << 1);
825  //}
826  ret->paddr = ret->vaddr;
827  break;
828  default:
829  break;
830  }
831  return ret;
832 }
833 
834 static ut64 size(RzBinFile *bf) {
835  ut64 off = 0;
836  ut64 len = 0;
837  if (!bf->o->sections) {
838  RzListIter *iter;
840  bf->o->sections = sections(bf);
841  rz_list_foreach (bf->o->sections, iter, section) {
842  if (section->paddr > off) {
843  off = section->paddr;
844  len = section->size;
845  }
846  }
847  }
848  return off + len;
849 }
850 
851 static RzList *strings(RzBinFile *bf) {
852  return rz_bin_file_strings(bf, 4, false);
853 }
854 
856  .name = "mach0",
857  .desc = "mach0 bin plugin",
858  .license = "LGPL3",
859  .get_sdb = &get_sdb,
860  .load_buffer = &load_buffer,
861  .destroy = &destroy,
862  .check_buffer = &check_buffer,
863  .baddr = &baddr,
864  .binsym = &binsym,
865  .entries = &entries,
866  .signature = &entitlements,
867  .virtual_files = &virtual_files,
868  .maps = &maps,
869  .sections = &sections,
870  .symbols = &symbols,
871  .imports = &imports,
872  .strings = &strings,
873  .size = &size,
874  .info = &info,
875  .header = MACH0_(mach_headerfields),
876  .fields = MACH0_(mach_fields),
877  .libs = &libs,
878  .relocs = &relocs,
879  .create = &create,
880  .classes = &classes,
881  .section_type_to_string = &MACH0_(section_type_to_string),
882  .section_flag_to_rzlist = &MACH0_(section_flag_to_rzlist)
883 };
884 
885 #ifndef RZ_PLUGIN_INCORE
888  .data = &rz_bin_plugin_mach0,
890 };
891 #endif
892 #endif
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
RZ_API RZ_OWN RzList * rz_bin_file_strings(RZ_NONNULL RzBinFile *bf, size_t min_length, bool raw_strings)
Generates a RzList struct containing RzBinString from a given RzBinFile.
Definition: bfile_string.c:325
RZ_API void rz_bin_symbol_free(RzBinSymbol *sym)
Definition: bin.c:175
RZ_API void rz_bin_import_free(RzBinImport *imp)
Definition: bin.c:137
RZ_API RZ_OWN char * rz_bin_demangle(RZ_NULLABLE RzBinFile *bf, RZ_NULLABLE const char *language, RZ_NULLABLE const char *symbol, ut64 vaddr, bool libs)
Demangles a symbol based on the language or the RzBinFile data.
Definition: bin.c:1295
static RzBinAddr * binsym(RzBinFile *bf, RzBinSpecialSymbol sym)
Definition: bin_mach0.c:813
#define W(x, y, z)
static void _handle_arm_thumb(struct MACH0_(obj_t) *bin, RzBinSymbol **p)
Definition: bin_mach0.c:176
static void process_constructors(RzBinFile *bf, RzList *ret, int bits)
Definition: bin_mach0.c:96
static Sdb * get_sdb(RzBinFile *bf)
Definition: bin_mach0.c:18
static RzList * classes(RzBinFile *bf)
Definition: bin_mach0.c:525
RzBinPlugin rz_bin_plugin_mach0
Definition: bin_mach0.c:855
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb)
Definition: bin_mach0.c:42
static RzList * symbols(RzBinFile *bf)
Definition: bin_mach0.c:193
#define WZ(x, y)
static ut64 size(RzBinFile *bf)
Definition: bin_mach0.c:834
static RzList * libs(RzBinFile *bf)
Definition: bin_mach0.c:458
static RzList * strings(RzBinFile *bf)
Definition: bin_mach0.c:851
static void destroy(RzBinFile *bf)
Definition: bin_mach0.c:56
#define Z(x)
RZ_API RzLibStruct rizin_plugin
Definition: bin_mach0.c:886
static bool check_buffer(RzBuffer *b)
Definition: bin_mach0.c:531
static RzBinAddr * newEntry(ut64 hpaddr, ut64 paddr, int type, int bits)
Definition: bin_mach0.c:79
static RzList * virtual_files(RzBinFile *bf)
Definition: bin_mach0.c:67
#define B(x, y)
static ut64 baddr(RzBinFile *bf)
Definition: bin_mach0.c:61
static RzList * entries(RzBinFile *bf)
Definition: bin_mach0.c:140
static RzList * maps(RzBinFile *bf)
Definition: bin_mach0.c:71
static char * entitlements(RzBinFile *bf, bool json)
Definition: bin_mach0.c:27
static RzBuffer * create(RzBin *bin, const ut8 *code, int clen, const ut8 *data, int dlen, RzBinArchOptions *opt)
Definition: bin_mach0.c:544
static RzBinInfo * info(RzBinFile *bf)
Definition: bin_mach0.c:478
static RzBinImport * import_from_name(RzBin *rbin, const char *orig_name, HtPP *imports_by_name)
Definition: bin_mach0.c:320
static RzList * sections(RzBinFile *bf)
Definition: bin_mach0.c:75
static RzList * imports(RzBinFile *bf)
Definition: bin_mach0.c:364
static RzList * relocs(RzBinFile *bf)
Definition: bin_mach0.c:410
#define D(x)
int bits(struct state *s, int need)
Definition: blast.c:72
static int value
Definition: cmd_api.c:93
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
RzList *MACH0_() mach_fields(RzBinFile *bf)
Definition: mach0.c:3969
const char *MACH0_() get_intrp(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3320
RzList *MACH0_() get_maps(RzBinFile *bf)
Definition: mach0.c:2252
RzList *MACH0_() get_segments(RzBinFile *bf)
Definition: mach0.c:2267
char *MACH0_() section_type_to_string(ut64 type)
Definition: mach0.c:2347
const RzList *MACH0_() get_symbols_list(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2761
char *MACH0_() get_class(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3277
RzList *MACH0_() section_flag_to_rzlist(ut64 flag)
Definition: mach0.c:2378
void MACH0_() mach_headerfields(RzBinFile *bf)
Definition: mach0.c:3633
char *MACH0_() get_filetype(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3578
struct lib_t *MACH0_() get_libs(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3242
char *MACH0_() get_cpusubtype(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3546
const struct symbol_t *MACH0_() get_symbols(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2959
ut64 MACH0_() get_main(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3582
bool MACH0_() is_big_endian(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3312
ut64 MACH0_() get_baddr(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3262
void *MACH0_() mach0_free(struct MACH0_(obj_t) *mo)
Definition: mach0.c:2057
bool MACH0_() has_nx(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3554
bool MACH0_() is_pie(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3550
RzList *MACH0_() get_virtual_files(RzBinFile *bf)
Definition: mach0.c:2162
const char *MACH0_() get_cputype(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3383
struct import_t *MACH0_() get_imports(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3146
const char *MACH0_() get_os(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3324
void MACH0_() opts_set_default(struct MACH0_(opts_t) *options, RzBinFile *bf)
Definition: mach0.c:2103
struct addr_t *MACH0_() get_entrypoint(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3196
RZ_BORROW RzSkipList *MACH0_() get_relocs(struct MACH0_(obj_t) *bin)
Definition: mach0_relocs.c:120
RZ_API RzList *MACH0_() parse_classes(RzBinFile *bf, objc_cache_opt_info *oi)
@ CPU_TYPE_ARM
#define MACH0_(name)
Definition: mach0_specs.h:20
#define RZ_BIN_MACH0_SYMBOL_TYPE_LOCAL
Definition: mach0_specs.h:26
int type
Definition: mipsasm.c:17
RZ_API int sdb_ns_set(Sdb *s, const char *name, Sdb *r)
Definition: ns.c:156
const char * name
Definition: op.c:541
int off
Definition: pal.c:13
static int is_arm(RzBinPEObj *bin)
Definition: pe_info.c:12
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define RZ_BIN_DBG_STRIPPED
Definition: rz_bin.h:27
#define RZ_BIN_ENTRY_TYPE_FINI
Definition: rz_bin.h:36
RzBinSpecialSymbol
Definition: rz_bin.h:136
@ RZ_BIN_SPECIAL_SYMBOL_MAIN
Definition: rz_bin.h:139
#define RZ_BIN_ENTRY_TYPE_INIT
Definition: rz_bin.h:35
#define RZ_BIN_BIND_LOCAL_STR
Definition: rz_bin.h:106
#define RZ_BIN_BIND_GLOBAL_STR
Definition: rz_bin.h:107
#define RZ_BIN_TYPE_FUNC_STR
Definition: rz_bin.h:119
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_bytes(RZ_NULLABLE RZ_BORROW const ut8 *bytes, ut64 len)
Creates a new buffer with a bytes array.
Definition: buf.c:465
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
static ut32 rz_read_le32(const void *src)
Definition: rz_endian.h:239
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
@ RZ_LIB_TYPE_BIN
Definition: rz_lib.h:75
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API char * pj_drain(PJ *j)
Definition: pj.c:50
RZ_API PJ * pj_s(PJ *j, const char *k)
Definition: pj.c:197
#define rz_skiplist_foreach(list, it, pos)
Definition: rz_skiplist.h:48
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_dup(char *ptr, const char *string)
Definition: str.c:1021
RZ_API const char * rz_str_constpool_get(RzStrConstPool *pool, const char *str)
Definition: str_constpool.c:19
#define IS_UPPER(c)
Definition: rz_str_util.h:14
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT64x
Definition: rz_types.h:393
#define UT64_MAX
Definition: rz_types_base.h:86
RZ_API const ut8 * rz_uleb128_decode(const ut8 *data, int *datalen, ut64 *v)
Definition: uleb128.c:71
#define RZ_VERSION
Definition: rz_version.h:8
RZ_API SetU * set_u_new(void)
Definition: set.c:30
RZ_API void set_u_free(SetU *s)
Definition: set.c:46
RZ_API void set_u_add(SetU *s, ut64 u)
Definition: set.c:34
RZ_API bool set_u_contains(SetU *s, ut64 u)
Definition: set.c:38
HtUP SetU
Definition: set.h:22
#define b(i)
Definition: sha256.c:42
Definition: mach0.h:85
Definition: malloc.c:26
Definition: inftree9.h:24
Definition: zipcmp.c:77
Definition: mach0.h:65
Definition: mach0.h:92
Definition: z80asm.h:102
Definition: rz_pj.h:12
Definition: mach0.h:71
ut64 target
Definition: mach0.h:82
ut64 addr
Definition: mach0.h:73
char name[256]
Definition: mach0.h:78
int ord
Definition: mach0.h:76
ut64 offset
Definition: mach0.h:72
ut8 type
Definition: mach0.h:75
st64 addend
Definition: mach0.h:74
ut64 vaddr
Definition: rz_bin.h:186
ut64 paddr
Definition: rz_bin.h:187
ut64 hpaddr
Definition: rz_bin.h:189
const char * arch
Definition: rz_bin.h:414
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RzBinObject * o
Definition: rz_bin.h:305
struct rz_bin_t * rbin
Definition: rz_bin.h:316
char * file
Definition: rz_bin.h:299
RzBuffer * buf
Definition: rz_bin.h:303
const char * type
Definition: rz_bin.h:704
const char * bind
Definition: rz_bin.h:703
ut32 ordinal
Definition: rz_bin.h:707
char * name
Definition: rz_bin.h:701
int has_va
Definition: rz_bin.h:228
char * type
Definition: rz_bin.h:211
int has_crypto
Definition: rz_bin.h:233
char * intrp
Definition: rz_bin.h:243
int has_canary
Definition: rz_bin.h:230
char * os
Definition: rz_bin.h:219
char * subsystem
Definition: rz_bin.h:220
int has_pi
Definition: rz_bin.h:229
int has_nx
Definition: rz_bin.h:234
char * machine
Definition: rz_bin.h:216
const char * lang
Definition: rz_bin.h:224
char * bclass
Definition: rz_bin.h:212
char * file
Definition: rz_bin.h:210
ut64 dbg_info
Definition: rz_bin.h:240
int has_retguard
Definition: rz_bin.h:231
char * rclass
Definition: rz_bin.h:213
char * arch
Definition: rz_bin.h:214
char * compiler
Definition: rz_bin.h:244
int has_sanitizers
Definition: rz_bin.h:232
int big_endian
Definition: rz_bin.h:235
ut64 boffset
Definition: rz_bin.h:262
void * bin_obj
Definition: rz_bin.h:293
RzList * sections
Definition: rz_bin.h:267
char * name
Definition: rz_bin.h:509
char * version
Definition: rz_bin.h:512
ut64 paddr
the paddr where the value should be patched into
Definition: rz_bin.h:717
RzBinRelocType type
Definition: rz_bin.h:712
ut64 vaddr
the vaddr where the value should be patched into
Definition: rz_bin.h:716
ut64 target_vaddr
the target address that the patched reloc points to
Definition: rz_bin.h:718
RzBinImport * import
Definition: rz_bin.h:714
bool additive
Definition: rz_bin.h:720
st64 addend
Definition: rz_bin.h:715
char * name
Definition: rz_bin.h:619
const char * bind
Definition: rz_bin.h:681
bool is_imported
Definition: rz_bin.h:684
const char * type
Definition: rz_bin.h:682
char * name
Definition: rz_bin.h:675
char * classname
Definition: rz_bin.h:678
ut32 ordinal
Definition: rz_bin.h:692
char * dname
Definition: rz_bin.h:676
const char * forwarder
Definition: rz_bin.h:680
RzStrConstPool constpool
Definition: rz_bin.h:362
RzListFree free
Definition: rz_list.h:21
Definition: sdb.h:63
uint32_t size
Definition: mach0.h:54
bool last
Definition: mach0.h:62
bool is_imported
Definition: mach0.h:60
ut64 size
Definition: mach0.h:57
ut64 addr
Definition: mach0.h:56
int bits
Definition: mach0.h:58
ut64 offset
Definition: mach0.h:55
int type
Definition: mach0.h:59
#define get_bits(av, af, an)
Definition: tms320_dasm.c:18
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115