1 /* radare - LGPL - Copyright 2010-2020 - nibble, pancake */
2 
3 #include <stdio.h>
4 #include <r_types.h>
5 #include <r_util.h>
6 #include "mach0.h"
7 #include <r_hash.h>
8 
9 // TODO: deprecate bprintf and use Eprintf (bin->self)
10 #define bprintf if (bin->verbose) eprintf
11 #define Eprintf if (mo->verbose) eprintf
12 
13 typedef struct {
14 	struct symbol_t *symbols;
15 	int j;
16 	int symbols_count;
17 	HtPP *hash;
18 } RSymCtx;
19 
20 typedef void (*RExportsIterator)(struct MACH0_(obj_t) *bin, const char *name, ut64 flags, ut64 offset, void *ctx);
21 
22 typedef struct {
23 	ut8 *node;
24 	char *label;
25 	int i;
26 	ut8 *next_child;
27 } RTrieState;
28 
29 // OMG; THIS SHOULD BE KILLED; this var exposes the local native endian, which is completely unnecessary
30 // USE THIS: int ws = bf->o->info->big_endian;
31 #define mach0_endian 1
32 
read_uleb128(ut8 ** p,ut8 * end)33 static ut64 read_uleb128(ut8 **p, ut8 *end) {
34 	const char *error = NULL;
35 	ut64 v;
36 	*p = (ut8 *)r_uleb128 (*p, end - *p, &v, &error);
37 	if (error) {
38 		eprintf ("%s", error);
39 		R_FREE (error);
40 		return UT64_MAX;
41 	}
42 	return v;
43 }
44 
entry_to_vaddr(struct MACH0_ (obj_t)* bin)45 static ut64 entry_to_vaddr(struct MACH0_(obj_t) *bin) {
46 	switch (bin->main_cmd.cmd) {
47 	case LC_MAIN:
48 		return bin->entry + bin->baddr;
49 	case LC_UNIXTHREAD:
50 	case LC_THREAD:
51 		return bin->entry;
52 	default:
53 		return 0;
54 	}
55 }
56 
addr_to_offset(struct MACH0_ (obj_t)* bin,ut64 addr)57 static ut64 addr_to_offset(struct MACH0_(obj_t) *bin, ut64 addr) {
58 	if (bin->segs) {
59 		size_t i;
60 		for (i = 0; i < bin->nsegs; i++) {
61 			const ut64 segment_base = (ut64)bin->segs[i].vmaddr;
62 			const ut64 segment_size = (ut64)bin->segs[i].vmsize;
63 			if (addr >= segment_base && addr < segment_base + segment_size) {
64 				return bin->segs[i].fileoff + (addr - segment_base);
65 			}
66 		}
67 	}
68 	return 0;
69 }
70 
offset_to_vaddr(struct MACH0_ (obj_t)* bin,ut64 offset)71 static ut64 offset_to_vaddr(struct MACH0_(obj_t) *bin, ut64 offset) {
72 	if (bin->segs) {
73 		size_t i;
74 		for (i = 0; i < bin->nsegs; i++) {
75 			ut64 segment_base = (ut64)bin->segs[i].fileoff;
76 			ut64 segment_size = (ut64)bin->segs[i].filesize;
77 			if (offset >= segment_base && offset < segment_base + segment_size) {
78 				return bin->segs[i].vmaddr + (offset - segment_base);
79 			}
80 		}
81 	}
82 	return 0;
83 }
84 
pa2va(RBinFile * bf,ut64 offset)85 static ut64 pa2va(RBinFile *bf, ut64 offset) {
86 	r_return_val_if_fail (bf && bf->rbin, offset);
87 	RIO *io = bf->rbin->iob.io;
88 	if (!io || !io->va) {
89 		return offset;
90 	}
91 	struct MACH0_(obj_t) *bin = bf->o->bin_obj;
92 	return bin? offset_to_vaddr (bin, offset): offset;
93 }
94 
init_sdb_formats(struct MACH0_ (obj_t)* bin)95 static void init_sdb_formats(struct MACH0_(obj_t) *bin) {
96 	/*
97 	 * These definitions are used by r2 -nn
98 	 * must be kept in sync with libr/bin/d/macho
99 	 */
100 	sdb_set (bin->kv, "mach0_build_platform.cparse",
101 		"enum mach0_build_platform" "{MACOS=1, IOS=2, TVOS=3, WATCHOS=4, BRIDGEOS=5, IOSMAC=6, IOSSIMULATOR=7, TVOSSIMULATOR=8, WATCHOSSIMULATOR=9};",
102 		0);
103 	sdb_set (bin->kv, "mach0_build_tool.cparse",
104 		"enum mach0_build_tool" "{CLANG=1, SWIFT=2, LD=3};",
105 		0);
106 	sdb_set (bin->kv, "mach0_load_command_type.cparse",
107 		"enum mach0_load_command_type" "{ LC_SEGMENT=0x00000001ULL, LC_SYMTAB=0x00000002ULL, LC_SYMSEG=0x00000003ULL, LC_THREAD=0x00000004ULL, LC_UNIXTHREAD=0x00000005ULL, LC_LOADFVMLIB=0x00000006ULL, LC_IDFVMLIB=0x00000007ULL, LC_IDENT=0x00000008ULL, LC_FVMFILE=0x00000009ULL, LC_PREPAGE=0x0000000aULL, LC_DYSYMTAB=0x0000000bULL, LC_LOAD_DYLIB=0x0000000cULL, LC_ID_DYLIB=0x0000000dULL, LC_LOAD_DYLINKER=0x0000000eULL, LC_ID_DYLINKER=0x0000000fULL, LC_PREBOUND_DYLIB=0x00000010ULL, LC_ROUTINES=0x00000011ULL, LC_SUB_FRAMEWORK=0x00000012ULL, LC_SUB_UMBRELLA=0x00000013ULL, LC_SUB_CLIENT=0x00000014ULL, LC_SUB_LIBRARY=0x00000015ULL, LC_TWOLEVEL_HINTS=0x00000016ULL, LC_PREBIND_CKSUM=0x00000017ULL, LC_LOAD_WEAK_DYLIB=0x80000018ULL, LC_SEGMENT_64=0x00000019ULL, LC_ROUTINES_64=0x0000001aULL, LC_UUID=0x0000001bULL, LC_RPATH=0x8000001cULL, LC_CODE_SIGNATURE=0x0000001dULL, LC_SEGMENT_SPLIT_INFO=0x0000001eULL, LC_REEXPORT_DYLIB=0x8000001fULL, LC_LAZY_LOAD_DYLIB=0x00000020ULL, LC_ENCRYPTION_INFO=0x00000021ULL, LC_DYLD_INFO=0x00000022ULL, LC_DYLD_INFO_ONLY=0x80000022ULL, LC_LOAD_UPWARD_DYLIB=0x80000023ULL, LC_VERSION_MIN_MACOSX=0x00000024ULL, LC_VERSION_MIN_IPHONEOS=0x00000025ULL, LC_FUNCTION_STARTS=0x00000026ULL, LC_DYLD_ENVIRONMENT=0x00000027ULL, LC_MAIN=0x80000028ULL, LC_DATA_IN_CODE=0x00000029ULL, LC_SOURCE_VERSION=0x0000002aULL, LC_DYLIB_CODE_SIGN_DRS=0x0000002bULL, LC_ENCRYPTION_INFO_64=0x0000002cULL, LC_LINKER_OPTION=0x0000002dULL, LC_LINKER_OPTIMIZATION_HINT=0x0000002eULL, LC_VERSION_MIN_TVOS=0x0000002fULL, LC_VERSION_MIN_WATCHOS=0x00000030ULL, LC_NOTE=0x00000031ULL, LC_BUILD_VERSION=0x00000032ULL };",
108 		0);
109 	sdb_set (bin->kv, "mach0_header_filetype.cparse",
110 		"enum mach0_header_filetype" "{MH_OBJECT=1, MH_EXECUTE=2, MH_FVMLIB=3, MH_CORE=4, MH_PRELOAD=5, MH_DYLIB=6, MH_DYLINKER=7, MH_BUNDLE=8, MH_DYLIB_STUB=9, MH_DSYM=10, MH_KEXT_BUNDLE=11};",
111 		0);
112 	sdb_set (bin->kv, "mach0_header_flags.cparse",
113 		"enum mach0_header_flags" "{MH_NOUNDEFS=1, MH_INCRLINK=2,MH_DYLDLINK=4,MH_BINDATLOAD=8,MH_PREBOUND=0x10, MH_SPLIT_SEGS=0x20,MH_LAZY_INIT=0x40,MH_TWOLEVEL=0x80, MH_FORCE_FLAT=0x100,MH_NOMULTIDEFS=0x200,MH_NOFIXPREBINDING=0x400, MH_PREBINDABLE=0x800, MH_ALLMODSBOUND=0x1000, MH_SUBSECTIONS_VIA_SYMBOLS=0x2000, MH_CANONICAL=0x4000,MH_WEAK_DEFINES=0x8000, MH_BINDS_TO_WEAK=0x10000,MH_ALLOW_STACK_EXECUTION=0x20000, MH_ROOT_SAFE=0x40000,MH_SETUID_SAFE=0x80000, MH_NO_REEXPORTED_DYLIBS=0x100000,MH_PIE=0x200000, MH_DEAD_STRIPPABLE_DYLIB=0x400000, MH_HAS_TLV_DESCRIPTORS=0x800000, MH_NO_HEAP_EXECUTION=0x1000000};",
114 		0);
115 	sdb_set (bin->kv, "mach0_section_types.cparse",
116 		"enum mach0_section_types" "{S_REGULAR=0, S_ZEROFILL=1, S_CSTRING_LITERALS=2, S_4BYTE_LITERALS=3, S_8BYTE_LITERALS=4, S_LITERAL_POINTERS=5, S_NON_LAZY_SYMBOL_POINTERS=6, S_LAZY_SYMBOL_POINTERS=7, S_SYMBOL_STUBS=8, S_MOD_INIT_FUNC_POINTERS=9, S_MOD_TERM_FUNC_POINTERS=0xa, S_COALESCED=0xb, S_GB_ZEROFILL=0xc, S_INTERPOSING=0xd, S_16BYTE_LITERALS=0xe, S_DTRACE_DOF=0xf, S_LAZY_DYLIB_SYMBOL_POINTERS=0x10, S_THREAD_LOCAL_REGULAR=0x11, S_THREAD_LOCAL_ZEROFILL=0x12, S_THREAD_LOCAL_VARIABLES=0x13, S_THREAD_LOCAL_VARIABLE_POINTERS=0x14, S_THREAD_LOCAL_INIT_FUNCTION_POINTERS=0x15, S_INIT_FUNC_OFFSETS=0x16};",
117 		0);
118 	sdb_set (bin->kv, "mach0_section_attrs.cparse",
119 		"enum mach0_section_attrs" "{S_ATTR_PURE_INSTRUCTIONS=0x800000ULL, S_ATTR_NO_TOC=0x400000ULL, S_ATTR_STRIP_STATIC_SYMS=0x200000ULL, S_ATTR_NO_DEAD_STRIP=0x100000ULL, S_ATTR_LIVE_SUPPORT=0x080000ULL, S_ATTR_SELF_MODIFYING_CODE=0x040000ULL, S_ATTR_DEBUG=0x020000ULL, S_ATTR_SOME_INSTRUCTIONS=0x000004ULL, S_ATTR_EXT_RELOC=0x000002ULL, S_ATTR_LOC_RELOC=0x000001ULL};",
120 		0);
121 	sdb_set (bin->kv, "mach0_header.format",
122 		"xxx[4]Edd[4]B "
123 		"magic cputype cpusubtype (mach0_header_filetype)filetype ncmds sizeofcmds (mach0_header_flags)flags",
124 		0);
125 	sdb_set (bin->kv, "mach0_segment.format",
126 		"[4]Ed[16]zxxxxoodx "
127 		"(mach0_load_command_type)cmd cmdsize segname vmaddr vmsize fileoff filesize maxprot initprot nsects flags",
128 		0);
129 	sdb_set (bin->kv, "mach0_segment64.format",
130 		"[4]Ed[16]zqqqqoodx "
131 		"(mach0_load_command_type)cmd cmdsize segname vmaddr vmsize fileoff filesize maxprot initprot nsects flags",
132 		0);
133 	sdb_set (bin->kv, "mach0_symtab_command.format",
134 		"[4]Edxdxd "
135 		"(mach0_load_command_type)cmd cmdsize symoff nsyms stroff strsize",
136 		0);
137 	sdb_set (bin->kv, "mach0_dysymtab_command.format",
138 		"[4]Edddddddddddxdxdxxxd "
139 		"(mach0_load_command_type)cmd cmdsize ilocalsym nlocalsym iextdefsym nextdefsym iundefsym nundefsym tocoff ntoc moddtaboff nmodtab extrefsymoff nextrefsyms inddirectsymoff nindirectsyms extreloff nextrel locreloff nlocrel",
140 		0);
141 	sdb_set (bin->kv, "mach0_section.format",
142 		"[16]z[16]zxxxxxx[1]E[3]Bxx "
143 		"sectname segname addr size offset align reloff nreloc (mach0_section_types)flags_type (mach0_section_attrs)flags_attr reserved1 reserved2", 0);
144 	sdb_set (bin->kv, "mach0_section64.format",
145 		"[16]z[16]zqqxxxx[1]E[3]Bxxx "
146 		"sectname segname addr size offset align reloff nreloc (mach0_section_types)flags_type (mach0_section_attrs)flags_attr reserved1 reserved2 reserved3",
147 		0);
148 	sdb_set (bin->kv, "mach0_dylib.format",
149 		"xxxxz "
150 		"name_offset timestamp current_version compatibility_version name",
151 		0);
152 	sdb_set (bin->kv, "mach0_dylib_command.format",
153 		"[4]Ed? "
154 		"(mach0_load_command_type)cmd cmdsize (mach0_dylib)dylib",
155 		0);
156 	sdb_set (bin->kv, "mach0_id_dylib_command.format",
157 		"[4]Ed? "
158 		"(mach0_load_command_type)cmd cmdsize (mach0_dylib)dylib",
159 		0);
160 	sdb_set (bin->kv, "mach0_uuid_command.format",
161 		"[4]Ed[16]b "
162 		"(mach0_load_command_type)cmd cmdsize uuid",
163 		0);
164 	sdb_set (bin->kv, "mach0_rpath_command.format",
165 		"[4]Edxz "
166 		"(mach0_load_command_type)cmd cmdsize path_offset path",
167 		0);
168 	sdb_set (bin->kv, "mach0_entry_point_command.format",
169 		"[4]Edqq "
170 		"(mach0_load_command_type)cmd cmdsize entryoff stacksize",
171 		0);
172 	sdb_set (bin->kv, "mach0_encryption_info64_command.format",
173 		"[4]Edxddx "
174 		"(mach0_load_command_type)cmd cmdsize offset size id padding",
175 		0);
176 	sdb_set (bin->kv, "mach0_encryption_info_command.format",
177 		"[4]Edxdd "
178 		"(mach0_load_command_type)cmd cmdsize offset size id",
179 		0);
180 	sdb_set (bin->kv, "mach0_code_signature_command.format",
181 		"[4]Edxd "
182 		"(mach0_load_command_type)cmd cmdsize offset size",
183 		0);
184 	sdb_set (bin->kv, "mach0_dyld_info_only_command.format",
185 		"[4]Edxdxdxdxdxd "
186 		"(mach0_load_command_type)cmd cmdsize rebase_off rebase_size bind_off bind_size weak_bind_off weak_bind_size lazy_bind_off lazy_bind_size export_off export_size",
187 		0);
188 	sdb_set (bin->kv, "mach0_load_dylinker_command.format",
189 		"[4]Edxz "
190 		"(mach0_load_command_type)cmd cmdsize name_offset name",
191 		0);
192 	sdb_set (bin->kv, "mach0_id_dylinker_command.format",
193 		"[4]Edxzi "
194 		"(mach0_load_command_type)cmd cmdsize name_offset name",
195 		0);
196 	sdb_set (bin->kv, "mach0_build_version_command.format",
197 		"[4]Ed[4]Exxd "
198 		"(mach0_load_command_type)cmd cmdsize (mach0_build_platform)platform minos sdk ntools",
199 		0);
200 	sdb_set (bin->kv, "mach0_build_version_tool.format",
201 		"[4]Ex "
202 		"(mach0_build_tool)tool version",
203 		0);
204 	sdb_set (bin->kv, "mach0_source_version_command.format",
205 		"[4]Edq "
206 		"(mach0_load_command_type)cmd cmdsize version",
207 		0);
208 	sdb_set (bin->kv, "mach0_function_starts_command.format",
209 		"[4]Edxd "
210 		"(mach0_load_command_type)cmd cmdsize offset size",
211 		0);
212 	sdb_set (bin->kv, "mach0_data_in_code_command.format",
213 		"[4]Edxd "
214 		"(mach0_load_command_type)cmd cmdsize offset size",
215 		0);
216 	sdb_set (bin->kv, "mach0_version_min_command.format",
217 		"[4]Edxx "
218 		"(mach0_load_command_type)cmd cmdsize version reserved",
219 		0);
220 	sdb_set (bin->kv, "mach0_segment_split_info_command.format",
221 		"[4]Edxd "
222 		"(mach0_load_command_type)cmd cmdsize offset size",
223 		0);
224 	sdb_set (bin->kv, "mach0_unixthread_command.format",
225 		"[4]Eddd "
226 		"(mach0_load_command_type)cmd cmdsize flavor count",
227 		0);
228 }
229 
init_hdr(struct MACH0_ (obj_t)* bin)230 static bool init_hdr(struct MACH0_(obj_t) *bin) {
231 	ut8 magicbytes[4] = {0};
232 	ut8 machohdrbytes[sizeof (struct MACH0_(mach_header))] = {0};
233 	int len;
234 
235 	if (r_buf_read_at (bin->b, 0 + bin->header_at, magicbytes, 4) < 1) {
236 		return false;
237 	}
238 	if (r_read_le32 (magicbytes) == 0xfeedface) {
239 		bin->big_endian = false;
240 	} else if (r_read_be32 (magicbytes) == 0xfeedface) {
241 		bin->big_endian = true;
242 	} else if (r_read_le32 (magicbytes) == FAT_MAGIC) {
243 		bin->big_endian = false;
244 	} else if (r_read_be32 (magicbytes) == FAT_MAGIC) {
245 		bin->big_endian = true;
246 	} else if (r_read_le32 (magicbytes) == 0xfeedfacf) {
247 		bin->big_endian = false;
248 	} else if (r_read_be32 (magicbytes) == 0xfeedfacf) {
249 		bin->big_endian = true;
250 	} else {
251 		return false; // object files are magic == 0, but body is different :?
252 	}
253 	len = r_buf_read_at (bin->b, 0 + bin->header_at, machohdrbytes, sizeof (machohdrbytes));
254 	if (len != sizeof (machohdrbytes)) {
255 		bprintf ("Error: read (hdr)\n");
256 		return false;
257 	}
258 	bin->hdr.magic = r_read_ble (&machohdrbytes[0], bin->big_endian, 32);
259 	bin->hdr.cputype = r_read_ble (&machohdrbytes[4], bin->big_endian, 32);
260 	bin->hdr.cpusubtype = r_read_ble (&machohdrbytes[8], bin->big_endian, 32);
261 	bin->hdr.filetype = r_read_ble (&machohdrbytes[12], bin->big_endian, 32);
262 	bin->hdr.ncmds = r_read_ble (&machohdrbytes[16], bin->big_endian, 32);
263 	bin->hdr.sizeofcmds = r_read_ble (&machohdrbytes[20], bin->big_endian, 32);
264 	bin->hdr.flags = r_read_ble (&machohdrbytes[24], bin->big_endian, 32);
265 #if R_BIN_MACH064
266 	bin->hdr.reserved = r_read_ble (&machohdrbytes[28], bin->big_endian, 32);
267 #endif
268 	init_sdb_formats (bin);
269 	sdb_num_set (bin->kv, "mach0_header.offset", 0, 0); // wat about fatmach0?
270 	return true;
271 }
272 
parse_segments(struct MACH0_ (obj_t)* bin,ut64 off)273 static bool parse_segments(struct MACH0_(obj_t) *bin, ut64 off) {
274 	size_t i, j, k, sect, len;
275 	ut32 size_sects;
276 	ut8 segcom[sizeof (struct MACH0_(segment_command))] = {0};
277 	ut8 sec[sizeof (struct MACH0_(section))] = {0};
278 
279 	if (!UT32_MUL (&size_sects, bin->nsegs, sizeof (struct MACH0_(segment_command)))) {
280 		return false;
281 	}
282 	if (!size_sects || size_sects > bin->size) {
283 		return false;
284 	}
285 	if (off > bin->size || off + sizeof (struct MACH0_(segment_command)) > bin->size) {
286 		return false;
287 	}
288 	if (!(bin->segs = realloc (bin->segs, bin->nsegs * sizeof(struct MACH0_(segment_command))))) {
289 		perror ("realloc (seg)");
290 		return false;
291 	}
292 	j = bin->nsegs - 1;
293 	len = r_buf_read_at (bin->b, off, segcom, sizeof (struct MACH0_(segment_command)));
294 	if (len != sizeof (struct MACH0_(segment_command))) {
295 		bprintf ("Error: read (seg)\n");
296 		return false;
297 	}
298 	i = 0;
299 	bin->segs[j].cmd = r_read_ble32 (&segcom[i], bin->big_endian);
300 	i += sizeof (ut32);
301 	bin->segs[j].cmdsize = r_read_ble32 (&segcom[i], bin->big_endian);
302 	i += sizeof (ut32);
303 	memcpy (&bin->segs[j].segname, &segcom[i], 16);
304 	i += 16;
305 #if R_BIN_MACH064
306 	bin->segs[j].vmaddr = r_read_ble64 (&segcom[i], bin->big_endian);
307 	i += sizeof (ut64);
308 	bin->segs[j].vmsize = r_read_ble64 (&segcom[i], bin->big_endian);
309 	i += sizeof (ut64);
310 	bin->segs[j].fileoff = r_read_ble64 (&segcom[i], bin->big_endian);
311 	i += sizeof (ut64);
312 	bin->segs[j].filesize = r_read_ble64 (&segcom[i], bin->big_endian);
313 	i += sizeof (ut64);
314 #else
315 	bin->segs[j].vmaddr = r_read_ble32 (&segcom[i], bin->big_endian);
316 	i += sizeof (ut32);
317 	bin->segs[j].vmsize = r_read_ble32 (&segcom[i], bin->big_endian);
318 	i += sizeof (ut32);
319 	bin->segs[j].fileoff = r_read_ble32 (&segcom[i], bin->big_endian);
320 	i += sizeof (ut32);
321 	bin->segs[j].filesize = r_read_ble32 (&segcom[i], bin->big_endian);
322 	i += sizeof (ut32);
323 #endif
324 	bin->segs[j].maxprot = r_read_ble32 (&segcom[i], bin->big_endian);
325 	i += sizeof (ut32);
326 	bin->segs[j].initprot = r_read_ble32 (&segcom[i], bin->big_endian);
327 	i += sizeof (ut32);
328 	bin->segs[j].nsects = r_read_ble32 (&segcom[i], bin->big_endian);
329 	i += sizeof (ut32);
330 	bin->segs[j].flags = r_read_ble32 (&segcom[i], bin->big_endian);
331 
332 #if R_BIN_MACH064
333 	sdb_num_set (bin->kv, sdb_fmt ("mach0_segment64_%zu.offset", j), off, 0);
334 #else
335 	sdb_num_set (bin->kv, sdb_fmt ("mach0_segment_%zu.offset", j), off, 0);
336 #endif
337 
338 	sdb_num_set (bin->kv, "mach0_segments.count", 0, 0);
339 
340 	if (bin->segs[j].nsects > 0) {
341 		sect = bin->nsects;
342 		bin->nsects += bin->segs[j].nsects;
343 		if (bin->nsects > 128) {
344 			int new_nsects = bin->nsects & 0xf;
345 			bprintf ("WARNING: mach0 header contains too many sections (%d). Wrapping to %d\n",
346 				 bin->nsects, new_nsects);
347 			bin->nsects = new_nsects;
348 		}
349 		if ((int)bin->nsects < 1) {
350 			bprintf ("Warning: Invalid number of sections\n");
351 			bin->nsects = sect;
352 			return false;
353 		}
354 		if (!UT32_MUL (&size_sects, bin->nsects-sect, sizeof (struct MACH0_(section)))){
355 			bin->nsects = sect;
356 			return false;
357 		}
358 		if (!size_sects || size_sects > bin->size){
359 			bin->nsects = sect;
360 			return false;
361 		}
362 
363 		if (bin->segs[j].cmdsize != sizeof (struct MACH0_(segment_command)) \
364 				  + (sizeof (struct MACH0_(section))*bin->segs[j].nsects)){
365 			bin->nsects = sect;
366 			return false;
367 		}
368 
369 		if (off + sizeof (struct MACH0_(segment_command)) > bin->size ||\
370 				off + sizeof (struct MACH0_(segment_command)) + size_sects > bin->size){
371 			bin->nsects = sect;
372 			return false;
373 		}
374 
375 		if (!(bin->sects = realloc (bin->sects, bin->nsects * sizeof (struct MACH0_(section))))) {
376 			perror ("realloc (sects)");
377 			bin->nsects = sect;
378 			return false;
379 		}
380 
381 		for (k = sect, j = 0; k < bin->nsects; k++, j++) {
382 			ut64 offset = off + sizeof (struct MACH0_(segment_command)) + j * sizeof (struct MACH0_(section));
383 			len = r_buf_read_at (bin->b, offset, sec, sizeof (struct MACH0_(section)));
384 			if (len != sizeof (struct MACH0_(section))) {
385 				bprintf ("Error: read (sects)\n");
386 				bin->nsects = sect;
387 				return false;
388 			}
389 
390 			i = 0;
391 			memcpy (&bin->sects[k].sectname, &sec[i], 16);
392 			i += 16;
393 			memcpy (&bin->sects[k].segname, &sec[i], 16);
394 			i += 16;
395 
396 			sdb_num_set (bin->kv, sdb_fmt ("mach0_section_%.16s_%.16s.offset",
397 						bin->sects[k].segname, bin->sects[k].sectname), offset, 0);
398 #if R_BIN_MACH064
399 			sdb_set (bin->kv, sdb_fmt ("mach0_section_%.16s_%.16s.format",
400 						bin->sects[k].segname, bin->sects[k].sectname), "mach0_section64", 0);
401 #else
402 			sdb_set (bin->kv, sdb_fmt ("mach0_section_%.16s_%.16s.format",
403 						bin->sects[k].segname, bin->sects[k].sectname), "mach0_section", 0);
404 #endif
405 
406 #if R_BIN_MACH064
407 			bin->sects[k].addr = r_read_ble64 (&sec[i], bin->big_endian);
408 			i += sizeof (ut64);
409 			bin->sects[k].size = r_read_ble64 (&sec[i], bin->big_endian);
410 			i += sizeof (ut64);
411 #else
412 			bin->sects[k].addr = r_read_ble32 (&sec[i], bin->big_endian);
413 			i += sizeof (ut32);
414 			bin->sects[k].size = r_read_ble32 (&sec[i], bin->big_endian);
415 			i += sizeof (ut32);
416 #endif
417 			bin->sects[k].offset = r_read_ble32 (&sec[i], bin->big_endian);
418 			i += sizeof (ut32);
419 			bin->sects[k].align = r_read_ble32 (&sec[i], bin->big_endian);
420 			i += sizeof (ut32);
421 			bin->sects[k].reloff = r_read_ble32 (&sec[i], bin->big_endian);
422 			i += sizeof (ut32);
423 			bin->sects[k].nreloc = r_read_ble32 (&sec[i], bin->big_endian);
424 			i += sizeof (ut32);
425 			bin->sects[k].flags = r_read_ble32 (&sec[i], bin->big_endian);
426 			i += sizeof (ut32);
427 			bin->sects[k].reserved1 = r_read_ble32 (&sec[i], bin->big_endian);
428 			i += sizeof (ut32);
429 			bin->sects[k].reserved2 = r_read_ble32 (&sec[i], bin->big_endian);
430 #if R_BIN_MACH064
431 			i += sizeof (ut32);
432 			bin->sects[k].reserved3 = r_read_ble32 (&sec[i], bin->big_endian);
433 #endif
434 		}
435 	}
436 	return true;
437 }
438 
439 #define Error(x) error_message = x; goto error;
parse_symtab(struct MACH0_ (obj_t)* mo,ut64 off)440 static bool parse_symtab(struct MACH0_(obj_t) *mo, ut64 off) {
441 	struct symtab_command st;
442 	ut32 size_sym;
443 	size_t i;
444 	const char *error_message = "";
445 	ut8 symt[sizeof (struct symtab_command)] = {0};
446 	ut8 nlst[sizeof (struct MACH0_(nlist))] = {0};
447 	const bool be = mo->big_endian;
448 
449 	if (off > (ut64)mo->size || off + sizeof (struct symtab_command) > (ut64)mo->size) {
450 		return false;
451 	}
452 	int len = r_buf_read_at (mo->b, off, symt, sizeof (struct symtab_command));
453 	if (len != sizeof (struct symtab_command)) {
454 		Eprintf ("Error: read (symtab)\n");
455 		return false;
456 	}
457 	st.cmd = r_read_ble32 (symt, be);
458 	st.cmdsize = r_read_ble32 (symt + 4, be);
459 	st.symoff = r_read_ble32 (symt + 8, be);
460 	st.nsyms = r_read_ble32 (symt + 12, be);
461 	st.stroff = r_read_ble32 (symt + 16, be);
462 	st.strsize = r_read_ble32 (symt + 20, be);
463 
464 	mo->symtab = NULL;
465 	mo->nsymtab = 0;
466 	if (st.strsize > 0 && st.strsize < mo->size && st.nsyms > 0) {
467 		mo->nsymtab = st.nsyms;
468 		if (st.stroff > mo->size || st.stroff + st.strsize > mo->size) {
469 			Error ("fail");
470 		}
471 		if (!UT32_MUL (&size_sym, mo->nsymtab, sizeof (struct MACH0_(nlist)))) {
472 			Error ("fail2");
473 		}
474 		if (!size_sym) {
475 			Error ("symbol size is zero");
476 		}
477 		if (st.symoff > mo->size || st.symoff + size_sym > mo->size) {
478 			Error ("symoff is out of bounds");
479 		}
480 		if (!(mo->symstr = calloc (1, st.strsize + 2))) {
481 			Error ("symoff is out of bounds");
482 		}
483 		mo->symstrlen = st.strsize;
484 		len = r_buf_read_at (mo->b, st.stroff, (ut8*)mo->symstr, st.strsize);
485 		if (len != st.strsize) {
486 			Error ("Error: read (symstr)");
487 		}
488 		if (!(mo->symtab = calloc (mo->nsymtab, sizeof (struct MACH0_(nlist))))) {
489 			goto error;
490 		}
491 		for (i = 0; i < mo->nsymtab; i++) {
492 			ut64 at = st.symoff + (i * sizeof (struct MACH0_(nlist)));
493 			len = r_buf_read_at (mo->b, at, nlst, sizeof (struct MACH0_(nlist)));
494 			if (len != sizeof (struct MACH0_(nlist))) {
495 				Error ("read (nlist)");
496 			}
497 			//XXX not very safe what if is n_un.n_name instead?
498 			mo->symtab[i].n_strx = r_read_ble32 (nlst, be);
499 			mo->symtab[i].n_type = r_read_ble8 (nlst + 4);
500 			mo->symtab[i].n_sect = r_read_ble8 (nlst + 5);
501 			mo->symtab[i].n_desc = r_read_ble16 (nlst + 6, be);
502 #if R_BIN_MACH064
503 			mo->symtab[i].n_value = r_read_ble64 (&nlst[8], be);
504 #else
505 			mo->symtab[i].n_value = r_read_ble32 (&nlst[8], be);
506 #endif
507 		}
508 	}
509 	return true;
510 error:
511 	R_FREE (mo->symstr);
512 	R_FREE (mo->symtab);
513 	Eprintf ("%s\n", error_message);
514 	return false;
515 }
516 
parse_dysymtab(struct MACH0_ (obj_t)* bin,ut64 off)517 static bool parse_dysymtab(struct MACH0_(obj_t) *bin, ut64 off) {
518 	size_t len, i;
519 	ut32 size_tab;
520 	ut8 dysym[sizeof (struct dysymtab_command)] = {0};
521 	ut8 dytoc[sizeof (struct dylib_table_of_contents)] = {0};
522 	ut8 dymod[sizeof (struct MACH0_(dylib_module))] = {0};
523 	ut8 idsyms[sizeof (ut32)] = {0};
524 
525 	if (off > bin->size || off + sizeof (struct dysymtab_command) > bin->size) {
526 		return false;
527 	}
528 
529 	len = r_buf_read_at (bin->b, off, dysym, sizeof (struct dysymtab_command));
530 	if (len != sizeof (struct dysymtab_command)) {
531 		bprintf ("Error: read (dysymtab)\n");
532 		return false;
533 	}
534 
535 	bin->dysymtab.cmd = r_read_ble32 (&dysym[0], bin->big_endian);
536 	bin->dysymtab.cmdsize = r_read_ble32 (&dysym[4], bin->big_endian);
537 	bin->dysymtab.ilocalsym = r_read_ble32 (&dysym[8], bin->big_endian);
538 	bin->dysymtab.nlocalsym = r_read_ble32 (&dysym[12], bin->big_endian);
539 	bin->dysymtab.iextdefsym = r_read_ble32 (&dysym[16], bin->big_endian);
540 	bin->dysymtab.nextdefsym = r_read_ble32 (&dysym[20], bin->big_endian);
541 	bin->dysymtab.iundefsym = r_read_ble32 (&dysym[24], bin->big_endian);
542 	bin->dysymtab.nundefsym = r_read_ble32 (&dysym[28], bin->big_endian);
543 	bin->dysymtab.tocoff = r_read_ble32 (&dysym[32], bin->big_endian);
544 	bin->dysymtab.ntoc = r_read_ble32 (&dysym[36], bin->big_endian);
545 	bin->dysymtab.modtaboff = r_read_ble32 (&dysym[40], bin->big_endian);
546 	bin->dysymtab.nmodtab = r_read_ble32 (&dysym[44], bin->big_endian);
547 	bin->dysymtab.extrefsymoff = r_read_ble32 (&dysym[48], bin->big_endian);
548 	bin->dysymtab.nextrefsyms = r_read_ble32 (&dysym[52], bin->big_endian);
549 	bin->dysymtab.indirectsymoff = r_read_ble32 (&dysym[56], bin->big_endian);
550 	bin->dysymtab.nindirectsyms = r_read_ble32 (&dysym[60], bin->big_endian);
551 	bin->dysymtab.extreloff = r_read_ble32 (&dysym[64], bin->big_endian);
552 	bin->dysymtab.nextrel = r_read_ble32 (&dysym[68], bin->big_endian);
553 	bin->dysymtab.locreloff = r_read_ble32 (&dysym[72], bin->big_endian);
554 	bin->dysymtab.nlocrel = r_read_ble32 (&dysym[76], bin->big_endian);
555 
556 	bin->ntoc = bin->dysymtab.ntoc;
557 	if (bin->ntoc > 0) {
558 		if (!(bin->toc = calloc (bin->ntoc, sizeof (struct dylib_table_of_contents)))) {
559 			perror ("calloc (toc)");
560 			return false;
561 		}
562 		if (!UT32_MUL (&size_tab, bin->ntoc, sizeof (struct dylib_table_of_contents))){
563 			R_FREE (bin->toc);
564 			return false;
565 		}
566 		if (!size_tab){
567 			R_FREE (bin->toc);
568 			return false;
569 		}
570 		if (bin->dysymtab.tocoff > bin->size || bin->dysymtab.tocoff + size_tab > bin->size){
571 			R_FREE (bin->toc);
572 			return false;
573 		}
574 		for (i = 0; i < bin->ntoc; i++) {
575 			len = r_buf_read_at (bin->b, bin->dysymtab.tocoff +
576 				i * sizeof (struct dylib_table_of_contents),
577 				dytoc, sizeof (struct dylib_table_of_contents));
578 			if (len != sizeof (struct dylib_table_of_contents)) {
579 				bprintf ("Error: read (toc)\n");
580 				R_FREE (bin->toc);
581 				return false;
582 			}
583 			bin->toc[i].symbol_index = r_read_ble32 (&dytoc[0], bin->big_endian);
584 			bin->toc[i].module_index = r_read_ble32 (&dytoc[4], bin->big_endian);
585 		}
586 	}
587 	bin->nmodtab = bin->dysymtab.nmodtab;
588 	if (bin->nmodtab > 0) {
589 		if (!(bin->modtab = calloc (bin->nmodtab, sizeof (struct MACH0_(dylib_module))))) {
590 			perror ("calloc (modtab)");
591 			return false;
592 		}
593 		if (!UT32_MUL (&size_tab, bin->nmodtab, sizeof (struct MACH0_(dylib_module)))){
594 			R_FREE (bin->modtab);
595 			return false;
596 		}
597 		if (!size_tab){
598 			R_FREE (bin->modtab);
599 			return false;
600 		}
601 		if (bin->dysymtab.modtaboff > bin->size || \
602 		  bin->dysymtab.modtaboff + size_tab > bin->size){
603 			R_FREE (bin->modtab);
604 			return false;
605 		}
606 		for (i = 0; i < bin->nmodtab; i++) {
607 			len = r_buf_read_at (bin->b, bin->dysymtab.modtaboff +
608 				i * sizeof (struct MACH0_(dylib_module)),
609 				dymod, sizeof (struct MACH0_(dylib_module)));
610 			if (len == -1) {
611 				bprintf ("Error: read (modtab)\n");
612 				R_FREE (bin->modtab);
613 				return false;
614 			}
615 
616 			bin->modtab[i].module_name = r_read_ble32 (&dymod[0], bin->big_endian);
617 			bin->modtab[i].iextdefsym = r_read_ble32 (&dymod[4], bin->big_endian);
618 			bin->modtab[i].nextdefsym = r_read_ble32 (&dymod[8], bin->big_endian);
619 			bin->modtab[i].irefsym = r_read_ble32 (&dymod[12], bin->big_endian);
620 			bin->modtab[i].nrefsym = r_read_ble32 (&dymod[16], bin->big_endian);
621 			bin->modtab[i].ilocalsym = r_read_ble32 (&dymod[20], bin->big_endian);
622 			bin->modtab[i].nlocalsym = r_read_ble32 (&dymod[24], bin->big_endian);
623 			bin->modtab[i].iextrel = r_read_ble32 (&dymod[28], bin->big_endian);
624 			bin->modtab[i].nextrel = r_read_ble32 (&dymod[32], bin->big_endian);
625 			bin->modtab[i].iinit_iterm = r_read_ble32 (&dymod[36], bin->big_endian);
626 			bin->modtab[i].ninit_nterm = r_read_ble32 (&dymod[40], bin->big_endian);
627 #if R_BIN_MACH064
628 			bin->modtab[i].objc_module_info_size = r_read_ble32 (&dymod[44], bin->big_endian);
629 			bin->modtab[i].objc_module_info_addr = r_read_ble64 (&dymod[48], bin->big_endian);
630 #else
631 			bin->modtab[i].objc_module_info_addr = r_read_ble32 (&dymod[44], bin->big_endian);
632 			bin->modtab[i].objc_module_info_size = r_read_ble32 (&dymod[48], bin->big_endian);
633 #endif
634 		}
635 	}
636 	bin->nindirectsyms = bin->dysymtab.nindirectsyms;
637 	if (bin->nindirectsyms > 0) {
638 		if (!(bin->indirectsyms = calloc (bin->nindirectsyms, sizeof (ut32)))) {
639 			perror ("calloc (indirectsyms)");
640 			return false;
641 		}
642 		if (!UT32_MUL (&size_tab, bin->nindirectsyms, sizeof (ut32))){
643 			R_FREE (bin->indirectsyms);
644 			return false;
645 		}
646 		if (!size_tab){
647 			R_FREE (bin->indirectsyms);
648 			return false;
649 		}
650 		if (bin->dysymtab.indirectsymoff > bin->size || \
651 				bin->dysymtab.indirectsymoff + size_tab > bin->size){
652 			R_FREE (bin->indirectsyms);
653 			return false;
654 		}
655 		for (i = 0; i < bin->nindirectsyms; i++) {
656 			len = r_buf_read_at (bin->b, bin->dysymtab.indirectsymoff + i * sizeof (ut32), idsyms, 4);
657 			if (len == -1) {
658 				bprintf ("Error: read (indirect syms)\n");
659 				R_FREE (bin->indirectsyms);
660 				return false;
661 			}
662 			bin->indirectsyms[i] = r_read_ble32 (&idsyms[0], bin->big_endian);
663 		}
664 	}
665 	/* TODO extrefsyms, extrel, locrel */
666 	return true;
667 }
668 
readString(ut8 * p,int off,int len)669 static char *readString (ut8 *p, int off, int len) {
670 	if (off < 0 || off >= len) {
671 		return NULL;
672 	}
673 	return r_str_ndup ((const char *)p + off, len - off);
674 }
675 
parseCodeDirectory(RBuffer * b,int offset,int datasize)676 static void parseCodeDirectory (RBuffer *b, int offset, int datasize) {
677 	typedef struct __CodeDirectory {
678 		uint32_t magic;		/* magic number (CSMAGIC_CODEDIRECTORY) */
679 		uint32_t length;	/* total length of CodeDirectory blob */
680 		uint32_t version;	/* compatibility version */
681 		uint32_t flags;		/* setup and mode flags */
682 		uint32_t hashOffset;	/* offset of hash slot element at index zero */
683 		uint32_t identOffset;	/* offset of identifier string */
684 		uint32_t nSpecialSlots;	/* number of special hash slots */
685 		uint32_t nCodeSlots;	/* number of ordinary (code) hash slots */
686 		uint32_t codeLimit;	/* limit to main image signature range */
687 		uint8_t hashSize;	/* size of each hash in bytes */
688 		uint8_t hashType;	/* type of hash (cdHashType* constants) */
689 		uint8_t platform;	/* unused (must be zero) */
690 		uint8_t	pageSize;	/* log2(page size in bytes); 0 => infinite */
691 		uint32_t spare2;	/* unused (must be zero) */
692 		/* followed by dynamic content as located by offset fields above */
693 		uint32_t scatterOffset;
694 		uint32_t teamIDOffset;
695 		uint32_t spare3;
696 		ut64 codeLimit64;
697 		ut64 execSegBase;
698 		ut64 execSegLimit;
699 		ut64 execSegFlags;
700 	} CS_CodeDirectory;
701 	ut64 off = offset;
702 	int psize = datasize;
703 	ut8 *p = calloc (1, psize);
704 	if (!p) {
705 		return;
706 	}
707 	eprintf ("Offset: 0x%08"PFMT64x"\n", off);
708 	r_buf_read_at (b, off, p, datasize);
709 	CS_CodeDirectory cscd = {0};
710 	#define READFIELD(x) cscd.x = r_read_ble32 (p + r_offsetof (CS_CodeDirectory, x), 1)
711 	#define READFIELD8(x) cscd.x = p[r_offsetof (CS_CodeDirectory, x)]
712 	READFIELD (length);
713 	READFIELD (version);
714 	READFIELD (flags);
715 	READFIELD (hashOffset);
716 	READFIELD (identOffset);
717 	READFIELD (nSpecialSlots);
718 	READFIELD (nCodeSlots);
719 	READFIELD (hashSize);
720 	READFIELD (teamIDOffset);
721 	READFIELD8 (hashType);
722 	READFIELD (pageSize);
723 	READFIELD (codeLimit);
724 	eprintf ("Version: %x\n", cscd.version);
725 	eprintf ("Flags: %x\n", cscd.flags);
726 	eprintf ("Length: %d\n", cscd.length);
727 	eprintf ("PageSize: %d\n", cscd.pageSize);
728 	eprintf ("hashOffset: %d\n", cscd.hashOffset);
729 	eprintf ("codeLimit: %d\n", cscd.codeLimit);
730 	eprintf ("hashSize: %d\n", cscd.hashSize);
731 	eprintf ("hashType: %d\n", cscd.hashType);
732 	char *identity = readString (p, cscd.identOffset, psize);
733 	eprintf ("Identity: %s\n", identity);
734 	char *teamId = readString (p, cscd.teamIDOffset, psize);
735 	eprintf ("TeamID: %s\n", teamId);
736 	eprintf ("CodeSlots: %d\n", cscd.nCodeSlots);
737 	free (identity);
738 	free (teamId);
739 
740 	int hashSize = 20; // SHA1 is default
741 	int algoType = R_HASH_SHA1;
742 	const char *hashName = "sha1";
743 	switch (cscd.hashType) {
744 	case 0: // SHA1 == 20 bytes
745 	case 1: // SHA1 == 20 bytes
746 		hashSize = 20;
747 		hashName = "sha1";
748 		algoType = R_HASH_SHA1;
749 		break;
750 	case 2: // SHA256 == 32 bytes
751 		hashSize = 32;
752 		algoType = R_HASH_SHA256;
753 		hashName = "sha256";
754 		break;
755 	}
756 	// computed cdhash
757 	RHash *ctx = r_hash_new (true, algoType);
758 	int fofsz = cscd.length;
759 	ut8 *fofbuf = calloc (fofsz, 1);
760 	if (fofbuf) {
761 		int i;
762 		if (r_buf_read_at (b, off, fofbuf, fofsz) != fofsz) {
763 			eprintf ("Invalid cdhash offset/length values\n");
764 		}
765 		r_hash_do_begin (ctx, algoType);
766 		if (algoType == R_HASH_SHA1) {
767 			r_hash_do_sha1 (ctx, fofbuf, fofsz);
768 		} else {
769 			r_hash_do_sha256 (ctx, fofbuf, fofsz);
770 		}
771 		r_hash_do_end (ctx, algoType);
772 		eprintf ("ph %s @ 0x%"PFMT64x"!%d\n", hashName, off, fofsz);
773 		eprintf ("ComputedCDHash: ");
774 		for (i = 0; i < hashSize;i++) {
775 			eprintf ("%02x", ctx->digest[i]);
776 		}
777 		eprintf ("\n");
778 		free (fofbuf);
779 	}
780 	// show and check the rest of hashes
781 	ut8 *hash = p + cscd.hashOffset;
782 	int j = 0;
783 	int k = 0;
784 	eprintf ("Hashed region: 0x%08"PFMT64x" - 0x%08"PFMT64x"\n", (ut64)0, (ut64)cscd.codeLimit);
785 	for (j = 0; j < cscd.nCodeSlots; j++) {
786 		int fof = 4096 * j;
787 		int idx = j * hashSize;
788 		eprintf ("0x%08"PFMT64x"  ", off + cscd.hashOffset + idx);
789 		for (k = 0; k < hashSize; k++) {
790 			eprintf ("%02x", hash[idx + k]);
791 		}
792 		ut8 fofbuf[4096];
793 		int fofsz = R_MIN (sizeof (fofbuf), cscd.codeLimit - fof);
794 		r_buf_read_at (b, fof, fofbuf, sizeof (fofbuf));
795 		r_hash_do_begin (ctx, algoType);
796 		if (algoType == R_HASH_SHA1) {
797 			r_hash_do_sha1 (ctx, fofbuf, fofsz);
798 		} else {
799 			r_hash_do_sha256 (ctx, fofbuf, fofsz);
800 		}
801 		r_hash_do_end (ctx, algoType);
802 		if (memcmp (hash + idx, ctx->digest, hashSize)) {
803 			eprintf ("  wx ");
804 			int i;
805 			for (i = 0; i < hashSize;i++) {
806 				eprintf ("%02x", ctx->digest[i]);
807 			}
808 		} else {
809 			eprintf ("  OK");
810 		}
811 		eprintf ("\n");
812 	}
813 	r_hash_free (ctx);
814 	free (p);
815 }
816 
817 // parse the Load Command
parse_signature(struct MACH0_ (obj_t)* bin,ut64 off)818 static bool parse_signature(struct MACH0_(obj_t) *bin, ut64 off) {
819 	int i,len;
820 	ut32 data;
821 	bin->signature = NULL;
822 	struct linkedit_data_command link = {0};
823 	ut8 lit[sizeof (struct linkedit_data_command)] = {0};
824 	struct blob_index_t idx = {0};
825 	struct super_blob_t super = {{0}};
826 
827 	if (off > bin->size || off + sizeof (struct linkedit_data_command) > bin->size) {
828 		return false;
829 	}
830 	len = r_buf_read_at (bin->b, off, lit, sizeof (struct linkedit_data_command));
831 	if (len != sizeof (struct linkedit_data_command)) {
832 		bprintf ("Failed to get data while parsing LC_CODE_SIGNATURE command\n");
833 		return false;
834 	}
835 	link.cmd = r_read_ble32 (&lit[0], bin->big_endian);
836 	link.cmdsize = r_read_ble32 (&lit[4], bin->big_endian);
837 	link.dataoff = r_read_ble32 (&lit[8], bin->big_endian);
838 	link.datasize = r_read_ble32 (&lit[12], bin->big_endian);
839 
840 	data = link.dataoff;
841 	if (data > bin->size || data + sizeof (struct super_blob_t) > bin->size) {
842 		bin->signature = (ut8 *)strdup ("Malformed entitlement");
843 		return true;
844 	}
845 	super.blob.magic = r_buf_read_ble32_at (bin->b, data, mach0_endian);
846 	super.blob.length = r_buf_read_ble32_at (bin->b, data + 4, mach0_endian);
847 	super.count = r_buf_read_ble32_at (bin->b, data + 8, mach0_endian);
848 	char *verbose = r_sys_getenv ("RABIN2_CODESIGN_VERBOSE");
849 	bool isVerbose = false;
850 	if (verbose) {
851 		isVerbose = *verbose;
852 		free (verbose);
853 	}
854 	// to dump all certificates
855 	// [0x00053f75]> b 5K;/x 30800609;wtf @@ hit*
856 	// then do this:
857 	// $ openssl asn1parse -inform der -in a|less
858 	// $ openssl pkcs7 -inform DER -print_certs -text -in a
859 	for (i = 0; i < super.count; i++) {
860 		if (data + i > bin->size) {
861 			bin->signature = (ut8 *)strdup ("Malformed entitlement");
862 			break;
863 		}
864 		struct blob_index_t bi;
865 		if (r_buf_read_at (bin->b, data + 12 + (i * sizeof (struct blob_index_t)),
866 			(ut8*)&bi, sizeof (struct blob_index_t)) < sizeof (struct blob_index_t)) {
867 			break;
868 		}
869 		idx.type = r_read_ble32 (&bi.type, mach0_endian);
870 		idx.offset = r_read_ble32 (&bi.offset, mach0_endian);
871 		switch (idx.type) {
872 		case CSSLOT_ENTITLEMENTS:
873 			if (true || isVerbose) {
874 				ut64 off = data + idx.offset;
875 				if (off > bin->size || off + sizeof (struct blob_t) > bin->size) {
876 					bin->signature = (ut8 *)strdup ("Malformed entitlement");
877 					break;
878 				}
879 				struct blob_t entitlements = {0};
880 				entitlements.magic = r_buf_read_ble32_at (bin->b, off, mach0_endian);
881 				entitlements.length = r_buf_read_ble32_at (bin->b, off + 4, mach0_endian);
882 				len = entitlements.length - sizeof (struct blob_t);
883 				if (len <= bin->size && len > 1) {
884 					bin->signature = calloc (1, len + 1);
885 					if (!bin->signature) {
886 						break;
887 					}
888 					if (off + sizeof (struct blob_t) + len < r_buf_size (bin->b)) {
889 						r_buf_read_at (bin->b, off + sizeof (struct blob_t), (ut8 *)bin->signature, len);
890 						if (len >= 0) {
891 							bin->signature[len] = '\0';
892 						}
893 					} else {
894 						bin->signature = (ut8 *)strdup ("Malformed entitlement");
895 					}
896 				} else {
897 					bin->signature = (ut8 *)strdup ("Malformed entitlement");
898 				}
899 			}
900 			break;
901 		case CSSLOT_CODEDIRECTORY:
902 			if (isVerbose) {
903 				parseCodeDirectory (bin->b, data + idx.offset, link.datasize);
904 			}
905 			break;
906 		case 0x1000:
907 			// unknown
908 			break;
909 		case CSSLOT_CMS_SIGNATURE: // ASN1/DER certificate
910 			if (isVerbose) {
911 				ut8 header[8] = {0};
912 				r_buf_read_at (bin->b, data + idx.offset, header, sizeof (header));
913 				ut32 length = R_MIN (UT16_MAX, r_read_ble32 (header + 4, 1));
914 				ut8 *p = calloc (length, 1);
915 				if (p) {
916 					r_buf_read_at (bin->b, data + idx.offset + 0, p, length);
917 					ut32 *words = (ut32*)p;
918 					eprintf ("Magic: %x\n", words[0]);
919 					eprintf ("wtf DUMP @%d!%d\n",
920 						(int)data + idx.offset + 8, (int)length);
921 					eprintf ("openssl pkcs7 -print_certs -text -inform der -in DUMP\n");
922 					eprintf ("openssl asn1parse -offset %d -length %d -inform der -in /bin/ls\n",
923 						(int)data + idx.offset + 8, (int)length);
924 					eprintf ("pFp@%d!%d\n",
925 						(int)data + idx.offset + 8, (int)length);
926 					free (p);
927 				}
928 			}
929 			break;
930 		case CSSLOT_REQUIREMENTS: // 2
931 			{
932 				ut8 p[256];
933 				r_buf_read_at (bin->b, data + idx.offset + 16, p, sizeof (p));
934 				p[sizeof (p) - 1] = 0;
935 				ut32 slot_size = r_read_ble32 (p  + 8, 1);
936 				if (slot_size < sizeof (p)) {
937 					ut32 ident_size = r_read_ble32 (p  + 8, 1);
938 					char *ident = r_str_ndup ((const char *)p + 28, ident_size);
939 					if (ident) {
940 						sdb_set (bin->kv, "mach0.ident", ident, 0);
941 						free (ident);
942 					}
943 				} else {
944 					if (bin->verbose) {
945 						eprintf ("Invalid code slot size\n");
946 					}
947 				}
948 			}
949 			break;
950 		case CSSLOT_INFOSLOT: // 1;
951 		case CSSLOT_RESOURCEDIR: // 3;
952 		case CSSLOT_APPLICATION: // 4;
953 			// TODO: parse those codesign slots
954 			if (bin->verbose) {
955 				eprintf ("TODO: Some codesign slots are not yet supported\n");
956 			}
957 			break;
958 		default:
959 			if (bin->verbose) {
960 				eprintf ("Unknown Code signature slot %d\n", idx.type);
961 			}
962 			break;
963 		}
964 	}
965 	if (!bin->signature) {
966 		bin->signature = (ut8 *)strdup ("No entitlement found");
967 	}
968 	return true;
969 }
970 
parse_thread(struct MACH0_ (obj_t)* bin,struct load_command * lc,ut64 off,bool is_first_thread)971 static int parse_thread(struct MACH0_(obj_t) *bin, struct load_command *lc, ut64 off, bool is_first_thread) {
972 	ut64 ptr_thread, pc = UT64_MAX, pc_offset = UT64_MAX;
973 	ut32 flavor, count;
974 	ut8 *arw_ptr = NULL;
975 	int arw_sz, len = 0;
976 	ut8 thc[sizeof (struct thread_command)] = {0};
977 	ut8 tmp[4];
978 
979 	if (off > bin->size || off + sizeof (struct thread_command) > bin->size) {
980 		return false;
981 	}
982 
983 	len = r_buf_read_at (bin->b, off, thc, 8);
984 	if (len < 1) {
985 		goto wrong_read;
986 	}
987 	bin->thread.cmd = r_read_ble32 (&thc[0], bin->big_endian);
988 	bin->thread.cmdsize = r_read_ble32 (&thc[4], bin->big_endian);
989 	if (r_buf_read_at (bin->b, off + sizeof (struct thread_command), tmp, 4) < 4) {
990 		goto wrong_read;
991 	}
992 	flavor = r_read_ble32 (tmp, bin->big_endian);
993 	if (len == -1) {
994 		goto wrong_read;
995 	}
996 
997 	if (off + sizeof (struct thread_command) + sizeof (flavor) > bin->size ||
998 		off + sizeof (struct thread_command) + sizeof (flavor) + sizeof (ut32) > bin->size) {
999 		return false;
1000 	}
1001 
1002 	// TODO: use count for checks
1003 	if (r_buf_read_at (bin->b, off + sizeof (struct thread_command) + sizeof (flavor), tmp, 4) < 4) {
1004 		goto wrong_read;
1005 	}
1006 	count = r_read_ble32 (tmp, bin->big_endian);
1007 	ptr_thread = off + sizeof (struct thread_command) + sizeof (flavor) + sizeof (count);
1008 
1009 	if (ptr_thread > bin->size) {
1010 		return false;
1011 	}
1012 
1013 	switch (bin->hdr.cputype) {
1014 	case CPU_TYPE_I386:
1015 	case CPU_TYPE_X86_64:
1016 		switch (flavor) {
1017 		case X86_THREAD_STATE32:
1018 			if (ptr_thread + sizeof (struct x86_thread_state32) > bin->size) {
1019 				return false;
1020 			}
1021 			if (r_buf_fread_at (bin->b, ptr_thread,
1022 				(ut8*)&bin->thread_state.x86_32, "16i", 1) == -1) {
1023 				bprintf ("Error: read (thread state x86_32)\n");
1024 				return false;
1025 			}
1026 			pc = bin->thread_state.x86_32.eip;
1027 			pc_offset = ptr_thread + r_offsetof(struct x86_thread_state32, eip);
1028 			arw_ptr = (ut8 *)&bin->thread_state.x86_32;
1029 			arw_sz = sizeof (struct x86_thread_state32);
1030 			break;
1031 		case X86_THREAD_STATE64:
1032 			if (ptr_thread + sizeof (struct x86_thread_state64) > bin->size) {
1033 				return false;
1034 			}
1035 			if (r_buf_fread_at (bin->b, ptr_thread,
1036 				(ut8*)&bin->thread_state.x86_64, "32l", 1) == -1) {
1037 				bprintf ("Error: read (thread state x86_64)\n");
1038 				return false;
1039 			}
1040 			pc = bin->thread_state.x86_64.rip;
1041 			pc_offset = ptr_thread + r_offsetof(struct x86_thread_state64, rip);
1042 			arw_ptr = (ut8 *)&bin->thread_state.x86_64;
1043 			arw_sz = sizeof (struct x86_thread_state64);
1044 			break;
1045 		//default: bprintf ("Unknown type\n");
1046 		}
1047 		break;
1048 	case CPU_TYPE_POWERPC:
1049 	case CPU_TYPE_POWERPC64:
1050 		if (flavor == X86_THREAD_STATE32) {
1051 			if (ptr_thread + sizeof (struct ppc_thread_state32) > bin->size) {
1052 				return false;
1053 			}
1054 			if (r_buf_fread_at (bin->b, ptr_thread,
1055 				(ut8*)&bin->thread_state.ppc_32, bin->big_endian ? "40I" : "40i", 1) == -1) {
1056 				bprintf ("Error: read (thread state ppc_32)\n");
1057 				return false;
1058 			}
1059 			pc = bin->thread_state.ppc_32.srr0;
1060 			pc_offset = ptr_thread + r_offsetof(struct ppc_thread_state32, srr0);
1061 			arw_ptr = (ut8 *)&bin->thread_state.ppc_32;
1062 			arw_sz = sizeof (struct ppc_thread_state32);
1063 		} else if (flavor == X86_THREAD_STATE64) {
1064 			if (ptr_thread + sizeof (struct ppc_thread_state64) > bin->size) {
1065 				return false;
1066 			}
1067 			if (r_buf_fread_at (bin->b, ptr_thread,
1068 				(ut8*)&bin->thread_state.ppc_64, bin->big_endian ? "34LI3LI" : "34li3li", 1) == -1) {
1069 				bprintf ("Error: read (thread state ppc_64)\n");
1070 				return false;
1071 			}
1072 			pc = bin->thread_state.ppc_64.srr0;
1073 			pc_offset = ptr_thread + r_offsetof(struct ppc_thread_state64, srr0);
1074 			arw_ptr = (ut8 *)&bin->thread_state.ppc_64;
1075 			arw_sz = sizeof (struct ppc_thread_state64);
1076 		}
1077 		break;
1078 	case CPU_TYPE_ARM:
1079 		if (ptr_thread + sizeof (struct arm_thread_state32) > bin->size) {
1080 			return false;
1081 		}
1082 		if (r_buf_fread_at (bin->b, ptr_thread,
1083 			(ut8*)&bin->thread_state.arm_32, bin->big_endian ? "17I" : "17i", 1) == -1) {
1084 			bprintf ("Error: read (thread state arm)\n");
1085 			return false;
1086 		}
1087 		pc = bin->thread_state.arm_32.r15;
1088 		pc_offset = ptr_thread + r_offsetof (struct arm_thread_state32, r15);
1089 		arw_ptr = (ut8 *)&bin->thread_state.arm_32;
1090 		arw_sz = sizeof (struct arm_thread_state32);
1091 		break;
1092 	case CPU_TYPE_ARM64:
1093 		if (ptr_thread + sizeof (struct arm_thread_state64) > bin->size) {
1094 			return false;
1095 		}
1096 		if (r_buf_fread_at (bin->b, ptr_thread,
1097 			(ut8*)&bin->thread_state.arm_64, bin->big_endian ? "34LI1I" : "34Li1i", 1) == -1) {
1098 			bprintf ("Error: read (thread state arm)\n");
1099 			return false;
1100 		}
1101 		pc = r_read_be64 (&bin->thread_state.arm_64.pc);
1102 		pc_offset = ptr_thread + r_offsetof (struct arm_thread_state64, pc);
1103 		arw_ptr = (ut8*)&bin->thread_state.arm_64;
1104 		arw_sz = sizeof (struct arm_thread_state64);
1105 		break;
1106 	default:
1107 		bprintf ("Error: read (unknown thread state structure)\n");
1108 		return false;
1109 	}
1110 
1111 	// TODO: this shouldnt be an bprintf...
1112 	if (arw_ptr && arw_sz > 0) {
1113 		int i;
1114 		ut8 *p = arw_ptr;
1115 		bprintf ("arw ");
1116 		for (i = 0; i < arw_sz; i++) {
1117 			bprintf ("%02x", 0xff & p[i]);
1118 		}
1119 		bprintf ("\n");
1120 	}
1121 
1122 	if (is_first_thread) {
1123 		bin->main_cmd = *lc;
1124 		if (pc != UT64_MAX) {
1125 			bin->entry = pc;
1126 		}
1127 		if (pc_offset != UT64_MAX) {
1128 			sdb_num_set (bin->kv, "mach0.entry.offset", pc_offset, 0);
1129 		}
1130 	}
1131 
1132 	return true;
1133 wrong_read:
1134 	bprintf ("Error: read (thread)\n");
1135 	return false;
1136 }
1137 
parse_function_starts(struct MACH0_ (obj_t)* bin,ut64 off)1138 static int parse_function_starts (struct MACH0_(obj_t) *bin, ut64 off) {
1139 	struct linkedit_data_command fc;
1140 	ut8 sfc[sizeof (struct linkedit_data_command)] = {0};
1141 	int len;
1142 
1143 	if (off > bin->size || off + sizeof (struct linkedit_data_command) > bin->size) {
1144 		bprintf ("Likely overflow while parsing"
1145 			" LC_FUNCTION_STARTS command\n");
1146 	}
1147 	bin->func_start = NULL;
1148 	len = r_buf_read_at (bin->b, off, sfc, sizeof (struct linkedit_data_command));
1149 	if (len < 1) {
1150 		bprintf ("Failed to get data while parsing"
1151 			" LC_FUNCTION_STARTS command\n");
1152 	}
1153 	fc.cmd = r_read_ble32 (&sfc[0], bin->big_endian);
1154 	fc.cmdsize = r_read_ble32 (&sfc[4], bin->big_endian);
1155 	fc.dataoff = r_read_ble32 (&sfc[8], bin->big_endian);
1156 	fc.datasize = r_read_ble32 (&sfc[12], bin->big_endian);
1157 
1158 	if ((int)fc.datasize > 0) {
1159 		ut8 *buf = calloc (1, fc.datasize + 1);
1160 		if (!buf) {
1161 			bprintf ("Failed to allocate buffer\n");
1162 			return false;
1163 		}
1164 		bin->func_size = fc.datasize;
1165 		if (fc.dataoff > bin->size || fc.dataoff + fc.datasize > bin->size) {
1166 			free (buf);
1167 			bprintf ("Likely overflow while parsing "
1168 				"LC_FUNCTION_STARTS command\n");
1169 			return false;
1170 		}
1171 		len = r_buf_read_at (bin->b, fc.dataoff, buf, fc.datasize);
1172 		if (len != fc.datasize) {
1173 			free (buf);
1174 			bprintf ("Failed to get data while parsing"
1175 				" LC_FUNCTION_STARTS\n");
1176 			return false;
1177 		}
1178 		buf[fc.datasize] = 0; // null-terminated buffer
1179 		bin->func_start = buf;
1180 		return true;
1181 	}
1182 	bin->func_start = NULL;
1183 	return false;
1184 
1185 }
1186 
parse_dylib(struct MACH0_ (obj_t)* bin,ut64 off)1187 static int parse_dylib(struct MACH0_(obj_t) *bin, ut64 off) {
1188 	struct dylib_command dl;
1189 	int lib, len;
1190 	ut8 sdl[sizeof (struct dylib_command)] = {0};
1191 
1192 	if (off > bin->size || off + sizeof (struct dylib_command) > bin->size) {
1193 		return false;
1194 	}
1195 	lib = bin->nlibs - 1;
1196 
1197 	void *relibs = realloc (bin->libs, bin->nlibs * R_BIN_MACH0_STRING_LENGTH);
1198 	if (!relibs) {
1199 		perror ("realloc (libs)");
1200 		return false;
1201 	}
1202 	bin->libs = relibs;
1203 	len = r_buf_read_at (bin->b, off, sdl, sizeof (struct dylib_command));
1204 	if (len < 1) {
1205 		bprintf ("Error: read (dylib)\n");
1206 		return false;
1207 	}
1208 	dl.cmd = r_read_ble32 (&sdl[0], bin->big_endian);
1209 	dl.cmdsize = r_read_ble32 (&sdl[4], bin->big_endian);
1210 	dl.dylib.name = r_read_ble32 (&sdl[8], bin->big_endian);
1211 	dl.dylib.timestamp = r_read_ble32 (&sdl[12], bin->big_endian);
1212 	dl.dylib.current_version = r_read_ble32 (&sdl[16], bin->big_endian);
1213 	dl.dylib.compatibility_version = r_read_ble32 (&sdl[20], bin->big_endian);
1214 
1215 	if (off + dl.dylib.name > bin->size ||\
1216 	  off + dl.dylib.name + R_BIN_MACH0_STRING_LENGTH > bin->size) {
1217 		return false;
1218 	}
1219 
1220 	memset (bin->libs[lib], 0, R_BIN_MACH0_STRING_LENGTH);
1221 	len = r_buf_read_at (bin->b, off + dl.dylib.name,
1222 		(ut8*)bin->libs[lib], R_BIN_MACH0_STRING_LENGTH);
1223 	bin->libs[lib][R_BIN_MACH0_STRING_LENGTH - 1] = 0;
1224 	if (len < 1) {
1225 		bprintf ("Error: read (dylib str)");
1226 		return false;
1227 	}
1228 	return true;
1229 }
1230 
cmd_to_string(ut32 cmd)1231 static const char *cmd_to_string(ut32 cmd) {
1232 	switch (cmd) {
1233 	case LC_DATA_IN_CODE:
1234 		return "LC_DATA_IN_CODE";
1235 	case LC_CODE_SIGNATURE:
1236 		return "LC_CODE_SIGNATURE";
1237 	case LC_RPATH:
1238 		return "LC_RPATH";
1239 	case LC_TWOLEVEL_HINTS:
1240 		return "LC_TWOLEVEL_HINTS";
1241 	case LC_PREBIND_CKSUM:
1242 		return "LC_PREBIND_CKSUM";
1243 	case LC_SEGMENT:
1244 		return "LC_SEGMENT";
1245 	case LC_SEGMENT_64:
1246 		return "LC_SEGMENT_64";
1247 	case LC_SYMTAB:
1248 		return "LC_SYMTAB";
1249 	case LC_SYMSEG:
1250 		return "LC_SYMSEG";
1251 	case LC_DYSYMTAB:
1252 		return "LC_DYSYMTAB";
1253 	case LC_PREBOUND_DYLIB:
1254 		return "LC_PREBOUND_DYLIB";
1255 	case LC_ROUTINES:
1256 		return "LC_ROUTINES";
1257 	case LC_ROUTINES_64:
1258 		return "LC_ROUTINES_64";
1259 	case LC_SUB_FRAMEWORK:
1260 		return "LC_SUB_FRAMEWORK";
1261 	case LC_SUB_UMBRELLA:
1262 		return "LC_SUB_UMBRELLA";
1263 	case LC_SUB_CLIENT:
1264 		return "LC_SUB_CLIENT";
1265 	case LC_SUB_LIBRARY:
1266 		return "LC_SUB_LIBRARY";
1267 	case LC_FUNCTION_STARTS:
1268 		return "LC_FUNCTION_STARTS";
1269 	case LC_DYLIB_CODE_SIGN_DRS:
1270 		return "LC_DYLIB_CODE_SIGN_DRS";
1271 	case LC_NOTE:
1272 		return "LC_NOTE";
1273 	case LC_BUILD_VERSION:
1274 		return "LC_BUILD_VERSION";
1275 	case LC_VERSION_MIN_MACOSX:
1276 		return "LC_VERSION_MIN_MACOSX";
1277 	case LC_VERSION_MIN_IPHONEOS:
1278 		return "LC_VERSION_MIN_IPHONEOS";
1279 	case LC_VERSION_MIN_TVOS:
1280 		return "LC_VERSION_MIN_TVOS";
1281 	case LC_VERSION_MIN_WATCHOS:
1282 		return "LC_VERSION_MIN_WATCHOS";
1283 	case LC_DYLD_INFO:
1284 		return "LC_DYLD_INFO";
1285 	case LC_DYLD_INFO_ONLY:
1286 		return "LC_DYLD_INFO_ONLY";
1287 	case LC_DYLD_ENVIRONMENT:
1288 		return "LC_DYLD_ENVIRONMENT";
1289 	case LC_SOURCE_VERSION:
1290 		return "LC_SOURCE_VERSION";
1291 	case LC_MAIN:
1292 		return "LC_MAIN";
1293 	case LC_UUID:
1294 		return "LC_UUID";
1295 	case LC_ID_DYLIB:
1296 		return "LC_ID_DYLIB";
1297 	case LC_ID_DYLINKER:
1298 		return "LC_ID_DYLINKER";
1299 	case LC_LAZY_LOAD_DYLIB:
1300 		return "LC_LAZY_LOAD_DYLIB";
1301 	case LC_ENCRYPTION_INFO:
1302 		return "LC_ENCRYPTION_INFO";
1303 	case LC_ENCRYPTION_INFO_64:
1304 		return "LC_ENCRYPTION_INFO_64";
1305 	case LC_SEGMENT_SPLIT_INFO:
1306 		return "LC_SEGMENT_SPLIT_INFO";
1307 	case LC_REEXPORT_DYLIB:
1308 		return "LC_REEXPORT_DYLIB";
1309 	case LC_LINKER_OPTION:
1310 		return "LC_LINKER_OPTION";
1311 	case LC_LINKER_OPTIMIZATION_HINT:
1312 		return "LC_LINKER_OPTIMIZATION_HINT";
1313 	case LC_LOAD_DYLINKER:
1314 		return "LC_LOAD_DYLINKER";
1315 	case LC_LOAD_DYLIB:
1316 		return "LC_LOAD_DYLIB";
1317 	case LC_LOAD_WEAK_DYLIB:
1318 		return "LC_LOAD_WEAK_DYLIB";
1319 	case LC_THREAD:
1320 		return "LC_THREAD";
1321 	case LC_UNIXTHREAD:
1322 		return "LC_UNIXTHREAD";
1323 	case LC_LOADFVMLIB:
1324 		return "LC_LOADFVMLIB";
1325 	case LC_IDFVMLIB:
1326 		return "LC_IDFVMLIB";
1327 	case LC_IDENT:
1328 		return "LC_IDENT";
1329 	case LC_FVMFILE:
1330 		return "LC_FVMFILE";
1331 	case LC_PREPAGE:
1332 		return "LC_PREPAGE";
1333 	}
1334 	return "";
1335 }
1336 
cmd_to_pf_definition(ut32 cmd)1337 static const char *cmd_to_pf_definition(ut32 cmd) {
1338 	switch (cmd) {
1339 	case LC_BUILD_VERSION:
1340 		return "mach0_build_version_command";
1341 	case LC_CODE_SIGNATURE:
1342 		return "mach0_code_signature_command";
1343 	case LC_DATA_IN_CODE:
1344 		return "mach0_data_in_code_command";
1345 	case LC_DYLD_INFO:
1346 	case LC_DYLD_INFO_ONLY:
1347 		return "mach0_dyld_info_only_command";
1348 	case LC_DYLD_ENVIRONMENT:
1349 		return NULL;
1350 	case LC_DYLIB_CODE_SIGN_DRS:
1351 		return NULL;
1352 	case LC_DYSYMTAB:
1353 		return "mach0_dysymtab_command";
1354 	case LC_ENCRYPTION_INFO:
1355 		return "mach0_encryption_info_command";
1356 	case LC_ENCRYPTION_INFO_64:
1357 		return "mach0_encryption_info64_command";
1358 	case LC_FUNCTION_STARTS:
1359 		return "mach0_function_starts_command";
1360 	case LC_FVMFILE:
1361 		return NULL;
1362 	case LC_ID_DYLIB:
1363 		return "mach0_id_dylib_command";
1364 	case LC_ID_DYLINKER:
1365 		return "mach0_id_dylinker_command";
1366 	case LC_IDENT:
1367 		return NULL;
1368 	case LC_IDFVMLIB:
1369 		return NULL;
1370 	case LC_LINKER_OPTION:
1371 		return NULL;
1372 	case LC_LINKER_OPTIMIZATION_HINT:
1373 		return NULL;
1374 	case LC_LOAD_DYLINKER:
1375 		return "mach0_load_dylinker_command";
1376 	case LC_LAZY_LOAD_DYLIB:
1377 	case LC_LOAD_WEAK_DYLIB:
1378 	case LC_LOAD_DYLIB:
1379 		return "mach0_dylib_command";
1380 	case LC_LOADFVMLIB:
1381 		return NULL;
1382 	case LC_MAIN:
1383 		return "mach0_entry_point_command";
1384 	case LC_NOTE:
1385 		return NULL;
1386 	case LC_PREBIND_CKSUM:
1387 		return NULL;
1388 	case LC_PREBOUND_DYLIB:
1389 		return NULL;
1390 	case LC_PREPAGE:
1391 		return NULL;
1392 	case LC_REEXPORT_DYLIB:
1393 		return NULL;
1394 	case LC_ROUTINES:
1395 		return NULL;
1396 	case LC_ROUTINES_64:
1397 		return NULL;
1398 	case LC_RPATH:
1399 		return "mach0_rpath_command";
1400 	case LC_SEGMENT:
1401 		return "mach0_segment";
1402 	case LC_SEGMENT_64:
1403 		return "mach0_segment64";
1404 	case LC_SEGMENT_SPLIT_INFO:
1405 		return "mach0_segment_split_info_command";
1406 	case LC_SOURCE_VERSION:
1407 		return "mach0_source_version_command";
1408 	case LC_SUB_FRAMEWORK:
1409 		return NULL;
1410 	case LC_SUB_UMBRELLA:
1411 		return NULL;
1412 	case LC_SUB_CLIENT:
1413 		return NULL;
1414 	case LC_SUB_LIBRARY:
1415 		return NULL;
1416 	case LC_SYMTAB:
1417 		return "mach0_symtab_command";
1418 	case LC_SYMSEG:
1419 		return NULL;
1420 	case LC_TWOLEVEL_HINTS:
1421 		return NULL;
1422 	case LC_UUID:
1423 		return "mach0_uuid_command";
1424 	case LC_VERSION_MIN_MACOSX:
1425 	case LC_VERSION_MIN_IPHONEOS:
1426 	case LC_VERSION_MIN_TVOS:
1427 	case LC_VERSION_MIN_WATCHOS:
1428 		return "mach0_version_min_command";
1429 	case LC_THREAD:
1430 		return NULL;
1431 	case LC_UNIXTHREAD:
1432 		return "mach0_unixthread_command";
1433 	}
1434 	return NULL;
1435 }
1436 
build_version_platform_to_string(ut32 platform)1437 static const char *build_version_platform_to_string(ut32 platform) {
1438 	switch (platform) {
1439 	case 1:
1440 		return "macOS";
1441 	case 2:
1442 		return "iOS";
1443 	case 3:
1444 		return "tvOS";
1445 	case 4:
1446 		return "watchOS";
1447 	case 5:
1448 		return "bridgeOS";
1449 	case 6:
1450 		return "iOSmac";
1451 	case 7:
1452 		return "iOS Simulator";
1453 	case 8:
1454 		return "tvOS Simulator";
1455 	case 9:
1456 		return "watchOS Simulator";
1457 	default:
1458 		return "unknown";
1459 	}
1460 }
1461 
build_version_tool_to_string(ut32 tool)1462 static const char *build_version_tool_to_string(ut32 tool) {
1463 	switch (tool) {
1464 	case 1:
1465 		return "clang";
1466 	case 2:
1467 		return "swift";
1468 	case 3:
1469 		return "ld";
1470 	default:
1471 		return "unknown";
1472 	}
1473 }
1474 
get_word_size(struct MACH0_ (obj_t)* bin)1475 static size_t get_word_size(struct MACH0_(obj_t) *bin) {
1476 	const size_t word_size = MACH0_(get_bits)(bin) / 8;
1477 	return R_MAX (word_size, 4);
1478 }
1479 
parse_chained_fixups(struct MACH0_ (obj_t)* bin,ut32 offset,ut32 size)1480 static bool parse_chained_fixups(struct MACH0_(obj_t) *bin, ut32 offset, ut32 size) {
1481 	struct dyld_chained_fixups_header header;
1482 	if (size < sizeof (header)) {
1483 		return false;
1484 	}
1485 	if (r_buf_fread_at (bin->b, offset, (ut8 *)&header, "7i", 1) != sizeof (header)) {
1486 		return false;
1487 	}
1488 	if (header.fixups_version > 0) {
1489 		eprintf ("Unsupported fixups version: %u\n", header.fixups_version);
1490 		return false;
1491 	}
1492 	ut64 starts_at = offset + header.starts_offset;
1493 	if (header.starts_offset > size) {
1494 		return false;
1495 	}
1496 	ut32 segs_count;
1497 	if ((segs_count = r_buf_read_le32_at (bin->b, starts_at)) == UT32_MAX) {
1498 		return false;
1499 	}
1500 	bin->chained_starts = R_NEWS0 (struct r_dyld_chained_starts_in_segment *, segs_count);
1501 	if (!bin->chained_starts) {
1502 		return false;
1503 	}
1504 	size_t i;
1505 	ut64 cursor = starts_at + sizeof (ut32);
1506 	for (i = 0; i < segs_count; i++) {
1507 		ut32 seg_off;
1508 		if ((seg_off = r_buf_read_le32_at (bin->b, cursor)) == UT32_MAX || !seg_off) {
1509 			cursor += sizeof (ut32);
1510 			continue;
1511 		}
1512 		if (i >= bin->nsegs) {
1513 			break;
1514 		}
1515 		struct r_dyld_chained_starts_in_segment *cur_seg = R_NEW0 (struct r_dyld_chained_starts_in_segment);
1516 		if (!cur_seg) {
1517 			return false;
1518 		}
1519 		bin->chained_starts[i] = cur_seg;
1520 		if (r_buf_fread_at (bin->b, starts_at + seg_off, (ut8 *)cur_seg, "isslis", 1) != 22) {
1521 			return false;
1522 		}
1523 		if (cur_seg->page_count > 0) {
1524 			ut16 *page_start = malloc (sizeof (ut16) * cur_seg->page_count);
1525 			if (!page_start) {
1526 				return false;
1527 			}
1528 			if (r_buf_fread_at (bin->b, starts_at + seg_off + 22, (ut8 *)page_start, "s", cur_seg->page_count)
1529 					!= cur_seg->page_count * 2) {
1530 				return false;
1531 			}
1532 			cur_seg->page_start = page_start;
1533 		}
1534 		cursor += sizeof (ut32);
1535 	}
1536 	/* TODO: handle also imports, symbols and multiple starts (32-bit only) */
1537 	return true;
1538 }
1539 
reconstruct_chained_fixup(struct MACH0_ (obj_t)* bin)1540 static bool reconstruct_chained_fixup(struct MACH0_(obj_t) *bin) {
1541 	if (!bin->dyld_info) {
1542 		return false;
1543 	}
1544 	if (!bin->nsegs) {
1545 		return false;
1546 	}
1547 	bin->chained_starts = R_NEWS0 (struct r_dyld_chained_starts_in_segment *, bin->nsegs);
1548 	if (!bin->chained_starts) {
1549 		return false;
1550 	}
1551 	size_t wordsize = get_word_size (bin);
1552 	ut8 *p = NULL;
1553 	size_t j, count, skip, bind_size;
1554 	int seg_idx = 0;
1555 	ut64 seg_off = 0;
1556 	bind_size = bin->dyld_info->bind_size;
1557 	if (!bind_size || bind_size < 1) {
1558 		return false;
1559 	}
1560 	if (bin->dyld_info->bind_off > bin->size) {
1561 		return false;
1562 	}
1563 	if (bin->dyld_info->bind_off + bind_size > bin->size) {
1564 		return false;
1565 	}
1566 	ut8 *opcodes = calloc (1, bind_size + 1);
1567 	if (!opcodes) {
1568 		return false;
1569 	}
1570 	if (r_buf_read_at (bin->b, bin->dyld_info->bind_off, opcodes, bind_size) != bind_size) {
1571 		bprintf ("Error: read (dyld_info bind) at 0x%08"PFMT64x"\n", (ut64)(size_t)bin->dyld_info->bind_off);
1572 		R_FREE (opcodes);
1573 		return false;
1574 	}
1575 	struct r_dyld_chained_starts_in_segment *cur_seg = NULL;
1576 	size_t cur_seg_idx = 0;
1577 	ut8 *end;
1578 	bool done = false;
1579 	for (p = opcodes, end = opcodes + bind_size; !done && p < end;) {
1580 		ut8 imm = *p & BIND_IMMEDIATE_MASK, op = *p & BIND_OPCODE_MASK;
1581 		p++;
1582 		switch (op) {
1583 		case BIND_OPCODE_DONE:
1584 			done = true;
1585 			break;
1586 		case BIND_OPCODE_THREADED: {
1587 			switch (imm) {
1588 			case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB: {
1589 				read_uleb128 (&p, end);
1590 				break;
1591 			}
1592 			case BIND_SUBOPCODE_THREADED_APPLY: {
1593 				const size_t ps = 0x1000;
1594 				if (!cur_seg || cur_seg_idx != seg_idx) {
1595 					cur_seg_idx = seg_idx;
1596 					cur_seg = bin->chained_starts[seg_idx];
1597 					if (!cur_seg) {
1598 						cur_seg = R_NEW0 (struct r_dyld_chained_starts_in_segment);
1599 						if (!cur_seg) {
1600 							break;
1601 						}
1602 						bin->chained_starts[seg_idx] = cur_seg;
1603 						cur_seg->pointer_format = DYLD_CHAINED_PTR_ARM64E;
1604 						cur_seg->page_size = ps;
1605 						cur_seg->page_count = ((bin->segs[seg_idx].vmsize + (ps - 1)) & ~(ps - 1)) / ps;
1606 						if (cur_seg->page_count > 0) {
1607 							cur_seg->page_start = malloc (sizeof (ut16) * cur_seg->page_count);
1608 							if (!cur_seg->page_start) {
1609 								break;
1610 							}
1611 							memset (cur_seg->page_start, 0xff, sizeof (ut16) * cur_seg->page_count);
1612 						}
1613 					}
1614 				}
1615 				if (cur_seg) {
1616 					ut32 page_index = (ut32)(seg_off / ps);
1617 					size_t maxsize = cur_seg->page_count * sizeof (ut16);
1618 					if (page_index < maxsize) {
1619 						cur_seg->page_start[page_index] = seg_off & 0xfff;
1620 					}
1621 				}
1622 				break;
1623 			}
1624 			default:
1625 				bprintf ("Error: Unexpected BIND_OPCODE_THREADED sub-opcode: 0x%x\n", imm);
1626 			}
1627 			break;
1628 		}
1629 		case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1630 		case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1631 		case BIND_OPCODE_SET_TYPE_IMM:
1632 			break;
1633 		case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1634 			read_uleb128 (&p, end);
1635 			break;
1636 		case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1637 			while (*p++ && p < end) {
1638 				/* empty loop */
1639 			}
1640 			break;
1641 		case BIND_OPCODE_SET_ADDEND_SLEB:
1642 			r_sleb128 ((const ut8 **)&p, end);
1643 			break;
1644 		case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1645 			seg_idx = imm;
1646 			if (seg_idx >= bin->nsegs) {
1647 				bprintf ("Error: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"
1648 					" has unexistent segment %d\n", seg_idx);
1649 				R_FREE (opcodes);
1650 				return false;
1651 			} else {
1652 				seg_off = read_uleb128 (&p, end);
1653 			}
1654 			break;
1655 		case BIND_OPCODE_ADD_ADDR_ULEB:
1656 			seg_off += read_uleb128 (&p, end);
1657 			break;
1658 		case BIND_OPCODE_DO_BIND:
1659 			break;
1660 		case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1661 			seg_off += read_uleb128 (&p, end) + wordsize;
1662 			break;
1663 		case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1664 			seg_off += (ut64)imm * (ut64)wordsize + wordsize;
1665 			break;
1666 		case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1667 			count = read_uleb128 (&p, end);
1668 			skip = read_uleb128 (&p, end);
1669 			for (j = 0; j < count; j++) {
1670 				seg_off += skip + wordsize;
1671 			}
1672 			break;
1673 		default:
1674 			bprintf ("Error: unknown bind opcode 0x%02x in dyld_info\n", *p);
1675 			R_FREE (opcodes);
1676 			return false;
1677 		}
1678 	}
1679 	R_FREE (opcodes);
1680 
1681 	return true;
1682 }
1683 
init_items(struct MACH0_ (obj_t)* bin)1684 static int init_items(struct MACH0_(obj_t) *bin) {
1685 	struct load_command lc = {0, 0};
1686 	ut8 loadc[sizeof (struct load_command)] = {0};
1687 	bool is_first_thread = true;
1688 	ut64 off = 0LL;
1689 	int i, len;
1690 
1691 	bin->uuidn = 0;
1692 	bin->os = 0;
1693 	bin->has_crypto = 0;
1694 	if (bin->hdr.sizeofcmds > bin->size) {
1695 		bprintf ("Warning: chopping hdr.sizeofcmds\n");
1696 		bin->hdr.sizeofcmds = bin->size - 128;
1697 		//return false;
1698 	}
1699 	//bprintf ("Commands: %d\n", bin->hdr.ncmds);
1700 	for (i = 0, off = sizeof (struct MACH0_(mach_header)) + bin->header_at; \
1701 			i < bin->hdr.ncmds; i++, off += lc.cmdsize) {
1702 		if (off > bin->size || off + sizeof (struct load_command) > bin->size) {
1703 			bprintf ("mach0: out of bounds command\n");
1704 			return false;
1705 		}
1706 		len = r_buf_read_at (bin->b, off, loadc, sizeof (struct load_command));
1707 		if (len < 1) {
1708 			bprintf ("Error: read (lc) at 0x%08"PFMT64x"\n", off);
1709 			return false;
1710 		}
1711 		lc.cmd = r_read_ble32 (&loadc[0], bin->big_endian);
1712 		lc.cmdsize = r_read_ble32 (&loadc[4], bin->big_endian);
1713 
1714 		if (lc.cmdsize < 1 || off + lc.cmdsize > bin->size) {
1715 			bprintf ("Warning: mach0_header %d = cmdsize<1. (0x%llx vs 0x%llx)\n", i,
1716 				(ut64)(off + lc.cmdsize), (ut64)(bin->size));
1717 			break;
1718 		}
1719 
1720 		sdb_num_set (bin->kv, sdb_fmt ("mach0_cmd_%d.offset", i), off, 0);
1721 		const char *format_name = cmd_to_pf_definition (lc.cmd);
1722 		if (format_name) {
1723 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.format", i), format_name, 0);
1724 		} else {
1725 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.format", i), "[4]Ed (mach_load_command_type)cmd size", 0);
1726 		}
1727 
1728 		switch (lc.cmd) {
1729 		case LC_DATA_IN_CODE:
1730 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "data_in_code", 0);
1731 			break;
1732 		case LC_RPATH:
1733 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "rpath", 0);
1734 			//bprintf ("--->\n");
1735 			break;
1736 		case LC_SEGMENT_64:
1737 		case LC_SEGMENT:
1738 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "segment", 0);
1739 			bin->nsegs++;
1740 			if (!parse_segments (bin, off)) {
1741 				bprintf ("error parsing segment\n");
1742 				bin->nsegs--;
1743 				return false;
1744 			}
1745 			break;
1746 		case LC_SYMTAB:
1747 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "symtab", 0);
1748 			if (!parse_symtab (bin, off)) {
1749 				bprintf ("error parsing symtab\n");
1750 				return false;
1751 			}
1752 			break;
1753 		case LC_DYSYMTAB:
1754 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "dysymtab", 0);
1755 			if (!parse_dysymtab (bin, off)) {
1756 				bprintf ("error parsing dysymtab\n");
1757 				return false;
1758 			}
1759 			break;
1760 		case LC_DYLIB_CODE_SIGN_DRS:
1761 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "dylib_code_sign_drs", 0);
1762 			//bprintf ("[mach0] code is signed\n");
1763 			break;
1764 		case LC_VERSION_MIN_MACOSX:
1765 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "version_min_macosx", 0);
1766 			bin->os = 1;
1767 			// set OS = osx
1768 			//bprintf ("[mach0] Requires OSX >= x\n");
1769 			break;
1770 		case LC_VERSION_MIN_IPHONEOS:
1771 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "version_min_iphoneos", 0);
1772 			bin->os = 2;
1773 			// set OS = ios
1774 			//bprintf ("[mach0] Requires iOS >= x\n");
1775 			break;
1776 		case LC_VERSION_MIN_TVOS:
1777 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "version_min_tvos", 0);
1778 			bin->os = 4;
1779 			break;
1780 		case LC_VERSION_MIN_WATCHOS:
1781 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "version_min_watchos", 0);
1782 			bin->os = 3;
1783 			break;
1784 		case LC_UUID:
1785 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "uuid", 0);
1786 			{
1787 			struct uuid_command uc = {0};
1788 			if (off + sizeof (struct uuid_command) > bin->size) {
1789 				bprintf ("UUID out of bounds\n");
1790 				return false;
1791 			}
1792 			if (r_buf_fread_at (bin->b, off, (ut8*)&uc, "24c", 1) != -1) {
1793 				char key[128];
1794 				char val[128];
1795 				snprintf (key, sizeof (key)-1, "uuid.%d", bin->uuidn++);
1796 				r_hex_bin2str ((ut8*)&uc.uuid, 16, val);
1797 				sdb_set (bin->kv, key, val, 0);
1798 				//for (i=0;i<16; i++) bprintf ("%02x%c", uc.uuid[i], (i==15)?'\n':'-');
1799 			}
1800 			}
1801 			break;
1802 		case LC_ENCRYPTION_INFO_64:
1803 			/* TODO: the struct is probably different here */
1804 		case LC_ENCRYPTION_INFO:
1805 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "encryption_info", 0);
1806 			{
1807 			struct MACH0_(encryption_info_command) eic = {0};
1808 			ut8 seic[sizeof (struct MACH0_(encryption_info_command))] = {0};
1809 			if (off + sizeof (struct MACH0_(encryption_info_command)) > bin->size) {
1810 				bprintf ("encryption info out of bounds\n");
1811 				return false;
1812 			}
1813 			if (r_buf_read_at (bin->b, off, seic, sizeof (struct MACH0_(encryption_info_command))) != -1) {
1814 				eic.cmd = r_read_ble32 (&seic[0], bin->big_endian);
1815 				eic.cmdsize = r_read_ble32 (&seic[4], bin->big_endian);
1816 				eic.cryptoff = r_read_ble32 (&seic[8], bin->big_endian);
1817 				eic.cryptsize = r_read_ble32 (&seic[12], bin->big_endian);
1818 				eic.cryptid = r_read_ble32 (&seic[16], bin->big_endian);
1819 
1820 				bin->has_crypto = eic.cryptid;
1821 				sdb_set (bin->kv, "crypto", "true", 0);
1822 				sdb_num_set (bin->kv, "cryptid", eic.cryptid, 0);
1823 				sdb_num_set (bin->kv, "cryptoff", eic.cryptoff, 0);
1824 				sdb_num_set (bin->kv, "cryptsize", eic.cryptsize, 0);
1825 				sdb_num_set (bin->kv, "cryptheader", off, 0);
1826 			} }
1827 			break;
1828 		case LC_LOAD_DYLINKER:
1829 			{
1830 				sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "dylinker", 0);
1831 				R_FREE (bin->intrp);
1832 				//bprintf ("[mach0] load dynamic linker\n");
1833 				struct dylinker_command dy = {0};
1834 				ut8 sdy[sizeof (struct dylinker_command)] = {0};
1835 				if (off + sizeof (struct dylinker_command) > bin->size){
1836 					bprintf ("Warning: Cannot parse dylinker command\n");
1837 					return false;
1838 				}
1839 				if (r_buf_read_at (bin->b, off, sdy, sizeof (struct dylinker_command)) == -1) {
1840 					bprintf ("Warning: read (LC_DYLD_INFO) at 0x%08"PFMT64x"\n", off);
1841 				} else {
1842 					dy.cmd = r_read_ble32 (&sdy[0], bin->big_endian);
1843 					dy.cmdsize = r_read_ble32 (&sdy[4], bin->big_endian);
1844 					dy.name = r_read_ble32 (&sdy[8], bin->big_endian);
1845 
1846 					int len = dy.cmdsize;
1847 					char *buf = malloc (len+1);
1848 					if (buf) {
1849 						// wtf @ off + 0xc ?
1850 						r_buf_read_at (bin->b, off + 0xc, (ut8*)buf, len);
1851 						buf[len] = 0;
1852 						free (bin->intrp);
1853 						bin->intrp = buf;
1854 					}
1855 				}
1856 			}
1857 			break;
1858 		case LC_MAIN:
1859 			{
1860 			struct {
1861 				ut64 eo;
1862 				ut64 ss;
1863 			} ep = {0};
1864 			ut8 sep[2 * sizeof (ut64)] = {0};
1865 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "main", 0);
1866 
1867 			if (!is_first_thread) {
1868 				bprintf ("Error: LC_MAIN with other threads\n");
1869 				return false;
1870 			}
1871 			if (off + 8 > bin->size || off + sizeof (ep) > bin->size) {
1872 				bprintf ("invalid command size for main\n");
1873 				return false;
1874 			}
1875 			r_buf_read_at (bin->b, off + 8, sep, 2 * sizeof (ut64));
1876 			ep.eo = r_read_ble64 (&sep[0], bin->big_endian);
1877 			ep.ss = r_read_ble64 (&sep[8], bin->big_endian);
1878 
1879 			bin->entry = ep.eo;
1880 			bin->main_cmd = lc;
1881 
1882 			sdb_num_set (bin->kv, "mach0.entry.offset", off + 8, 0);
1883 			sdb_num_set (bin->kv, "stacksize", ep.ss, 0);
1884 
1885 			is_first_thread = false;
1886 			}
1887 			break;
1888 		case LC_UNIXTHREAD:
1889 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "unixthread", 0);
1890 			if (!is_first_thread) {
1891 				bprintf("Error: LC_UNIXTHREAD with other threads\n");
1892 				return false;
1893 			}
1894 		case LC_THREAD:
1895 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "thread", 0);
1896 			if (!parse_thread (bin, &lc, off, is_first_thread)) {
1897 				bprintf ("Cannot parse thread\n");
1898 				return false;
1899 			}
1900 			is_first_thread = false;
1901 			break;
1902 		case LC_LOAD_DYLIB:
1903 		case LC_LOAD_WEAK_DYLIB:
1904 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "load_dylib", 0);
1905 			bin->nlibs++;
1906 			if (!parse_dylib (bin, off)) {
1907 				bprintf ("Cannot parse dylib\n");
1908 				bin->nlibs--;
1909 				return false;
1910 			}
1911 			break;
1912 		case LC_DYLD_INFO:
1913 		case LC_DYLD_INFO_ONLY:
1914 			{
1915 			ut8 dyldi[sizeof (struct dyld_info_command)] = {0};
1916 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "dyld_info", 0);
1917 			bin->dyld_info = calloc (1, sizeof (struct dyld_info_command));
1918 			if (bin->dyld_info) {
1919 				if (off + sizeof (struct dyld_info_command) > bin->size){
1920 					bprintf ("Cannot parse dyldinfo\n");
1921 					R_FREE (bin->dyld_info);
1922 					return false;
1923 				}
1924 				if (r_buf_read_at (bin->b, off, dyldi, sizeof (struct dyld_info_command)) == -1) {
1925 					R_FREE (bin->dyld_info);
1926 					bprintf ("Error: read (LC_DYLD_INFO) at 0x%08"PFMT64x"\n", off);
1927 				} else {
1928 					bin->dyld_info->cmd = r_read_ble32 (&dyldi[0], bin->big_endian);
1929 					bin->dyld_info->cmdsize = r_read_ble32 (&dyldi[4], bin->big_endian);
1930 					bin->dyld_info->rebase_off = r_read_ble32 (&dyldi[8], bin->big_endian);
1931 					bin->dyld_info->rebase_size = r_read_ble32 (&dyldi[12], bin->big_endian);
1932 					bin->dyld_info->bind_off = r_read_ble32 (&dyldi[16], bin->big_endian);
1933 					bin->dyld_info->bind_size = r_read_ble32 (&dyldi[20], bin->big_endian);
1934 					bin->dyld_info->weak_bind_off = r_read_ble32 (&dyldi[24], bin->big_endian);
1935 					bin->dyld_info->weak_bind_size = r_read_ble32 (&dyldi[28], bin->big_endian);
1936 					bin->dyld_info->lazy_bind_off = r_read_ble32 (&dyldi[32], bin->big_endian);
1937 					bin->dyld_info->lazy_bind_size = r_read_ble32 (&dyldi[36], bin->big_endian);
1938 					bin->dyld_info->export_off = r_read_ble32 (&dyldi[40], bin->big_endian);
1939 					bin->dyld_info->export_size = r_read_ble32 (&dyldi[44], bin->big_endian);
1940 				}
1941 			}
1942 			}
1943 			break;
1944 		case LC_CODE_SIGNATURE:
1945 			parse_signature (bin, off);
1946 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "signature", 0);
1947 			/* ut32 dataoff
1948 			// ut32 datasize */
1949 			break;
1950 		case LC_SOURCE_VERSION:
1951 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "version", 0);
1952 			/* uint64_t  version;  */
1953 			/* A.B.C.D.E packed as a24.b10.c10.d10.e10 */
1954 			//bprintf ("mach0: TODO: Show source version\n");
1955 			break;
1956 		case LC_SEGMENT_SPLIT_INFO:
1957 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "split_info", 0);
1958 			/* TODO */
1959 			break;
1960 		case LC_FUNCTION_STARTS:
1961 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "function_starts", 0);
1962 			if (!parse_function_starts (bin, off)) {
1963 				bprintf ("Cannot parse LC_FUNCTION_STARTS\n");
1964 			}
1965 			break;
1966 		case LC_REEXPORT_DYLIB:
1967 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "dylib", 0);
1968 			/* TODO */
1969 			break;
1970 		default:
1971 			//bprintf ("mach0: Unknown header command %x\n", lc.cmd);
1972 			break;
1973 		}
1974 	}
1975 	bool has_chained_fixups = false;
1976 	for (i = 0, off = sizeof (struct MACH0_(mach_header)) + bin->header_at; \
1977 			i < bin->hdr.ncmds; i++, off += lc.cmdsize) {
1978 		len = r_buf_read_at (bin->b, off, loadc, sizeof (struct load_command));
1979 		if (len < 1) {
1980 			bprintf ("Error: read (lc) at 0x%08"PFMT64x"\n", off);
1981 			return false;
1982 		}
1983 		lc.cmd = r_read_ble32 (&loadc[0], bin->big_endian);
1984 		lc.cmdsize = r_read_ble32 (&loadc[4], bin->big_endian);
1985 
1986 		if (lc.cmdsize < 1 || off + lc.cmdsize > bin->size) {
1987 			bprintf ("Warning: mach0_header %d = cmdsize<1. (0x%llx vs 0x%llx)\n", i,
1988 				(ut64)(off + lc.cmdsize), (ut64)(bin->size));
1989 			break;
1990 		}
1991 
1992 		sdb_num_set (bin->kv, sdb_fmt ("mach0_cmd_%d.offset", i), off, 0);
1993 		const char *format_name = cmd_to_pf_definition (lc.cmd);
1994 		if (format_name) {
1995 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.format", i), format_name, 0);
1996 		} else {
1997 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.format", i), "[4]Ed (mach_load_command_type)cmd size", 0);
1998 		}
1999 
2000 		switch (lc.cmd) {
2001 		case LC_DATA_IN_CODE:
2002 			sdb_set (bin->kv, sdb_fmt ("mach0_cmd_%d.cmd", i), "data_in_code", 0);
2003 			if (bin->verbose) {
2004 				ut8 buf[8];
2005 				r_buf_read_at (bin->b, off + 8, buf, sizeof (buf));
2006 				ut32 dataoff = r_read_ble32 (buf, bin->big_endian);
2007 				ut32 datasize= r_read_ble32 (buf + 4, bin->big_endian);
2008 				eprintf ("data-in-code at 0x%x size %d\n", dataoff, datasize);
2009 				ut8 *db = (ut8*)malloc (datasize);
2010 				if (db) {
2011 					r_buf_read_at (bin->b, dataoff, db, datasize);
2012 					// TODO table of non-instructions regions in __text
2013 					int j;
2014 					for (j = 0; j < datasize; j += 8) {
2015 						ut32 dw = r_read_ble32 (db + j, bin->big_endian);
2016 						// int kind = r_read_ble16 (db + i + 4 + 2, bin->big_endian);
2017 						int len = r_read_ble16 (db + j + 4, bin->big_endian);
2018 						ut64 va = offset_to_vaddr(bin, dw);
2019 					//	eprintf ("# 0x%d -> 0x%x\n", dw, va);
2020 					//	eprintf ("0x%x kind %d len %d\n", dw, kind, len);
2021 						eprintf ("Cd 4 %d @ 0x%"PFMT64x"\n", len / 4, va);
2022 					}
2023 				}
2024 			}
2025 			break;
2026 		case LC_DYLD_EXPORTS_TRIE:
2027 			if (bin->verbose) {
2028 				ut8 buf[8];
2029 				r_buf_read_at (bin->b, off + 8, buf, sizeof (buf));
2030 				ut32 dataoff = r_read_ble32 (buf, bin->big_endian);
2031 				ut32 datasize= r_read_ble32 (buf + 4, bin->big_endian);
2032 				eprintf ("exports trie at 0x%x size %d\n", dataoff, datasize);
2033 			}
2034 			break;
2035 		case LC_DYLD_CHAINED_FIXUPS: {
2036 				ut8 buf[8];
2037 				if (r_buf_read_at (bin->b, off + 8, buf, sizeof (buf)) == sizeof (buf)) {
2038 					ut32 dataoff = r_read_ble32 (buf, bin->big_endian);
2039 					ut32 datasize= r_read_ble32 (buf + 4, bin->big_endian);
2040 					if (bin->verbose) {
2041 						eprintf ("chained fixups at 0x%x size %d\n", dataoff, datasize);
2042 					}
2043 					has_chained_fixups = parse_chained_fixups (bin, dataoff, datasize);
2044 				}
2045 			}
2046 			break;
2047 		}
2048 	}
2049 
2050 	if (!has_chained_fixups && bin->hdr.cputype == CPU_TYPE_ARM64 &&
2051 		(bin->hdr.cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E) {
2052 		if (bin->verbose) {
2053 			eprintf ("reconstructing chained fixups\n");
2054 		}
2055 		reconstruct_chained_fixup (bin);
2056 	}
2057 	return true;
2058 }
2059 
init(struct MACH0_ (obj_t)* mo)2060 static bool init(struct MACH0_(obj_t) *mo) {
2061 	if (!init_hdr (mo)) {
2062 		return false;
2063 	}
2064 	if (!init_items (mo)) {
2065 		Eprintf ("Warning: Cannot initialize items\n");
2066 	}
2067 	mo->baddr = MACH0_(get_baddr)(mo);
2068 	return true;
2069 }
2070 
MACH0_(mach0_free)2071 void *MACH0_(mach0_free)(struct MACH0_(obj_t) *mo) {
2072 	if (!mo) {
2073 		return NULL;
2074 	}
2075 
2076 	size_t i;
2077 	if (mo->symbols) {
2078 		for (i = 0; !mo->symbols[i].last; i++) {
2079 			free (mo->symbols[i].name);
2080 		}
2081 		free (mo->symbols);
2082 	}
2083 	free (mo->segs);
2084 	free (mo->sects);
2085 	free (mo->symtab);
2086 	free (mo->symstr);
2087 	free (mo->indirectsyms);
2088 	free (mo->imports_by_ord);
2089 	if (mo->imports_by_name) {
2090 		ht_pp_free (mo->imports_by_name);
2091 	}
2092 	free (mo->dyld_info);
2093 	free (mo->toc);
2094 	free (mo->modtab);
2095 	free (mo->libs);
2096 	free (mo->func_start);
2097 	free (mo->signature);
2098 	free (mo->intrp);
2099 	free (mo->compiler);
2100 	if (mo->chained_starts) {
2101 		for (i = 0; i < mo->nsegs; i++) {
2102 			if (mo->chained_starts[i]) {
2103 				free (mo->chained_starts[i]->page_start);
2104 				free (mo->chained_starts[i]);
2105 			}
2106 		}
2107 		free (mo->chained_starts);
2108 	}
2109 	r_buf_free (mo->b);
2110 	free (mo);
2111 	return NULL;
2112 }
2113 
MACH0_(opts_set_default)2114 void MACH0_(opts_set_default)(struct MACH0_(opts_t) *options, RBinFile *bf) {
2115 	r_return_if_fail (options && bf && bf->rbin);
2116 	options->header_at = 0;
2117 	options->verbose = bf->rbin->verbose;
2118 }
2119 
duplicate_ptr(void * p)2120 static void *duplicate_ptr(void *p) {
2121 	return p;
2122 }
2123 
free_only_key(HtPPKv * kv)2124 static void free_only_key(HtPPKv *kv) {
2125 	free (kv->key);
2126 }
2127 
ptr_size(void * c)2128 static size_t ptr_size(void *c) {
2129 	// :D
2130 	return 8;
2131 }
2132 
2133 // XXX should be deprecated its never called
MACH0_(obj_t)2134 struct MACH0_(obj_t) *MACH0_(mach0_new)(const char *file, struct MACH0_(opts_t) *options) {
2135 	struct MACH0_(obj_t) *bin = R_NEW0 (struct MACH0_(obj_t));
2136 	if (!bin) {
2137 		return NULL;
2138 	}
2139 	if (options) {
2140 		bin->verbose = options->verbose;
2141 		bin->header_at = options->header_at;
2142 	}
2143 	bin->file = file;
2144 	size_t binsz;
2145 	ut8 *buf = (ut8 *)r_file_slurp (file, &binsz);
2146 	bin->size = binsz;
2147 	if (!buf) {
2148 		return MACH0_(mach0_free)(bin);
2149 	}
2150 	bin->b = r_buf_new ();
2151 	if (!r_buf_set_bytes (bin->b, buf, bin->size)) {
2152 		free (buf);
2153 		return MACH0_(mach0_free)(bin);
2154 	}
2155 	free (buf);
2156 	bin->dyld_info = NULL;
2157 	if (!init (bin)) {
2158 		return MACH0_(mach0_free)(bin);
2159 	}
2160 	bin->imports_by_ord_size = 0;
2161 	bin->imports_by_ord = NULL;
2162 	bin->imports_by_name = ht_pp_new ((HtPPDupValue)duplicate_ptr, free_only_key, (HtPPCalcSizeV)ptr_size);
2163 	return bin;
2164 }
2165 
MACH0_(obj_t)2166 struct MACH0_(obj_t) *MACH0_(new_buf)(RBuffer *buf, struct MACH0_(opts_t) *options) {
2167 	r_return_val_if_fail (buf, NULL);
2168 	struct MACH0_(obj_t) *bin = R_NEW0 (struct MACH0_(obj_t));
2169 	if (bin) {
2170 		bin->b = r_buf_ref (buf);
2171 		bin->main_addr = UT64_MAX;
2172 		bin->kv = sdb_new (NULL, "bin.mach0", 0);
2173 		bin->size = r_buf_size (bin->b);
2174 		if (options) {
2175 			bin->verbose = options->verbose;
2176 			bin->header_at = options->header_at;
2177 		}
2178 		if (!init (bin)) {
2179 			return MACH0_(mach0_free)(bin);
2180 		}
2181 	}
2182 	return bin;
2183 }
2184 
2185 // prot: r = 1, w = 2, x = 4
2186 // perm: r = 4, w = 2, x = 1
prot2perm(int x)2187 static int prot2perm(int x) {
2188 	int r = 0;
2189 	if (x & 1) {
2190 		r |= 4;
2191 	}
2192 	if (x & 2) {
2193 		r |= 2;
2194 	}
2195 	if (x & 4) {
2196 		r |= 1;
2197 	}
2198 	return r;
2199 }
2200 
__isDataSection(RBinSection * sect)2201 static bool __isDataSection(RBinSection *sect) {
2202 	if (strstr (sect->name, "_cstring")) {
2203 		return true;
2204 	}
2205 	if (strstr (sect->name, "_objc_methname")) {
2206 		return true;
2207 	}
2208 	if (strstr (sect->name, "_objc_classname")) {
2209 		return true;
2210 	}
2211 	if (strstr (sect->name, "_objc_methtype")) {
2212 		return true;
2213 	}
2214 	return false;
2215 }
2216 
MACH0_(get_segments)2217 RList *MACH0_(get_segments)(RBinFile *bf) {
2218 	struct MACH0_(obj_t) *bin = bf->o->bin_obj;
2219 	RList *list = r_list_newf ((RListFree)r_bin_section_free);
2220 	size_t i, j;
2221 
2222 	/* for core files */
2223 	if (bin->nsegs > 0) {
2224 		struct MACH0_(segment_command) *seg;
2225 		for (i = 0; i < bin->nsegs; i++) {
2226 			seg = &bin->segs[i];
2227 			if (!seg->initprot) {
2228 				continue;
2229 			}
2230 			RBinSection *s = r_bin_section_new (NULL);
2231 			if (!s) {
2232 				break;
2233 			}
2234 			s->vaddr = seg->vmaddr;
2235 			s->vsize = seg->vmsize;
2236 			s->size = seg->vmsize;
2237 			s->paddr = seg->fileoff;
2238 			s->paddr += bf->o->boffset;
2239 			//TODO s->flags = seg->flags;
2240 			s->name = r_str_ndup (seg->segname, 16);
2241 			s->is_segment = true;
2242 			r_str_filter (s->name, -1);
2243 			s->perm = prot2perm (seg->initprot);
2244 			s->add = true;
2245 			r_list_append (list, s);
2246 		}
2247 	}
2248 	if (bin->nsects > 0) {
2249 		int last_section = R_MIN (bin->nsects, 128); // maybe drop this limit?
2250 		for (i = 0; i < last_section; i++) {
2251 			RBinSection *s = R_NEW0 (RBinSection);
2252 			if (!s) {
2253 				break;
2254 			}
2255 			s->vaddr = (ut64)bin->sects[i].addr;
2256 			s->vsize = (ut64)bin->sects[i].size;
2257 			s->is_segment = false;
2258 			s->size = (bin->sects[i].flags == S_ZEROFILL) ? 0 : (ut64)bin->sects[i].size;
2259 			// XXX flags
2260 			s->paddr = (ut64)bin->sects[i].offset;
2261 			int segment_index = 0;
2262 			//s->perm =prot2perm (bin->segs[j].initprot);
2263 			for (j = 0; j < bin->nsegs; j++) {
2264 				if (s->vaddr >= bin->segs[j].vmaddr &&
2265 						s->vaddr < (bin->segs[j].vmaddr + bin->segs[j].vmsize)) {
2266 					s->perm = prot2perm (bin->segs[j].initprot);
2267 					segment_index = j;
2268 					break;
2269 				}
2270 			}
2271 			char *section_name = r_str_ndup (bin->sects[i].sectname, 16);
2272 			char *segment_name = r_str_newf ("%zu.%s", i, bin->segs[segment_index].segname);
2273 			s->name = r_str_newf ("%s.%s", segment_name, section_name);
2274 			s->is_data = __isDataSection (s);
2275 			if (strstr (section_name, "interpos") || strstr (section_name, "__mod_")) {
2276 #if R_BIN_MACH064
2277 				const int ws = 8;
2278 #else
2279 				const int ws = 4;
2280 #endif
2281 				s->format = r_str_newf ("Cd %d[%"PFMT64d"]", ws, s->vsize / ws);
2282 			}
2283 			r_list_append (list, s);
2284 			free (segment_name);
2285 			free (section_name);
2286 		}
2287 	}
2288 	return list;
2289 }
2290 
2291 // XXX this function is called so many times
MACH0_(get_sections)2292 struct section_t *MACH0_(get_sections)(struct MACH0_(obj_t) *bin) {
2293 	r_return_val_if_fail (bin, NULL);
2294 	struct section_t *sections;
2295 	char sectname[64], raw_segname[17];
2296 	size_t i, j, to;
2297 
2298 	/* for core files */
2299 	if (bin->nsects < 1 && bin->nsegs > 0) {
2300 		struct MACH0_(segment_command) *seg;
2301 		if (!(sections = calloc ((bin->nsegs + 1), sizeof (struct section_t)))) {
2302 			return NULL;
2303 		}
2304 		for (i = 0; i < bin->nsegs; i++) {
2305 			seg = &bin->segs[i];
2306 			sections[i].addr = seg->vmaddr;
2307 			sections[i].offset = seg->fileoff;
2308 			sections[i].size = seg->vmsize;
2309 			sections[i].vsize = seg->vmsize;
2310 			sections[i].align = 4096;
2311 			sections[i].flags = seg->flags;
2312 			r_str_ncpy (sectname, seg->segname, 16);
2313 			sectname[16] = 0;
2314 			r_str_filter (sectname, -1);
2315 			// hack to support multiple sections with same name
2316 			sections[i].perm = prot2perm (seg->initprot);
2317 			sections[i].last = 0;
2318 		}
2319 		sections[i].last = 1;
2320 		return sections;
2321 	}
2322 
2323 	if (!bin->sects) {
2324 		return NULL;
2325 	}
2326 	to = R_MIN (bin->nsects, 128); // limit number of sections here to avoid fuzzed bins
2327 	if (to < 1) {
2328 		return NULL;
2329 	}
2330 	if (!(sections = calloc (bin->nsects + 1, sizeof (struct section_t)))) {
2331 		return NULL;
2332 	}
2333 	for (i = 0; i < to; i++) {
2334 		sections[i].offset = (ut64)bin->sects[i].offset;
2335 		sections[i].addr = (ut64)bin->sects[i].addr;
2336 		sections[i].size = (bin->sects[i].flags == S_ZEROFILL) ? 0 : (ut64)bin->sects[i].size;
2337 		sections[i].vsize = (ut64)bin->sects[i].size;
2338 		sections[i].align = bin->sects[i].align;
2339 		sections[i].flags = bin->sects[i].flags;
2340 		r_str_ncpy (sectname, bin->sects[i].sectname, 17);
2341 		r_str_filter (sectname, -1);
2342 		r_str_ncpy (raw_segname, bin->sects[i].segname, 16);
2343 		for (j = 0; j < bin->nsegs; j++) {
2344 			if (sections[i].addr >= bin->segs[j].vmaddr &&
2345 				sections[i].addr < (bin->segs[j].vmaddr + bin->segs[j].vmsize)) {
2346 				sections[i].perm = prot2perm (bin->segs[j].initprot);
2347 				break;
2348 			}
2349 		}
2350 		snprintf (sections[i].name, sizeof (sections[i].name),
2351 			"%d.%s.%s", (int)i, raw_segname, sectname);
2352 		sections[i].last = 0;
2353 	}
2354 	sections[i].last = 1;
2355 	return sections;
2356 }
2357 
parse_import_stub(struct MACH0_ (obj_t)* bin,struct symbol_t * symbol,int idx)2358 static bool parse_import_stub(struct MACH0_(obj_t) *bin, struct symbol_t *symbol, int idx) {
2359 	size_t i, j, nsyms, stridx;
2360 	const char *symstr;
2361 	if (idx < 0) {
2362 		return false;
2363 	}
2364 	symbol->offset = 0LL;
2365 	symbol->addr = 0LL;
2366 	symbol->name = NULL;
2367 	symbol->is_imported = true;
2368 
2369 	if (!bin || !bin->sects) {
2370 		return false;
2371 	}
2372 	for (i = 0; i < bin->nsects; i++) {
2373 		if ((bin->sects[i].flags & SECTION_TYPE) == S_SYMBOL_STUBS && bin->sects[i].reserved2 > 0) {
2374 			ut64 sect_size = bin->sects[i].size;
2375 			ut32 sect_fragment = bin->sects[i].reserved2;
2376 			if (bin->sects[i].offset > bin->size) {
2377 				bprintf ("mach0: section offset starts way beyond the end of the file\n");
2378 				continue;
2379 			}
2380 			if (sect_size > bin->size) {
2381 				bprintf ("mach0: Invalid symbol table size\n");
2382 				sect_size = bin->size - bin->sects[i].offset;
2383 			}
2384 			nsyms = (int)(sect_size / sect_fragment);
2385 			for (j = 0; j < nsyms; j++) {
2386 				if (bin->sects) {
2387 					if (bin->sects[i].reserved1 + j >= bin->nindirectsyms) {
2388 						continue;
2389 					}
2390 				}
2391 				if (bin->indirectsyms) {
2392 					if (idx != bin->indirectsyms[bin->sects[i].reserved1 + j]) {
2393 						continue;
2394 					}
2395 				}
2396 				if (idx > bin->nsymtab) {
2397 					continue;
2398 				}
2399 				symbol->type = R_BIN_MACH0_SYMBOL_TYPE_LOCAL;
2400 				int delta = j * bin->sects[i].reserved2;
2401 				if (delta < 0) {
2402 					bprintf ("mach0: corrupted reserved2 value leads to int overflow.\n");
2403 					continue;
2404 				}
2405 				symbol->offset = bin->sects[i].offset + delta;
2406 				symbol->addr = bin->sects[i].addr + delta;
2407 				symbol->size = 0;
2408 				stridx = bin->symtab[idx].n_strx;
2409 				if (stridx < bin->symstrlen) {
2410 					symstr = (char *)bin->symstr + stridx;
2411 				} else {
2412 					symstr = "???";
2413 				}
2414 				// Remove the extra underscore that every import seems to have in Mach-O.
2415 				if (*symstr == '_') {
2416 					symstr++;
2417 				}
2418 				symbol->name = strdup (symstr);
2419 				return true;
2420 			}
2421 		}
2422 	}
2423 	return false;
2424 }
2425 
inSymtab(HtPP * hash,const char * name,ut64 addr)2426 static int inSymtab(HtPP *hash, const char *name, ut64 addr) {
2427 	bool found = false;
2428 	char *key = r_str_newf ("%"PFMT64x".%s", addr, name);
2429 	ht_pp_find (hash, key, &found);
2430 	if (found) {
2431 		free (key);
2432 		return true;
2433 	}
2434 	ht_pp_insert (hash, key, "1");
2435 	free (key);
2436 	return false;
2437 }
2438 
get_name(struct MACH0_ (obj_t)* mo,ut32 stridx,bool filter)2439 static char *get_name(struct MACH0_(obj_t) *mo, ut32 stridx, bool filter) {
2440 	size_t i = 0;
2441 	if (!mo->symstr || stridx >= mo->symstrlen) {
2442 		return NULL;
2443 	}
2444 	int len = mo->symstrlen - stridx;
2445 	const char *symstr = (const char*)mo->symstr + stridx;
2446 	for (i = 0; i < len; i++) {
2447 		if ((ut8)(symstr[i] & 0xff) == 0xff || !symstr[i]) {
2448 			len = i;
2449 			break;
2450 		}
2451 	}
2452 	if (len > 0) {
2453 		char *res = r_str_ndup (symstr, len);
2454 		if (filter) {
2455 			r_str_filter (res, -1);
2456 		}
2457 		return res;
2458 	}
2459 	return NULL;
2460 }
2461 
walk_exports(struct MACH0_ (obj_t)* bin,RExportsIterator iterator,void * ctx)2462 static int walk_exports(struct MACH0_(obj_t) *bin, RExportsIterator iterator, void * ctx) {
2463 	r_return_val_if_fail (bin, 0);
2464 	if (!bin->dyld_info) {
2465 		return 0;
2466 	}
2467 
2468 	size_t count = 0;
2469 	ut8 *p = NULL;
2470 	ut8 * trie = NULL;
2471 	RList * states = NULL;
2472 	ut64 size = bin->dyld_info->export_size;
2473 	if (!size) {
2474 		return count;
2475 	}
2476 	trie = calloc (size + 1, 1);
2477 	if (!trie) {
2478 		return count;
2479 	}
2480 	ut8 * end = trie + size;
2481 
2482 	if (r_buf_read_at (bin->b, bin->dyld_info->export_off, trie, bin->dyld_info->export_size) != size) {
2483 		goto beach;
2484 	}
2485 
2486 	states = r_list_newf ((RListFree)free);
2487 	if (!states) {
2488 		goto beach;
2489 	}
2490 
2491 	RTrieState * root = R_NEW0 (RTrieState);
2492 	if (!root) {
2493 		goto beach;
2494 	}
2495 	root->node = trie;
2496 	root->i = 0;
2497 	root->label = NULL;
2498 	r_list_push (states, root);
2499 
2500 	do {
2501 		RTrieState * state = r_list_get_top (states);
2502 		p = state->node;
2503 		ut64 len = read_uleb128 (&p, end);
2504 		if (len == UT64_MAX) {
2505 			break;
2506 		}
2507 		if (len) {
2508 			ut64 flags = read_uleb128 (&p, end);
2509 			if (flags == UT64_MAX) {
2510 				break;
2511 			}
2512 			ut64 offset = read_uleb128 (&p, end);
2513 			if (offset == UT64_MAX) {
2514 				break;
2515 			}
2516 			ut64 resolver = 0;
2517 			bool isReexport = flags & EXPORT_SYMBOL_FLAGS_REEXPORT;
2518 			bool hasResolver = flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER;
2519 			if (hasResolver) {
2520 				ut64 res = read_uleb128 (&p, end);
2521 				if (res == UT64_MAX) {
2522 					break;
2523 				}
2524 				resolver = res + bin->header_at;
2525 			} else if (isReexport) {
2526 				p += strlen ((char*) p) + 1;
2527 				// TODO: handle this
2528 			}
2529 			if (!isReexport) {
2530 				offset += bin->header_at;
2531 			}
2532 			if (iterator && !isReexport) {
2533 				char * name = NULL;
2534 				RListIter *iter;
2535 				RTrieState *s;
2536 				r_list_foreach (states, iter, s) {
2537 					if (!s->label) {
2538 						continue;
2539 					}
2540 					name = r_str_append (name, s->label);
2541 				}
2542 				if (name == NULL) {
2543 					eprintf ("malformed export trie\n");
2544 					goto beach;
2545 				}
2546 				if (hasResolver) {
2547 					char * stub_name = r_str_newf ("stub.%s", name);
2548 					iterator (bin, stub_name, flags, offset, ctx);
2549 					iterator (bin, name, flags, resolver, ctx);
2550 					R_FREE (stub_name);
2551 				} else {
2552 					iterator (bin, name, flags, offset, ctx);
2553 				}
2554 				R_FREE (name);
2555 			}
2556 			if (!isReexport) {
2557 				if (hasResolver) {
2558 					count++;
2559 				}
2560 				count++;
2561 			}
2562 		}
2563 		ut64 child_count = read_uleb128 (&p, end);
2564 		if (child_count == UT64_MAX) {
2565 			goto beach;
2566 		}
2567 		if (state->i == child_count) {
2568 			free (r_list_pop (states));
2569 			continue;
2570 		}
2571 		if (!state->next_child) {
2572 			state->next_child = p;
2573 		} else {
2574 			p = state->next_child;
2575 		}
2576 		RTrieState * next = R_NEW0 (RTrieState);
2577 		if (!next) {
2578 			goto beach;
2579 		}
2580 		next->label = (char *) p;
2581 		p += strlen (next->label) + 1;
2582 		if (p >= end) {
2583 			eprintf ("malformed export trie\n");
2584 			R_FREE (next);
2585 			goto beach;
2586 		}
2587 		ut64 tr = read_uleb128 (&p, end);
2588 		if (tr == UT64_MAX) {
2589 			goto beach;
2590 		}
2591 		next->node = tr + trie;
2592 		if (next->node >= end) {
2593 			eprintf ("malformed export trie\n");
2594 			R_FREE (next);
2595 			goto beach;
2596 		}
2597 		{
2598 			// avoid loops
2599 			RListIter *it;
2600 			RTrieState *s;
2601 			r_list_foreach (states, it, s) {
2602 				if (s->node == next->node) {
2603 					eprintf ("malformed export trie\n");
2604 					R_FREE (next);
2605 					goto beach;
2606 				}
2607 			}
2608 		}
2609 		next->i = 0;
2610 		state->i++;
2611 		state->next_child = p;
2612 		r_list_push (states, next);
2613 	} while (r_list_length (states));
2614 
2615 beach:
2616 	r_list_free (states);
2617 	R_FREE (trie);
2618 	return count;
2619 }
2620 
fill_exports_list(struct MACH0_ (obj_t)* bin,const char * name,ut64 flags,ut64 offset,void * ctx)2621 static void fill_exports_list(struct MACH0_(obj_t) *bin, const char *name, ut64 flags, ut64 offset, void * ctx) {
2622 	RList *list = (RList*) ctx;
2623 	RBinSymbol *sym = R_NEW0 (RBinSymbol);
2624 	if (!sym) {
2625 		return;
2626 	}
2627 	sym->vaddr = offset_to_vaddr (bin, offset);
2628 	sym->paddr = offset;
2629 	sym->type = "EXT";
2630 	sym->name = strdup (name);
2631 	sym->bind = R_BIN_BIND_GLOBAL_STR;
2632 	r_list_append (list, sym);
2633 }
2634 
2635 // TODO: Return RList<RBinSymbol> // 2x speedup
MACH0_(get_symbols_list)2636 const RList *MACH0_(get_symbols_list)(struct MACH0_(obj_t) *bin) {
2637 	static RList * cache = NULL; // XXX DONT COMMIT WITH THIS
2638 	struct symbol_t *symbols;
2639 	size_t j, s, symbols_size, symbols_count;
2640 	ut32 to, from;
2641 	size_t i;
2642 
2643 	r_return_val_if_fail (bin, NULL);
2644 	if (cache) {
2645 		return cache;
2646 	}
2647 	RList *list = r_list_newf ((RListFree)r_bin_symbol_free);
2648 	cache = list;
2649 
2650 	HtPP *hash = ht_pp_new0 ();
2651 	if (!hash) {
2652 		return NULL;
2653 	}
2654 
2655 	walk_exports (bin, fill_exports_list, list);
2656 	if (r_list_length (list)) {
2657 		RListIter *it;
2658 		RBinSymbol *s;
2659 		r_list_foreach (list, it, s) {
2660 			inSymtab (hash, s->name, s->vaddr);
2661 		}
2662 	}
2663 
2664 	if (!bin->symtab || !bin->symstr) {
2665 		return list;
2666 	}
2667 	/* parse dynamic symbol table */
2668 	symbols_count = (bin->dysymtab.nextdefsym + \
2669 			bin->dysymtab.nlocalsym + \
2670 			bin->dysymtab.nundefsym );
2671 	symbols_count += bin->nsymtab;
2672 	symbols_size = (symbols_count + 1) * 2 * sizeof (struct symbol_t);
2673 
2674 	if (symbols_size < 1) {
2675 		return NULL;
2676 	}
2677 	if (!(symbols = calloc (1, symbols_size))) {
2678 		return NULL;
2679 	}
2680 	j = 0; // symbol_idx
2681 	bin->main_addr = 0;
2682 	int bits = MACH0_(get_bits_from_hdr) (&bin->hdr);
2683 	for (s = 0; s < 2; s++) {
2684 		switch (s) {
2685 		case 0:
2686 			from = bin->dysymtab.iextdefsym;
2687 			to = from + bin->dysymtab.nextdefsym;
2688 			break;
2689 		case 1:
2690 			from = bin->dysymtab.ilocalsym;
2691 			to = from + bin->dysymtab.nlocalsym;
2692 			break;
2693 #if NOT_USED
2694 		case 2:
2695 			from = bin->dysymtab.iundefsym;
2696 			to = from + bin->dysymtab.nundefsym;
2697 			break;
2698 #endif
2699 		}
2700 		if (from == to) {
2701 			continue;
2702 		}
2703 
2704 		from = R_MIN (R_MAX (0, from), symbols_size / sizeof (struct symbol_t));
2705 		to = R_MIN (R_MIN (to, bin->nsymtab), symbols_size / sizeof (struct symbol_t));
2706 
2707 		ut32 maxsymbols = symbols_size / sizeof (struct symbol_t);
2708 		if (symbols_count >= maxsymbols) {
2709 			symbols_count = maxsymbols - 1;
2710 			eprintf ("macho warning: Symbol table truncated\n");
2711 		}
2712 		for (i = from; i < to && j < symbols_count; i++, j++) {
2713 			RBinSymbol *sym = R_NEW0 (RBinSymbol);
2714 			sym->vaddr = bin->symtab[i].n_value;
2715 			sym->paddr = addr_to_offset (bin, sym->vaddr);
2716 			symbols[j].size = 0; /* TODO: Is it anywhere? */
2717 			sym->bits = bin->symtab[i].n_desc & N_ARM_THUMB_DEF ? 16 : bits;
2718 
2719 			if (bin->symtab[i].n_type & N_EXT) {
2720 				sym->type = "EXT";
2721 			} else {
2722 				sym->type = "LOCAL";
2723 			}
2724 			int stridx = bin->symtab[i].n_strx;
2725 			char *sym_name = get_name (bin, stridx, false);
2726 			if (sym_name) {
2727 				sym->name = sym_name;
2728 				if (!bin->main_addr || bin->main_addr == UT64_MAX) {
2729 					const char *name = sym->name;
2730 					if (!strcmp (name, "__Dmain")) {
2731 						bin->main_addr = symbols[j].addr;
2732 					} else if (strstr (name, "4main") && !strstr (name, "STATIC")) {
2733 						bin->main_addr = symbols[j].addr;
2734 					} else if (!strcmp (name, "_main")) {
2735 						bin->main_addr = symbols[j].addr;
2736 					} else if (!strcmp (name, "main")) {
2737 						bin->main_addr = symbols[j].addr;
2738 					}
2739 				}
2740 			} else {
2741 				sym->name = r_str_newf ("unk%zu", i);
2742 			}
2743 			if (!inSymtab (hash, sym->name, sym->vaddr)) {
2744 				r_list_append (list, sym);
2745 			}
2746 		}
2747 	}
2748 	to = R_MIN ((ut32)bin->nsymtab, bin->dysymtab.iundefsym + bin->dysymtab.nundefsym);
2749 	for (i = bin->dysymtab.iundefsym; i < to; i++) {
2750 		struct symbol_t symbol;
2751 		if (j > symbols_count) {
2752 			bprintf ("mach0-get-symbols: error\n");
2753 			break;
2754 		}
2755 		if (parse_import_stub (bin, &symbol, i)) {
2756 			j++;
2757 			RBinSymbol *sym = R_NEW0 (RBinSymbol);
2758 			sym->vaddr = symbol.addr;
2759 			sym->paddr = symbol.offset;
2760 			sym->name = symbol.name;
2761 			if (!sym->name) {
2762 				sym->name = r_str_newf ("unk%zu", i);
2763 			}
2764 			sym->is_imported = symbol.is_imported;
2765 			r_list_append (list, sym);
2766 		}
2767 	}
2768 
2769 	for (i = 0; i < bin->nsymtab; i++) {
2770 		struct MACH0_(nlist) *st = &bin->symtab[i];
2771 		// 0 is for imports
2772 		// 1 is for symbols
2773 		// 2 is for func.eh (exception handlers?)
2774 		int section = st->n_sect;
2775 		if (section == 1 && j < symbols_count) { // text ??st->n_type == 1) maybe wrong
2776 			RBinSymbol *sym = R_NEW0(RBinSymbol);
2777 			/* is symbol */
2778 			sym->vaddr = st->n_value;
2779 			sym->paddr = addr_to_offset (bin, symbols[j].addr);
2780 			sym->is_imported = symbols[j].is_imported;
2781 			if (st->n_type & N_EXT) {
2782 				sym->type = "EXT";
2783 			} else {
2784 				sym->type = "LOCAL";
2785 			}
2786 			char *sym_name = get_name (bin, st->n_strx, false);
2787 			if (sym_name) {
2788 				sym->name = sym_name;
2789 				if (inSymtab (hash, sym->name, sym->vaddr)) {
2790 					r_bin_symbol_free (sym);
2791 					continue;
2792 				}
2793 				if (!bin->main_addr || bin->main_addr == UT64_MAX) {
2794 					const char *name = sym->name;
2795 					if (!strcmp (name, "__Dmain")) {
2796 						bin->main_addr = symbols[i].addr;
2797 					} else if (strstr (name, "4main") && !strstr (name, "STATIC")) {
2798 						bin->main_addr = symbols[i].addr;
2799 					} else if (!strcmp (symbols[i].name, "_main")) {
2800 						bin->main_addr = symbols[i].addr;
2801 					}
2802 				}
2803 			} else {
2804 				sym->name = r_str_newf ("unk%zu", i);
2805 			}
2806 			r_list_append (list, sym);
2807 			j++;
2808 		}
2809 	}
2810 	ht_pp_free (hash);
2811 	// bin->symbols = symbols;
2812     free (symbols);
2813 	return list;
2814 }
2815 
assign_export_symbol_t(struct MACH0_ (obj_t)* bin,const char * name,ut64 flags,ut64 offset,void * ctx)2816 static void assign_export_symbol_t(struct MACH0_(obj_t) *bin, const char *name, ut64 flags, ut64 offset, void *ctx) {
2817 	RSymCtx *sym_ctx = (RSymCtx*) ctx;
2818 	int j = sym_ctx->j;
2819 	if (j < sym_ctx->symbols_count) {
2820 		sym_ctx->symbols[j].offset = offset;
2821 		sym_ctx->symbols[j].addr = offset_to_vaddr (bin, offset);
2822 		if (inSymtab (sym_ctx->hash, name, sym_ctx->symbols[j].addr)) {
2823 			return;
2824 		}
2825 		sym_ctx->symbols[j].size = 0;
2826 		sym_ctx->symbols[j].type = R_BIN_MACH0_SYMBOL_TYPE_EXT;
2827 		sym_ctx->symbols[j].name = strdup (name);
2828 		sym_ctx->j++;
2829 	}
2830 }
2831 
MACH0_(get_symbols)2832 const struct symbol_t *MACH0_(get_symbols)(struct MACH0_(obj_t) *bin) {
2833 	struct symbol_t *symbols;
2834 	int j, s, stridx, symbols_size, symbols_count;
2835 	ut32 to, from, i;
2836 
2837 	if (bin->symbols) {
2838 		return bin->symbols;
2839 	}
2840 
2841 	HtPP *hash = ht_pp_new0 ();
2842 	if (!hash) {
2843 		return NULL;
2844 	}
2845 
2846 	r_return_val_if_fail (bin, NULL);
2847 	int n_exports = walk_exports (bin, NULL, NULL);
2848 
2849 	symbols_count = n_exports;
2850 	j = 0; // symbol_idx
2851 
2852 	int bits = MACH0_(get_bits_from_hdr) (&bin->hdr);
2853 	if (bin->symtab && bin->symstr) {
2854 		/* parse dynamic symbol table */
2855 		symbols_count = (bin->dysymtab.nextdefsym + \
2856 				bin->dysymtab.nlocalsym + \
2857 				bin->dysymtab.nundefsym );
2858 		symbols_count += bin->nsymtab;
2859 		if (symbols_count < 0 || ((st64)symbols_count * 2) > ST32_MAX) {
2860 			eprintf ("Symbols count overflow\n");
2861 			ht_pp_free (hash);
2862 			return NULL;
2863 		}
2864 		symbols_size = (symbols_count + 1) * 2 * sizeof (struct symbol_t);
2865 
2866 		if (symbols_size < 1) {
2867 			ht_pp_free (hash);
2868 			return NULL;
2869 		}
2870 		if (!(symbols = calloc (1, symbols_size))) {
2871 			ht_pp_free (hash);
2872 			return NULL;
2873 		}
2874 		bin->main_addr = 0;
2875 		for (s = 0; s < 2; s++) {
2876 			switch (s) {
2877 			case 0:
2878 				from = bin->dysymtab.iextdefsym;
2879 				to = from + bin->dysymtab.nextdefsym;
2880 				break;
2881 			case 1:
2882 				from = bin->dysymtab.ilocalsym;
2883 				to = from + bin->dysymtab.nlocalsym;
2884 				break;
2885 #if NOT_USED
2886 			case 2:
2887 				from = bin->dysymtab.iundefsym;
2888 				to = from + bin->dysymtab.nundefsym;
2889 				break;
2890 #endif
2891 			}
2892 			if (from == to) {
2893 				continue;
2894 			}
2895 
2896 			from = R_MIN (R_MAX (0, from), symbols_size / sizeof (struct symbol_t));
2897 			to = R_MIN (R_MIN (to, bin->nsymtab), symbols_size / sizeof (struct symbol_t));
2898 
2899 			ut32 maxsymbols = symbols_size / sizeof (struct symbol_t);
2900 			if (symbols_count >= maxsymbols) {
2901 				symbols_count = maxsymbols - 1;
2902 				eprintf ("macho warning: Symbol table truncated\n");
2903 			}
2904 			for (i = from; i < to && j < symbols_count; i++, j++) {
2905 				symbols[j].offset = addr_to_offset (bin, bin->symtab[i].n_value);
2906 				symbols[j].addr = bin->symtab[i].n_value;
2907 				symbols[j].size = 0; /* TODO: Is it anywhere? */
2908 				symbols[j].bits = bin->symtab[i].n_desc & N_ARM_THUMB_DEF ? 16 : bits;
2909 				symbols[j].is_imported = false;
2910 				symbols[j].type = (bin->symtab[i].n_type & N_EXT)
2911 					? R_BIN_MACH0_SYMBOL_TYPE_EXT
2912 					: R_BIN_MACH0_SYMBOL_TYPE_LOCAL;
2913 				stridx = bin->symtab[i].n_strx;
2914 				symbols[j].name = get_name (bin, stridx, false);
2915 				symbols[j].last = false;
2916 
2917 				const char *name = symbols[j].name;
2918 				if (bin->main_addr == 0 && name) {
2919 					if (!strcmp (name, "__Dmain")) {
2920 						bin->main_addr = symbols[j].addr;
2921 					} else if (strstr (name, "4main") && !strstr (name, "STATIC")) {
2922 						bin->main_addr = symbols[j].addr;
2923 					} else if (!strcmp (name, "_main")) {
2924 						bin->main_addr = symbols[j].addr;
2925 					} else if (!strcmp (name, "main")) {
2926 						bin->main_addr = symbols[j].addr;
2927 					}
2928 				}
2929 				if (inSymtab (hash, symbols[j].name, symbols[j].addr)) {
2930 					free (symbols[j].name);
2931 					symbols[j].name = NULL;
2932 					j--;
2933 				}
2934 			}
2935 		}
2936 		to = R_MIN ((ut32)bin->nsymtab, bin->dysymtab.iundefsym + bin->dysymtab.nundefsym);
2937 		for (i = bin->dysymtab.iundefsym; i < to; i++) {
2938 			if (j > symbols_count) {
2939 				bprintf ("mach0-get-symbols: error\n");
2940 				break;
2941 			}
2942 			if (parse_import_stub (bin, &symbols[j], i)) {
2943 				symbols[j++].last = false;
2944 			}
2945 		}
2946 
2947 		for (i = 0; i < bin->nsymtab; i++) {
2948 			struct MACH0_(nlist) *st = &bin->symtab[i];
2949 			if (st->n_type & N_STAB) {
2950 				continue;
2951 			}
2952 			// 0 is for imports
2953 			// 1 is for symbols
2954 			// 2 is for func.eh (exception handlers?)
2955 			int section = st->n_sect;
2956 			if (section == 1 && j < symbols_count) {
2957 				// check if symbol exists already
2958 				/* is symbol */
2959 				symbols[j].addr = st->n_value;
2960 				symbols[j].offset = addr_to_offset (bin, symbols[j].addr);
2961 				symbols[j].size = 0; /* find next symbol and crop */
2962 				symbols[j].type = (st->n_type & N_EXT)
2963 					? R_BIN_MACH0_SYMBOL_TYPE_EXT
2964 					: R_BIN_MACH0_SYMBOL_TYPE_LOCAL;
2965 				char *sym_name = get_name (bin, st->n_strx, false);
2966 				if (sym_name) {
2967 					symbols[j].name = sym_name;
2968 				} else {
2969 					symbols[j].name = r_str_newf ("entry%d", i);
2970 				}
2971 				symbols[j].last = 0;
2972 				if (inSymtab (hash, symbols[j].name, symbols[j].addr)) {
2973 					R_FREE (symbols[j].name);
2974 				} else {
2975 					j++;
2976 				}
2977 
2978 				const char *name = symbols[i].name;
2979 				if (bin->main_addr == 0 && name) {
2980 					if (name && !strcmp (name, "__Dmain")) {
2981 						bin->main_addr = symbols[i].addr;
2982 					} else if (name && strstr (name, "4main") && !strstr (name, "STATIC")) {
2983 						bin->main_addr = symbols[i].addr;
2984 					} else if (symbols[i].name && !strcmp (symbols[i].name, "_main")) {
2985 						bin->main_addr = symbols[i].addr;
2986 					}
2987 				}
2988 			}
2989 		}
2990 	} else if (!n_exports) {
2991 		ht_pp_free (hash);
2992 		return NULL;
2993 	} else {
2994 		symbols_size = (symbols_count + 1) * sizeof (struct symbol_t);
2995 		if (symbols_size < 1) {
2996 			ht_pp_free (hash);
2997 			return NULL;
2998 		}
2999 		if (!(symbols = calloc (1, symbols_size))) {
3000 			ht_pp_free (hash);
3001 			return NULL;
3002 		}
3003 	}
3004 	if (n_exports && (symbols_count - j) >= n_exports) {
3005 		RSymCtx sym_ctx;
3006 		sym_ctx.symbols = symbols;
3007 		sym_ctx.j = j;
3008 		sym_ctx.symbols_count = symbols_count;
3009 		sym_ctx.hash = hash;
3010 		walk_exports (bin, assign_export_symbol_t, &sym_ctx);
3011 		j = sym_ctx.j;
3012 	}
3013 	ht_pp_free (hash);
3014 	symbols[j].last = true;
3015 	bin->symbols = symbols;
3016 	return symbols;
3017 }
3018 
parse_import_ptr(struct MACH0_ (obj_t)* bin,struct reloc_t * reloc,int idx)3019 static int parse_import_ptr(struct MACH0_(obj_t) *bin, struct reloc_t *reloc, int idx) {
3020 	int i, j, sym;
3021 	size_t wordsize;
3022 	ut32 stype;
3023 	wordsize = get_word_size (bin);
3024 	if (idx < 0 || idx >= bin->nsymtab) {
3025 		return 0;
3026 	}
3027 	if ((bin->symtab[idx].n_desc & REFERENCE_TYPE) == REFERENCE_FLAG_UNDEFINED_LAZY) {
3028 		stype = S_LAZY_SYMBOL_POINTERS;
3029 	} else {
3030 		stype = S_NON_LAZY_SYMBOL_POINTERS;
3031 	}
3032 
3033 	reloc->offset = 0;
3034 	reloc->addr = 0;
3035 	reloc->addend = 0;
3036 #define CASE(T) case ((T) / 8): reloc->type = R_BIN_RELOC_ ## T; break
3037 	switch (wordsize) {
3038 	CASE(8);
3039 	CASE(16);
3040 	CASE(32);
3041 	CASE(64);
3042 	default: return false;
3043 	}
3044 #undef CASE
3045 
3046 	for (i = 0; i < bin->nsects; i++) {
3047 		if ((bin->sects[i].flags & SECTION_TYPE) == stype) {
3048 			for (j = 0, sym = -1; bin->sects[i].reserved1 + j < bin->nindirectsyms; j++) {
3049 				int indidx = bin->sects[i].reserved1 + j;
3050 				if (indidx < 0 || indidx >= bin->nindirectsyms) {
3051 					break;
3052 				}
3053 				if (idx == bin->indirectsyms[indidx]) {
3054 					sym = j;
3055 					break;
3056 				}
3057 			}
3058 			reloc->offset = sym == -1 ? 0 : bin->sects[i].offset + sym * wordsize;
3059 			reloc->addr = sym == -1 ? 0 : bin->sects[i].addr + sym * wordsize;
3060 			return true;
3061 		}
3062 	}
3063 	return false;
3064 }
3065 
MACH0_(get_imports)3066 struct import_t *MACH0_(get_imports)(struct MACH0_(obj_t) *bin) {
3067 	r_return_val_if_fail (bin, NULL);
3068 
3069 	int i, j, idx, stridx;
3070 	if (!bin->sects || !bin->symtab || !bin->symstr || !bin->indirectsyms) {
3071 		return NULL;
3072 	}
3073 
3074 	if (bin->dysymtab.nundefsym < 1 || bin->dysymtab.nundefsym > 0xfffff) {
3075 		return NULL;
3076 	}
3077 
3078 	struct import_t *imports = calloc (bin->dysymtab.nundefsym + 1, sizeof (struct import_t));
3079 	if (!imports) {
3080 		return NULL;
3081 	}
3082 	for (i = j = 0; i < bin->dysymtab.nundefsym; i++) {
3083 		idx = bin->dysymtab.iundefsym + i;
3084 		if (idx < 0 || idx >= bin->nsymtab) {
3085 			bprintf ("WARNING: Imports index out of bounds. Ignoring relocs\n");
3086 			free (imports);
3087 			return NULL;
3088 		}
3089 		stridx = bin->symtab[idx].n_strx;
3090 		char *imp_name = get_name (bin, stridx, false);
3091 		if (imp_name) {
3092 			r_str_ncpy (imports[j].name, imp_name, R_BIN_MACH0_STRING_LENGTH);
3093 			free (imp_name);
3094 		} else {
3095 			//imports[j].name[0] = 0;
3096 			continue;
3097 		}
3098 		imports[j].ord = i;
3099 		imports[j++].last = 0;
3100 	}
3101 	imports[j].last = 1;
3102 
3103 	if (!bin->imports_by_ord_size) {
3104 		if (j > 0) {
3105 			bin->imports_by_ord_size = j;
3106 			bin->imports_by_ord = (RBinImport**)calloc (j, sizeof (RBinImport*));
3107 		} else {
3108 			bin->imports_by_ord_size = 0;
3109 			bin->imports_by_ord = NULL;
3110 		}
3111 	}
3112 
3113 	return imports;
3114 }
3115 
reloc_comparator(struct reloc_t * a,struct reloc_t * b)3116 static int reloc_comparator(struct reloc_t *a, struct reloc_t *b) {
3117 	return a->addr - b->addr;
3118 }
3119 
parse_relocation_info(struct MACH0_ (obj_t)* bin,RSkipList * relocs,ut32 offset,ut32 num)3120 static void parse_relocation_info(struct MACH0_(obj_t) *bin, RSkipList * relocs, ut32 offset, ut32 num) {
3121 	if (!num || !offset || (st32)num < 0) {
3122 		return;
3123 	}
3124 
3125 	ut64 total_size = num * sizeof (struct relocation_info);
3126 	struct relocation_info *info = calloc (num, sizeof (struct relocation_info));
3127 	if (!info) {
3128 		return;
3129 	}
3130 
3131 	if (r_buf_read_at (bin->b, offset, (ut8 *) info, total_size) < total_size) {
3132 		free (info);
3133 		return;
3134 	}
3135 
3136 	size_t i;
3137 	for (i = 0; i < num; i++) {
3138 		struct relocation_info a_info = info[i];
3139 		ut32 sym_num = a_info.r_symbolnum;
3140 		if (sym_num > bin->nsymtab) {
3141 			continue;
3142 		}
3143 
3144 		ut32 stridx = bin->symtab[sym_num].n_strx;
3145 		char *sym_name = get_name (bin, stridx, false);
3146 		if (!sym_name) {
3147 			continue;
3148 		}
3149 
3150 		struct reloc_t *reloc = R_NEW0 (struct reloc_t);
3151 		if (!reloc) {
3152 			free (sym_name);
3153 			return;
3154 		}
3155 
3156 		reloc->addr = offset_to_vaddr (bin, a_info.r_address);
3157 		reloc->offset = a_info.r_address;
3158 		reloc->ord = sym_num;
3159 		reloc->type = a_info.r_type; // enum RelocationInfoType
3160 		reloc->external = a_info.r_extern;
3161 		reloc->pc_relative = a_info.r_pcrel;
3162 		reloc->size = a_info.r_length;
3163 		r_str_ncpy (reloc->name, sym_name, sizeof (reloc->name) - 1);
3164 		r_skiplist_insert (relocs, reloc);
3165 		free (sym_name);
3166 	}
3167 	free (info);
3168 }
3169 
is_valid_ordinal_table_size(ut64 size)3170 static bool is_valid_ordinal_table_size(ut64 size) {
3171 	return size > 0 && size <= UT16_MAX;
3172 }
3173 
MACH0_(get_relocs)3174 RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
3175 	RSkipList *relocs = NULL;
3176 	RPVector *threaded_binds = NULL;
3177 	size_t wordsize = get_word_size (bin);
3178 	if (bin->dyld_info) {
3179 		ut8 *opcodes, rel_type = 0;
3180 		size_t bind_size, lazy_size, weak_size;
3181 
3182 #define CASE(T) case ((T) / 8): rel_type = R_BIN_RELOC_ ## T; break
3183 		switch (wordsize) {
3184 		CASE(8);
3185 		CASE(16);
3186 		CASE(32);
3187 		CASE(64);
3188 		default: return NULL;
3189 		}
3190 #undef CASE
3191 		bind_size = bin->dyld_info->bind_size;
3192 		lazy_size = bin->dyld_info->lazy_bind_size;
3193 		weak_size = bin->dyld_info->weak_bind_size;
3194 
3195 		if (!bind_size && !lazy_size) {
3196 			return NULL;
3197 		}
3198 
3199 		if ((bind_size + lazy_size)<1) {
3200 			return NULL;
3201 		}
3202 		if (bin->dyld_info->bind_off > bin->size || bin->dyld_info->bind_off + bind_size > bin->size) {
3203 			return NULL;
3204 		}
3205 		if (bin->dyld_info->lazy_bind_off > bin->size || \
3206 			bin->dyld_info->lazy_bind_off + lazy_size > bin->size) {
3207 			return NULL;
3208 		}
3209 		if (bin->dyld_info->bind_off + bind_size + lazy_size > bin->size) {
3210 			return NULL;
3211 		}
3212 		if (bin->dyld_info->weak_bind_off + weak_size > bin->size) {
3213 			return NULL;
3214 		}
3215 		ut64 amount = bind_size + lazy_size + weak_size;
3216 		if (amount == 0 || amount > UT32_MAX) {
3217 			return NULL;
3218 		}
3219 		if (!bin->segs) {
3220 			return NULL;
3221 		}
3222 		relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
3223 		if (!relocs) {
3224 			return NULL;
3225 		}
3226 		opcodes = calloc (1, amount + 1);
3227 		if (!opcodes) {
3228 			r_skiplist_free (relocs);
3229 			return NULL;
3230 		}
3231 
3232 		int len = r_buf_read_at (bin->b, bin->dyld_info->bind_off, opcodes, bind_size);
3233 		len += r_buf_read_at (bin->b, bin->dyld_info->lazy_bind_off, opcodes + bind_size, lazy_size);
3234 		len += r_buf_read_at (bin->b, bin->dyld_info->weak_bind_off, opcodes + bind_size + lazy_size, weak_size);
3235 		if (len < amount) {
3236 			bprintf ("Error: read (dyld_info bind) at 0x%08"PFMT64x"\n", (ut64)(size_t)bin->dyld_info->bind_off);
3237 			R_FREE (opcodes);
3238 			r_skiplist_free (relocs);
3239 			return NULL;
3240 		}
3241 
3242 		size_t partition_sizes[] = {bind_size, lazy_size, weak_size};
3243 		size_t pidx;
3244 		int opcodes_offset = 0;
3245 		for (pidx = 0; pidx < R_ARRAY_SIZE (partition_sizes); pidx++) {
3246 			size_t partition_size = partition_sizes[pidx];
3247 
3248 			ut8 type = 0;
3249 			int lib_ord = 0, seg_idx = -1, sym_ord = -1;
3250 			char *sym_name = NULL;
3251 			size_t j, count, skip;
3252 			st64 addend = 0;
3253 			ut64 addr = bin->segs[0].vmaddr;
3254 			ut64 segment_end_addr = addr + bin->segs[0].vmsize;
3255 
3256 			ut8 *p = opcodes + opcodes_offset;
3257 			ut8 *end = p + partition_size;
3258 			bool done = false;
3259 			while (!done && p < end) {
3260 				ut8 imm = *p & BIND_IMMEDIATE_MASK;
3261 				ut8 op = *p & BIND_OPCODE_MASK;
3262 				p++;
3263 				switch (op) {
3264 				case BIND_OPCODE_DONE: {
3265 					bool in_lazy_binds = pidx == 1;
3266 					if (!in_lazy_binds) {
3267 						done = true;
3268 					}
3269 					break;
3270 				}
3271 				case BIND_OPCODE_THREADED: {
3272 					switch (imm) {
3273 					case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB: {
3274 						ut64 table_size = read_uleb128 (&p, end);
3275 						if (!is_valid_ordinal_table_size (table_size)) {
3276 							bprintf ("Error: BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB size is wrong\n");
3277 							break;
3278 						}
3279 						if (threaded_binds) {
3280 							r_pvector_free (threaded_binds);
3281 						}
3282 						threaded_binds = r_pvector_new_with_len ((RPVectorFree) &free, table_size);
3283 						if (threaded_binds) {
3284 							sym_ord = 0;
3285 						}
3286 						break;
3287 					}
3288 					case BIND_SUBOPCODE_THREADED_APPLY:
3289 						if (threaded_binds) {
3290 							int cur_seg_idx = (seg_idx != -1)? seg_idx: 0;
3291 							size_t n_threaded_binds = r_pvector_len (threaded_binds);
3292 							while (addr < segment_end_addr) {
3293 								ut8 tmp[8];
3294 								ut64 paddr = addr - bin->segs[cur_seg_idx].vmaddr + bin->segs[cur_seg_idx].fileoff;
3295 								bin->rebasing_buffer = true;
3296 								if (r_buf_read_at (bin->b, paddr, tmp, 8) != 8) {
3297 									break;
3298 								}
3299 								bin->rebasing_buffer = false;
3300 								ut64 raw_ptr = r_read_le64 (tmp);
3301 								bool is_auth = (raw_ptr & (1ULL << 63)) != 0;
3302 								bool is_bind = (raw_ptr & (1ULL << 62)) != 0;
3303 								int ordinal = -1;
3304 								int addend = -1;
3305 								ut64 delta;
3306 								if (is_auth && is_bind) {
3307 									struct dyld_chained_ptr_arm64e_auth_bind *p =
3308 											(struct dyld_chained_ptr_arm64e_auth_bind *) &raw_ptr;
3309 									delta = p->next;
3310 									ordinal = p->ordinal;
3311 								} else if (!is_auth && is_bind) {
3312 									struct dyld_chained_ptr_arm64e_bind *p =
3313 											(struct dyld_chained_ptr_arm64e_bind *) &raw_ptr;
3314 									delta = p->next;
3315 									ordinal = p->ordinal;
3316 									addend = p->addend;
3317 								} else if (is_auth && !is_bind) {
3318 									struct dyld_chained_ptr_arm64e_auth_rebase *p =
3319 											(struct dyld_chained_ptr_arm64e_auth_rebase *) &raw_ptr;
3320 									delta = p->next;
3321 								} else {
3322 									struct dyld_chained_ptr_arm64e_rebase *p =
3323 											(struct dyld_chained_ptr_arm64e_rebase *) &raw_ptr;
3324 									delta = p->next;
3325 								}
3326 								if (ordinal != -1) {
3327 									if (ordinal >= n_threaded_binds) {
3328 										bprintf ("Error: Malformed bind chain\n");
3329 										break;
3330 									}
3331 									struct reloc_t *ref = r_pvector_at (threaded_binds, ordinal);
3332 									if (!ref) {
3333 										bprintf ("Error: Inconsistent bind opcodes\n");
3334 										break;
3335 									}
3336 									struct reloc_t *reloc = R_NEW0 (struct reloc_t);
3337 									if (!reloc) {
3338 										break;
3339 									}
3340 									*reloc = *ref;
3341 									reloc->addr = addr;
3342 									reloc->offset = paddr;
3343 									if (addend != -1) {
3344 										reloc->addend = addend;
3345 									}
3346 									r_skiplist_insert (relocs, reloc);
3347 								}
3348 								addr += delta * wordsize;
3349 								if (!delta) {
3350 									break;
3351 								}
3352 							}
3353 						}
3354 						break;
3355 					default:
3356 						bprintf ("Error: Unexpected BIND_OPCODE_THREADED sub-opcode: 0x%x\n", imm);
3357 					}
3358 					break;
3359 				}
3360 				case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
3361 					lib_ord = imm;
3362 					break;
3363 				case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
3364 					lib_ord = read_uleb128 (&p, end);
3365 					break;
3366 				case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
3367 					lib_ord = imm? (st8)(BIND_OPCODE_MASK | imm) : 0;
3368 					break;
3369 				case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: {
3370 					sym_name = (char*)p;
3371 					while (*p++ && p < end) {
3372 						/* empty loop */
3373 					}
3374 					if (threaded_binds) {
3375 						break;
3376 					}
3377 					sym_ord = -1;
3378 					if (bin->symtab && bin->dysymtab.nundefsym < UT16_MAX) {
3379 						for (j = 0; j < bin->dysymtab.nundefsym; j++) {
3380 							size_t stridx = 0;
3381 							bool found = false;
3382 							int iundefsym = bin->dysymtab.iundefsym;
3383 							if (iundefsym >= 0 && iundefsym < bin->nsymtab) {
3384 								int sidx = iundefsym + j;
3385 								if (sidx < 0 || sidx >= bin->nsymtab) {
3386 									continue;
3387 								}
3388 								stridx = bin->symtab[sidx].n_strx;
3389 								if (stridx >= bin->symstrlen) {
3390 									continue;
3391 								}
3392 								found = true;
3393 							}
3394 							if (found && !strcmp ((const char *)bin->symstr + stridx, sym_name)) {
3395 								sym_ord = j;
3396 								break;
3397 							}
3398 						}
3399 					}
3400 					break;
3401 				}
3402 				case BIND_OPCODE_SET_TYPE_IMM:
3403 					type = imm;
3404 					break;
3405 				case BIND_OPCODE_SET_ADDEND_SLEB:
3406 					addend = r_sleb128 ((const ut8 **)&p, end);
3407 					break;
3408 				case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
3409 					seg_idx = imm;
3410 					if (seg_idx >= bin->nsegs) {
3411 						bprintf ("Error: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"
3412 							" has unexistent segment %d\n", seg_idx);
3413 						free (opcodes);
3414 						r_skiplist_free (relocs);
3415 						r_pvector_free (threaded_binds);
3416 						return NULL; // early exit to avoid future mayhem
3417 					}
3418 					addr = bin->segs[seg_idx].vmaddr + read_uleb128 (&p, end);
3419 					segment_end_addr = bin->segs[seg_idx].vmaddr \
3420 							+ bin->segs[seg_idx].vmsize;
3421 					break;
3422 				case BIND_OPCODE_ADD_ADDR_ULEB:
3423 					addr += read_uleb128 (&p, end);
3424 					break;
3425 #define DO_BIND() do {\
3426 	if (sym_ord < 0 && !sym_name) break;\
3427 	if (!threaded_binds) {\
3428 		if (seg_idx < 0 ) break;\
3429 		if (!addr) break;\
3430 	}\
3431 	struct reloc_t *reloc = R_NEW0 (struct reloc_t);\
3432 	reloc->addr = addr;\
3433 	if (seg_idx >= 0) {\
3434 		reloc->offset = addr - bin->segs[seg_idx].vmaddr + bin->segs[seg_idx].fileoff;\
3435 		if (type == BIND_TYPE_TEXT_PCREL32)\
3436 			reloc->addend = addend - (bin->baddr + addr);\
3437 		else\
3438 			reloc->addend = addend;\
3439 	} else {\
3440 		reloc->addend = addend;\
3441 	}\
3442 	/* library ordinal ??? */ \
3443 	reloc->ord = lib_ord;\
3444 	reloc->ord = sym_ord;\
3445 	reloc->type = rel_type;\
3446 	if (sym_name)\
3447 		r_str_ncpy (reloc->name, sym_name, 256);\
3448 	if (threaded_binds)\
3449 		r_pvector_set (threaded_binds, sym_ord, reloc);\
3450 	else\
3451 		r_skiplist_insert (relocs, reloc);\
3452 } while (0)
3453 				case BIND_OPCODE_DO_BIND:
3454 					if (!threaded_binds && addr >= segment_end_addr) {
3455 						bprintf ("Error: Malformed DO bind opcode 0x%"PFMT64x"\n", addr);
3456 						goto beach;
3457 					}
3458 					DO_BIND ();
3459 					if (!threaded_binds) {
3460 						addr += wordsize;
3461 					} else {
3462 						sym_ord++;
3463 					}
3464 					break;
3465 				case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
3466 					if (addr >= segment_end_addr) {
3467 						bprintf ("Error: Malformed ADDR ULEB bind opcode\n");
3468 						goto beach;
3469 					}
3470 					DO_BIND ();
3471 					addr += read_uleb128 (&p, end) + wordsize;
3472 					break;
3473 				case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
3474 					if (addr >= segment_end_addr) {
3475 						bprintf ("Error: Malformed IMM SCALED bind opcode\n");
3476 						goto beach;
3477 					}
3478 					DO_BIND ();
3479 					addr += (ut64)imm * (ut64)wordsize + wordsize;
3480 					break;
3481 				case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
3482 					count = read_uleb128 (&p, end);
3483 					skip = read_uleb128 (&p, end);
3484 					for (j = 0; j < count; j++) {
3485 						if (addr >= segment_end_addr) {
3486 							bprintf ("Error: Malformed ULEB TIMES bind opcode\n");
3487 							goto beach;
3488 						}
3489 						DO_BIND ();
3490 						addr += skip + wordsize;
3491 					}
3492 					break;
3493 #undef DO_BIND
3494 				default:
3495 					bprintf ("Error: unknown bind opcode 0x%02x in dyld_info\n", *p);
3496 					R_FREE (opcodes);
3497 					r_pvector_free (threaded_binds);
3498 					return relocs;
3499 				}
3500 			}
3501 
3502 			opcodes_offset += partition_size;
3503 		}
3504 
3505 		R_FREE (opcodes);
3506 		r_pvector_free (threaded_binds);
3507 		threaded_binds = NULL;
3508 	}
3509 
3510 	if (bin->symtab && bin->symstr && bin->sects && bin->indirectsyms) {
3511 		int j;
3512 		int amount = bin->dysymtab.nundefsym;
3513 		if (amount < 0) {
3514 			amount = 0;
3515 		}
3516 		if (!relocs) {
3517 			relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
3518 			if (!relocs) {
3519 				return NULL;
3520 			}
3521 		}
3522 		for (j = 0; j < amount; j++) {
3523 			struct reloc_t *reloc = R_NEW0 (struct reloc_t);
3524 			if (!reloc) {
3525 				break;
3526 			}
3527 			if (parse_import_ptr (bin, reloc, bin->dysymtab.iundefsym + j)) {
3528 				reloc->ord = j;
3529 				r_skiplist_insert_autofree (relocs, reloc);
3530 			} else {
3531 				R_FREE (reloc);
3532 			}
3533 		}
3534 	}
3535 
3536 	if (bin->symtab && bin->dysymtab.extreloff && bin->dysymtab.nextrel) {
3537 		if (!relocs) {
3538 			relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
3539 			if (!relocs) {
3540 				return NULL;
3541 			}
3542 		}
3543 		parse_relocation_info (bin, relocs, bin->dysymtab.extreloff, bin->dysymtab.nextrel);
3544 	}
3545 beach:
3546 	r_pvector_free (threaded_binds);
3547 	return relocs;
3548 }
3549 
MACH0_(get_entrypoint)3550 struct addr_t *MACH0_(get_entrypoint)(struct MACH0_(obj_t) *bin) {
3551 	r_return_val_if_fail (bin, NULL);
3552 
3553 	ut64 ea = entry_to_vaddr (bin);
3554 	if (ea == 0 || ea == UT64_MAX) {
3555 		return NULL;
3556 	}
3557 	struct addr_t *entry = R_NEW0 (struct addr_t);
3558 	if (!entry) {
3559 		return NULL;
3560 	}
3561 	entry->addr = ea;
3562 	entry->offset = addr_to_offset (bin, entry->addr);
3563 	entry->haddr = sdb_num_get (bin->kv, "mach0.entry.offset", 0);
3564 	sdb_num_set (bin->kv, "mach0.entry.vaddr", entry->addr, 0);
3565 	sdb_num_set (bin->kv, "mach0.entry.paddr", bin->entry, 0);
3566 
3567 	if (entry->offset == 0 && !bin->sects) {
3568 		int i;
3569 		for (i = 0; i < bin->nsects; i++) {
3570 			// XXX: section name shoudnt matter .. just check for exec flags
3571 			if (!strncmp (bin->sects[i].sectname, "__text", 6)) {
3572 				entry->offset = (ut64)bin->sects[i].offset;
3573 				sdb_num_set (bin->kv, "mach0.entry", entry->offset, 0);
3574 				entry->addr = (ut64)bin->sects[i].addr;
3575 				if (!entry->addr) { // workaround for object files
3576 					eprintf ("entrypoint is 0...\n");
3577 					// XXX(lowlyw) there's technically not really entrypoints
3578 					// for .o files, so ignore this...
3579 					// entry->addr = entry->offset;
3580 				}
3581 				break;
3582 			}
3583 		}
3584 		bin->entry = entry->addr;
3585 	}
3586 	return entry;
3587 }
3588 
MACH0_(kv_loadlibs)3589 void MACH0_(kv_loadlibs)(struct MACH0_(obj_t) *bin) {
3590 	int i;
3591 	for (i = 0; i < bin->nlibs; i++) {
3592 		sdb_set (bin->kv, sdb_fmt ("libs.%d.name", i), bin->libs[i], 0);
3593 	}
3594 }
3595 
MACH0_(get_libs)3596 struct lib_t *MACH0_(get_libs)(struct MACH0_(obj_t) *bin) {
3597 	struct lib_t *libs;
3598 	int i;
3599 
3600 	if (!bin->nlibs) {
3601 		return NULL;
3602 	}
3603 	if (!(libs = calloc ((bin->nlibs + 1), sizeof (struct lib_t)))) {
3604 		return NULL;
3605 	}
3606 	for (i = 0; i < bin->nlibs; i++) {
3607 		sdb_set (bin->kv, sdb_fmt ("libs.%d.name", i), bin->libs[i], 0);
3608 		strncpy (libs[i].name, bin->libs[i], R_BIN_MACH0_STRING_LENGTH);
3609 		libs[i].name[R_BIN_MACH0_STRING_LENGTH - 1] = '\0';
3610 		libs[i].last = 0;
3611 	}
3612 	libs[i].last = 1;
3613 	return libs;
3614 }
3615 
MACH0_(get_baddr)3616 ut64 MACH0_(get_baddr)(struct MACH0_(obj_t) *bin) {
3617 	int i;
3618 
3619 	if (bin->hdr.filetype != MH_EXECUTE && bin->hdr.filetype != MH_DYLINKER &&
3620 			bin->hdr.filetype != MH_FILESET) {
3621 		return 0;
3622 	}
3623 	for (i = 0; i < bin->nsegs; i++) {
3624 		if (bin->segs[i].fileoff == 0 && bin->segs[i].filesize != 0) {
3625 			return bin->segs[i].vmaddr;
3626 		}
3627 	}
3628 	return 0;
3629 }
3630 
MACH0_(get_class)3631 char *MACH0_(get_class)(struct MACH0_(obj_t) *bin) {
3632 #if R_BIN_MACH064
3633 	return r_str_new ("MACH064");
3634 #else
3635 	return r_str_new ("MACH0");
3636 #endif
3637 }
3638 
3639 //XXX we are mixing up bits from cpu and opcodes
3640 //since thumb use 16 bits opcode but run in 32 bits
3641 //cpus  so here we should only return 32 or 64
MACH0_(get_bits)3642 int MACH0_(get_bits)(struct MACH0_(obj_t) *bin) {
3643 	if (bin) {
3644 		int bits = MACH0_(get_bits_from_hdr) (&bin->hdr);
3645 		if (bin->hdr.cputype == CPU_TYPE_ARM && bin->entry & 1) {
3646 			return 16;
3647 		}
3648 		return bits;
3649 	}
3650 	return 32;
3651 }
3652 
MACH0_(get_bits_from_hdr)3653 int MACH0_(get_bits_from_hdr)(struct MACH0_(mach_header) *hdr) {
3654 	if (hdr->magic == MH_MAGIC_64 || hdr->magic == MH_CIGAM_64) {
3655 		return 64;
3656 	}
3657 	if (hdr->cputype == CPU_TYPE_ARM64_32) { // new apple watch aka arm64_32
3658 		return 64;
3659 	}
3660 	if ((hdr->cpusubtype & CPU_SUBTYPE_MASK) == (CPU_SUBTYPE_ARM_V7K << 24)) {
3661 		return 16;
3662 	}
3663 	return 32;
3664 }
3665 
MACH0_(is_big_endian)3666 bool MACH0_(is_big_endian)(struct MACH0_(obj_t) *bin) {
3667 	if (bin) {
3668 		const int cpu = bin->hdr.cputype;
3669 		return cpu == CPU_TYPE_POWERPC || cpu == CPU_TYPE_POWERPC64;
3670 	}
3671 	return false;
3672 }
3673 
MACH0_(get_intrp)3674 const char *MACH0_(get_intrp)(struct MACH0_(obj_t) *bin) {
3675 	return bin? bin->intrp: NULL;
3676 }
3677 
MACH0_(get_os)3678 const char *MACH0_(get_os)(struct MACH0_(obj_t) *bin) {
3679 	if (bin) {
3680 		switch (bin->os) {
3681 		case 1: return "macos";
3682 		case 2: return "ios";
3683 		case 3: return "watchos";
3684 		case 4: return "tvos";
3685 		}
3686 	}
3687 	return "darwin";
3688 }
3689 
MACH0_(get_cputype_from_hdr)3690 const char *MACH0_(get_cputype_from_hdr)(struct MACH0_(mach_header) *hdr) {
3691 	const char *archstr = "unknown";
3692 	switch (hdr->cputype) {
3693 	case CPU_TYPE_VAX:
3694 		archstr = "vax";
3695 		break;
3696 	case CPU_TYPE_MC680x0:
3697 		archstr = "mc680x0";
3698 		break;
3699 	case CPU_TYPE_I386:
3700 	case CPU_TYPE_X86_64:
3701 		archstr = "x86";
3702 		break;
3703 	case CPU_TYPE_MC88000:
3704 		archstr = "mc88000";
3705 		break;
3706 	case CPU_TYPE_MC98000:
3707 		archstr = "mc98000";
3708 		break;
3709 	case CPU_TYPE_HPPA:
3710 		archstr = "hppa";
3711 		break;
3712 	case CPU_TYPE_ARM:
3713 	case CPU_TYPE_ARM64:
3714 	case CPU_TYPE_ARM64_32:
3715 		archstr = "arm";
3716 		break;
3717 	case CPU_TYPE_SPARC:
3718 		archstr = "sparc";
3719 		break;
3720 	case CPU_TYPE_MIPS:
3721 		archstr = "mips";
3722 		break;
3723 	case CPU_TYPE_I860:
3724 		archstr = "i860";
3725 		break;
3726 	case CPU_TYPE_POWERPC:
3727 	case CPU_TYPE_POWERPC64:
3728 		archstr = "ppc";
3729 		break;
3730 	default:
3731 		eprintf ("Unknown arch %d\n", hdr->cputype);
3732 		break;
3733 	}
3734 	return archstr;
3735 }
3736 
MACH0_(get_cputype)3737 const char *MACH0_(get_cputype)(struct MACH0_(obj_t) *bin) {
3738 	return bin? MACH0_(get_cputype_from_hdr) (&bin->hdr): "unknown";
3739 }
3740 
cpusubtype_tostring(ut32 cputype,ut32 cpusubtype)3741 static const char *cpusubtype_tostring (ut32 cputype, ut32 cpusubtype) {
3742 	switch (cputype) {
3743 	case CPU_TYPE_VAX:
3744 		switch (cpusubtype) {
3745 		case CPU_SUBTYPE_VAX_ALL:	return "all";
3746 		case CPU_SUBTYPE_VAX780:	return "vax780";
3747 		case CPU_SUBTYPE_VAX785:	return "vax785";
3748 		case CPU_SUBTYPE_VAX750:	return "vax750";
3749 		case CPU_SUBTYPE_VAX730:	return "vax730";
3750 		case CPU_SUBTYPE_UVAXI:		return "uvaxI";
3751 		case CPU_SUBTYPE_UVAXII:	return "uvaxII";
3752 		case CPU_SUBTYPE_VAX8200:	return "vax8200";
3753 		case CPU_SUBTYPE_VAX8500:	return "vax8500";
3754 		case CPU_SUBTYPE_VAX8600:	return "vax8600";
3755 		case CPU_SUBTYPE_VAX8650:	return "vax8650";
3756 		case CPU_SUBTYPE_VAX8800:	return "vax8800";
3757 		case CPU_SUBTYPE_UVAXIII:	return "uvaxIII";
3758 		default:			return "Unknown vax subtype";
3759 		}
3760 	case CPU_TYPE_MC680x0:
3761 		switch (cpusubtype) {
3762 		case CPU_SUBTYPE_MC68030:	return "mc68030";
3763 		case CPU_SUBTYPE_MC68040:	return "mc68040";
3764 		case CPU_SUBTYPE_MC68030_ONLY:	return "mc68030 only";
3765 		default:			return "Unknown mc680x0 subtype";
3766 		}
3767 	case CPU_TYPE_I386:
3768 		switch (cpusubtype) {
3769 		case CPU_SUBTYPE_386: 			return "386";
3770 		case CPU_SUBTYPE_486: 			return "486";
3771 		case CPU_SUBTYPE_486SX: 		return "486sx";
3772 		case CPU_SUBTYPE_PENT: 			return "Pentium";
3773 		case CPU_SUBTYPE_PENTPRO: 		return "Pentium Pro";
3774 		case CPU_SUBTYPE_PENTII_M3: 		return "Pentium 3 M3";
3775 		case CPU_SUBTYPE_PENTII_M5: 		return "Pentium 3 M5";
3776 		case CPU_SUBTYPE_CELERON: 		return "Celeron";
3777 		case CPU_SUBTYPE_CELERON_MOBILE:	return "Celeron Mobile";
3778 		case CPU_SUBTYPE_PENTIUM_3:		return "Pentium 3";
3779 		case CPU_SUBTYPE_PENTIUM_3_M:		return "Pentium 3 M";
3780 		case CPU_SUBTYPE_PENTIUM_3_XEON:	return "Pentium 3 Xeon";
3781 		case CPU_SUBTYPE_PENTIUM_M:		return "Pentium Mobile";
3782 		case CPU_SUBTYPE_PENTIUM_4:		return "Pentium 4";
3783 		case CPU_SUBTYPE_PENTIUM_4_M:		return "Pentium 4 M";
3784 		case CPU_SUBTYPE_ITANIUM:		return "Itanium";
3785 		case CPU_SUBTYPE_ITANIUM_2:		return "Itanium 2";
3786 		case CPU_SUBTYPE_XEON:			return "Xeon";
3787 		case CPU_SUBTYPE_XEON_MP:		return "Xeon MP";
3788 		default:				return "Unknown i386 subtype";
3789 		}
3790 	case CPU_TYPE_X86_64:
3791 		switch (cpusubtype & 0xff) {
3792 		case CPU_SUBTYPE_X86_64_ALL:	return "x86 64 all";
3793 		case CPU_SUBTYPE_X86_ARCH1:	return "x86 arch 1";
3794 		default:			return "Unknown x86 subtype";
3795 		}
3796 	case CPU_TYPE_MC88000:
3797 		switch (cpusubtype & 0xff) {
3798 		case CPU_SUBTYPE_MC88000_ALL:	return "all";
3799 		case CPU_SUBTYPE_MC88100:	return "mc88100";
3800 		case CPU_SUBTYPE_MC88110:	return "mc88110";
3801 		default:			return "Unknown mc88000 subtype";
3802 		}
3803 	case CPU_TYPE_MC98000:
3804 		switch (cpusubtype & 0xff) {
3805 		case CPU_SUBTYPE_MC98000_ALL:	return "all";
3806 		case CPU_SUBTYPE_MC98601:	return "mc98601";
3807 		default:			return "Unknown mc98000 subtype";
3808 		}
3809 	case CPU_TYPE_HPPA:
3810 		switch (cpusubtype & 0xff) {
3811 		case CPU_SUBTYPE_HPPA_7100:	return "hppa7100";
3812 		case CPU_SUBTYPE_HPPA_7100LC:	return "hppa7100LC";
3813 		default:			return "Unknown hppa subtype";
3814 		}
3815 	case CPU_TYPE_ARM64:
3816 		switch (cpusubtype & 0xff) {
3817 		case CPU_SUBTYPE_ARM64_ALL:	return "all";
3818 		case CPU_SUBTYPE_ARM64_V8:	return "arm64v8";
3819 		case CPU_SUBTYPE_ARM64E:	return "arm64e";
3820 		default:			return "Unknown arm64 subtype";
3821 		}
3822 		return "v8";
3823 	case CPU_TYPE_ARM:
3824 		switch (cpusubtype & 0xff) {
3825 		case CPU_SUBTYPE_ARM_ALL:
3826 			return "all";
3827 		case CPU_SUBTYPE_ARM_V4T:
3828 			return "v4t";
3829 		case CPU_SUBTYPE_ARM_V5:
3830 			return "v5";
3831 		case CPU_SUBTYPE_ARM_V6:
3832 			return "v6";
3833 		case CPU_SUBTYPE_ARM_XSCALE:
3834 			return "xscale";
3835 		case CPU_SUBTYPE_ARM_V7:
3836 			return "v7";
3837 		case CPU_SUBTYPE_ARM_V7F:
3838 			return "v7f";
3839 		case CPU_SUBTYPE_ARM_V7S:
3840 			return "v7s";
3841 		case CPU_SUBTYPE_ARM_V7K:
3842 			return "v7k";
3843 		case CPU_SUBTYPE_ARM_V7M:
3844 			return "v7m";
3845 		case CPU_SUBTYPE_ARM_V7EM:
3846 			return "v7em";
3847 		default:
3848 			eprintf ("Unknown arm subtype %d\n", cpusubtype & 0xff);
3849 			return "unknown arm subtype";
3850 		}
3851 	case CPU_TYPE_SPARC:
3852 		switch (cpusubtype & 0xff) {
3853 		case CPU_SUBTYPE_SPARC_ALL:	return "all";
3854 		default:			return "Unknown sparc subtype";
3855 		}
3856 	case CPU_TYPE_MIPS:
3857 		switch (cpusubtype & 0xff) {
3858 		case CPU_SUBTYPE_MIPS_ALL:	return "all";
3859 		case CPU_SUBTYPE_MIPS_R2300:	return "r2300";
3860 		case CPU_SUBTYPE_MIPS_R2600:	return "r2600";
3861 		case CPU_SUBTYPE_MIPS_R2800:	return "r2800";
3862 		case CPU_SUBTYPE_MIPS_R2000a:	return "r2000a";
3863 		case CPU_SUBTYPE_MIPS_R2000:	return "r2000";
3864 		case CPU_SUBTYPE_MIPS_R3000a:	return "r3000a";
3865 		case CPU_SUBTYPE_MIPS_R3000:	return "r3000";
3866 		default:			return "Unknown mips subtype";
3867 		}
3868 	case CPU_TYPE_I860:
3869 		switch (cpusubtype & 0xff) {
3870 		case CPU_SUBTYPE_I860_ALL:	return "all";
3871 		case CPU_SUBTYPE_I860_860:	return "860";
3872 		default:			return "Unknown i860 subtype";
3873 		}
3874 	case CPU_TYPE_POWERPC:
3875 	case CPU_TYPE_POWERPC64:
3876 		switch (cpusubtype & 0xff) {
3877 		case CPU_SUBTYPE_POWERPC_ALL:	return "all";
3878 		case CPU_SUBTYPE_POWERPC_601:	return "601";
3879 		case CPU_SUBTYPE_POWERPC_602:	return "602";
3880 		case CPU_SUBTYPE_POWERPC_603:	return "603";
3881 		case CPU_SUBTYPE_POWERPC_603e:	return "603e";
3882 		case CPU_SUBTYPE_POWERPC_603ev:	return "603ev";
3883 		case CPU_SUBTYPE_POWERPC_604:	return "604";
3884 		case CPU_SUBTYPE_POWERPC_604e:	return "604e";
3885 		case CPU_SUBTYPE_POWERPC_620:	return "620";
3886 		case CPU_SUBTYPE_POWERPC_750:	return "750";
3887 		case CPU_SUBTYPE_POWERPC_7400:	return "7400";
3888 		case CPU_SUBTYPE_POWERPC_7450:	return "7450";
3889 		case CPU_SUBTYPE_POWERPC_970:	return "970";
3890 		default:			return "Unknown ppc subtype";
3891 		}
3892 	}
3893 	return "Unknown cputype";
3894 }
3895 
MACH0_(get_cpusubtype_from_hdr)3896 char *MACH0_(get_cpusubtype_from_hdr)(struct MACH0_(mach_header) *hdr) {
3897 	r_return_val_if_fail (hdr, NULL);
3898 	return strdup (cpusubtype_tostring (hdr->cputype, hdr->cpusubtype));
3899 }
3900 
MACH0_(get_cpusubtype)3901 char *MACH0_(get_cpusubtype)(struct MACH0_(obj_t) *bin) {
3902 	return bin? MACH0_(get_cpusubtype_from_hdr) (&bin->hdr): strdup ("Unknown");
3903 }
3904 
MACH0_(is_pie)3905 bool MACH0_(is_pie)(struct MACH0_(obj_t) *bin) {
3906 	return (bin && bin->hdr.filetype == MH_EXECUTE && bin->hdr.flags & MH_PIE);
3907 }
3908 
MACH0_(has_nx)3909 bool MACH0_(has_nx)(struct MACH0_(obj_t) *bin) {
3910 	return (bin && bin->hdr.filetype == MH_EXECUTE &&
3911 		bin->hdr.flags & MH_NO_HEAP_EXECUTION);
3912 }
3913 
MACH0_(get_filetype_from_hdr)3914 char *MACH0_(get_filetype_from_hdr)(struct MACH0_(mach_header) *hdr) {
3915 	const char *mhtype = "Unknown";
3916 	switch (hdr->filetype) {
3917 	case MH_OBJECT:     mhtype = "Relocatable object"; break;
3918 	case MH_EXECUTE:    mhtype = "Executable file"; break;
3919 	case MH_FVMLIB:     mhtype = "Fixed VM shared library"; break;
3920 	case MH_CORE:       mhtype = "Core file"; break;
3921 	case MH_PRELOAD:    mhtype = "Preloaded executable file"; break;
3922 	case MH_DYLIB:      mhtype = "Dynamically bound shared library"; break;
3923 	case MH_DYLINKER:   mhtype = "Dynamic link editor"; break;
3924 	case MH_BUNDLE:     mhtype = "Dynamically bound bundle file"; break;
3925 	case MH_DYLIB_STUB: mhtype = "Shared library stub for static linking (no sections)"; break;
3926 	case MH_DSYM:       mhtype = "Companion file with only debug sections"; break;
3927 	case MH_KEXT_BUNDLE: mhtype = "Kernel extension bundle file"; break;
3928 	case MH_FILESET:    mhtype = "Kernel cache file"; break;
3929 	}
3930 	return strdup (mhtype);
3931 }
3932 
MACH0_(get_filetype)3933 char *MACH0_(get_filetype)(struct MACH0_(obj_t) *bin) {
3934 	return bin? MACH0_(get_filetype_from_hdr) (&bin->hdr): strdup ("Unknown");
3935 }
3936 
MACH0_(get_main)3937 ut64 MACH0_(get_main)(struct MACH0_(obj_t) *bin) {
3938 	ut64 addr = UT64_MAX;
3939 	int i;
3940 
3941 	// 0 = sscanned but no main found
3942 	// -1 = not scanned, so no main
3943 	// other = valid main addr
3944 	if (bin->main_addr == UT64_MAX) {
3945 #if FEATURE_SYMLIST
3946 		 (void)MACH0_(get_symbols_list) (bin);
3947 #else
3948 		 (void)MACH0_(get_symbols) (bin);
3949 #endif
3950 	}
3951 	if (bin->main_addr != 0 && bin->main_addr != UT64_MAX) {
3952 		return bin->main_addr;
3953 	}
3954 	// dummy call to initialize things
3955 	free (MACH0_(get_entrypoint)(bin));
3956 
3957 	bin->main_addr = 0;
3958 
3959 	if (addr == UT64_MAX && bin->main_cmd.cmd == LC_MAIN) {
3960 		addr = bin->entry + bin->baddr;
3961 	}
3962 
3963 	if (!addr) {
3964 		ut8 b[128];
3965 		ut64 entry = addr_to_offset (bin, bin->entry);
3966 		// XXX: X86 only and hacky!
3967 		if (entry > bin->size || entry + sizeof (b) > bin->size) {
3968 			return UT64_MAX;
3969 		}
3970 		i = r_buf_read_at (bin->b, entry, b, sizeof (b));
3971 		if (i < 80) {
3972 			return UT64_MAX;
3973 		}
3974 		for (i = 0; i < 64; i++) {
3975 			if (b[i] == 0xe8 && !b[i + 3] && !b[i + 4]) {
3976 				int delta = b[i + 1] | (b[i + 2] << 8) | (b[i + 3] << 16) | (b[i + 4] << 24);
3977 				addr = bin->entry + i + 5 + delta;
3978 				break;
3979 			}
3980 		}
3981 		if (!addr) {
3982 			addr = entry;
3983 		}
3984 	}
3985 	return bin->main_addr = addr;
3986 }
3987 
MACH0_(mach_headerfields)3988 void MACH0_(mach_headerfields)(RBinFile *bf) {
3989 	PrintfCallback cb_printf = bf->rbin->cb_printf;
3990 	if (!cb_printf) {
3991 		cb_printf = printf;
3992 	}
3993 	RBuffer *buf = bf->buf;
3994 	ut64 length = r_buf_size (buf);
3995 	int n = 0;
3996 	struct MACH0_(mach_header) *mh = MACH0_(get_hdr)(buf);
3997 	if (!mh) {
3998 		return;
3999 	}
4000 	ut64 pvaddr = pa2va (bf, 0);
4001 	cb_printf ("pf.mach0_header @ 0x%08"PFMT64x"\n", pvaddr);
4002 	cb_printf ("0x%08"PFMT64x"  Magic       0x%x\n", pvaddr, mh->magic);
4003 	pvaddr += 4;
4004 	cb_printf ("0x%08"PFMT64x"  CpuType     0x%x\n", pvaddr, mh->cputype);
4005 	pvaddr += 4;
4006 	cb_printf ("0x%08"PFMT64x"  CpuSubType  0x%x\n", pvaddr, mh->cpusubtype);
4007 	pvaddr += 4;
4008 	cb_printf ("0x%08"PFMT64x"  FileType    0x%x\n", pvaddr, mh->filetype);
4009 	pvaddr += 4;
4010 	cb_printf ("0x%08"PFMT64x"  nCmds       %d\n", pvaddr, mh->ncmds);
4011 	pvaddr += 4;
4012 	cb_printf ("0x%08"PFMT64x"  sizeOfCmds  %d\n", pvaddr, mh->sizeofcmds);
4013 	pvaddr += 4;
4014 	cb_printf ("0x%08"PFMT64x"  Flags       0x%x\n", pvaddr, mh->flags);
4015 	pvaddr += 4;
4016 	bool is64 = mh->cputype >> 16;
4017 
4018 	ut64 addr = 0x20 - 4;
4019 	ut32 word = 0;
4020 	ut8 wordbuf[sizeof (word)];
4021 	bool isBe = false;
4022 	switch (mh->cputype) {
4023 	case CPU_TYPE_POWERPC:
4024 	case CPU_TYPE_POWERPC64:
4025 		isBe = true;
4026 		break;
4027 	}
4028 #define READWORD() \
4029 		if (r_buf_read_at (buf, addr, (ut8*)wordbuf, 4) != 4) { \
4030 			eprintf ("Invalid address in buffer."); \
4031 			break; \
4032 		} \
4033 		addr += 4; \
4034 		pvaddr += 4;\
4035 		word = isBe? r_read_be32 (wordbuf): r_read_le32 (wordbuf);
4036 	if (is64) {
4037 		addr += 4;
4038 		pvaddr += 4;
4039 	}
4040 	for (n = 0; n < mh->ncmds; n++) {
4041 		READWORD ();
4042 		ut32 lcType = word;
4043 		const char *pf_definition = cmd_to_pf_definition (lcType);
4044 		if (pf_definition) {
4045 			cb_printf ("pf.%s @ 0x%08"PFMT64x"\n", pf_definition, pvaddr - 4);
4046 		}
4047 		cb_printf ("0x%08"PFMT64x"  cmd %7d 0x%x %s\n",
4048 			pvaddr - 4, n, lcType, cmd_to_string (lcType));
4049 		READWORD ();
4050 		if (addr > length) {
4051 			break;
4052 		}
4053 		int lcSize = word;
4054 		word &= 0xFFFFFF;
4055 		cb_printf ("0x%08"PFMT64x"  cmdsize     %d\n", pvaddr - 4, word);
4056 		if (lcSize < 1) {
4057 			eprintf ("Invalid size for a load command\n");
4058 			break;
4059 		}
4060 		switch (lcType) {
4061 		case LC_BUILD_VERSION: {
4062 			cb_printf ("0x%08"PFMT64x"  platform    %s\n",
4063 				pvaddr, build_version_platform_to_string (r_buf_read_le32_at (buf, addr)));
4064 			cb_printf ("0x%08"PFMT64x"  minos       %d.%d.%d\n",
4065 				pvaddr + 4, r_buf_read_le16_at (buf, addr + 6), r_buf_read8_at (buf, addr + 5),
4066 				r_buf_read8_at (buf, addr + 4));
4067 			cb_printf ("0x%08"PFMT64x"  sdk         %d.%d.%d\n",
4068 				pvaddr + 8, r_buf_read_le16_at (buf, addr + 10), r_buf_read8_at (buf, addr + 9),
4069 				r_buf_read8_at (buf, addr + 8));
4070 			ut32 ntools = r_buf_read_le32_at (buf, addr + 12);
4071 			cb_printf ("0x%08"PFMT64x"  ntools      %d\n",
4072 				pvaddr + 12, ntools);
4073 			ut64 off = 16;
4074 			while (off < (lcSize - 8) && ntools--) {
4075 				cb_printf ("pf.mach0_build_version_tool @ 0x%08"PFMT64x"\n", pvaddr + off);
4076 				cb_printf ("0x%08"PFMT64x"  tool        %s\n",
4077 					pvaddr + off, build_version_tool_to_string (r_buf_read_le32_at (buf, addr + off)));
4078 				off += 4;
4079 				if (off >= (lcSize - 8)) {
4080 					break;
4081 				}
4082 				cb_printf ("0x%08"PFMT64x"  version     %d.%d.%d\n",
4083 					pvaddr + off, r_buf_read_le16_at (buf, addr + off + 2), r_buf_read8_at (buf, addr + off + 1),
4084 					r_buf_read8_at (buf, addr + off));
4085 				off += 4;
4086 			}
4087 			break;
4088 		}
4089 		case LC_MAIN:
4090 			{
4091 				ut8 data[64] = {0};
4092 				r_buf_read_at (buf, addr, data, sizeof (data));
4093 #if R_BIN_MACH064
4094 				ut64 ep = r_read_ble64 (&data, false); //  bin->big_endian);
4095 				cb_printf ("0x%08"PFMT64x"  entry0      0x%" PFMT64x "\n", pvaddr, ep);
4096 				ut64 ss = r_read_ble64 (&data[8], false); //  bin->big_endian);
4097 				cb_printf ("0x%08"PFMT64x"  stacksize   0x%" PFMT64x "\n", pvaddr +  8, ss);
4098 #else
4099 				ut32 ep = r_read_ble32 (&data, false); //  bin->big_endian);
4100 				cb_printf ("0x%08"PFMT32x"  entry0      0x%" PFMT32x "\n", (ut32)pvaddr, ep);
4101 				ut32 ss = r_read_ble32 (&data[4], false); //  bin->big_endian);
4102 				cb_printf ("0x%08"PFMT32x"  stacksize   0x%" PFMT32x "\n", (ut32)pvaddr +  4, ss);
4103 #endif
4104 			}
4105 			break;
4106 		case LC_SYMTAB:
4107 #if 0
4108 			{
4109 			char *id = r_buf_get_string (buf, addr + 20);
4110 			cb_printf ("0x%08"PFMT64x"  id         0x%x\n", addr + 20, r_str_get (id));
4111 			cb_printf ("0x%08"PFMT64x"  symooff    0x%x\n", addr + 20, r_str_get (id));
4112 			cb_printf ("0x%08"PFMT64x"  nsyms      %d\n", addr + 20, r_str_get (id));
4113 			cb_printf ("0x%08"PFMT64x"  stroff     0x%x\n", addr + 20, r_str_get (id));
4114 			cb_printf ("0x%08"PFMT64x"  strsize    0x%x\n", addr + 20, r_str_get (id));
4115 			free (id);
4116 			}
4117 #endif
4118 			break;
4119 		case LC_ID_DYLIB: { // install_name_tool
4120 			ut32 str_off = r_buf_read_ble32_at (buf, addr, isBe);
4121 			char *id = r_buf_get_string (buf, addr + str_off - 8);
4122 			cb_printf ("0x%08"PFMT64x"  current     %d.%d.%d\n",
4123 				pvaddr + 8, r_buf_read_le16_at (buf, addr + 10), r_buf_read8_at (buf, addr + 9),
4124 				r_buf_read8_at (buf, addr + 8));
4125 			cb_printf ("0x%08"PFMT64x"  compat      %d.%d.%d\n",
4126 				pvaddr + 12, r_buf_read_le16_at (buf, addr + 14), r_buf_read8_at (buf, addr + 13),
4127 				r_buf_read8_at (buf, addr + 12));
4128 			cb_printf ("0x%08"PFMT64x"  id          %s\n",
4129 				pvaddr + str_off - 8, r_str_get (id));
4130 			if (id) {
4131 				free (id);
4132 			}
4133 			break;
4134 		}
4135 		case LC_UUID:
4136 			{
4137 				ut8 i, uuid[16];
4138 				r_buf_read_at (buf, addr, uuid, sizeof (uuid));
4139 				cb_printf ("0x%08"PFMT64x"  uuid        ", pvaddr);
4140 				for (i = 0; i < sizeof (uuid); i++) {
4141 					cb_printf ("%02x", uuid[i]);
4142 				}
4143 				cb_printf ("\n");
4144 			}
4145 			break;
4146 		case LC_SEGMENT:
4147 		case LC_SEGMENT_64:
4148 			{
4149 				ut8 name[17] = {0};
4150 				r_buf_read_at (buf, addr, name, sizeof (name) - 1);
4151 				cb_printf ("0x%08"PFMT64x"  name        %s\n", pvaddr, name);
4152 				ut32 nsects = r_buf_read_le32_at (buf, addr - 8 + (is64 ? 64 : 48));
4153 				ut64 off = is64 ? 72 : 56;
4154 				while (off < lcSize && nsects--) {
4155 					if (is64) {
4156 						cb_printf ("pf.mach0_section64 @ 0x%08"PFMT64x"\n", pvaddr - 8 + off);
4157 						off += 80;
4158 					} else {
4159 						cb_printf ("pf.mach0_section @ 0x%08"PFMT64x"\n", pvaddr - 8 + off);
4160 						off += 68;
4161 					}
4162 				}
4163 			}
4164 			break;
4165 		case LC_LOAD_DYLIB:
4166 		case LC_LOAD_WEAK_DYLIB: {
4167 			ut32 str_off = r_buf_read_ble32_at (buf, addr, isBe);
4168 			char *load_dylib = r_buf_get_string (buf, addr + str_off - 8);
4169 			cb_printf ("0x%08"PFMT64x"  current     %d.%d.%d\n",
4170 				pvaddr + 8, r_buf_read_le16_at (buf, addr + 10), r_buf_read8_at (buf, addr + 9),
4171 				r_buf_read8_at (buf, addr + 8));
4172 			cb_printf ("0x%08"PFMT64x"  compat      %d.%d.%d\n",
4173 				pvaddr + 12, r_buf_read_le16_at (buf, addr + 14), r_buf_read8_at (buf, addr + 13),
4174 				r_buf_read8_at (buf, addr + 12));
4175 			cb_printf ("0x%08"PFMT64x"  load_dylib  %s\n",
4176 				pvaddr + str_off - 8, r_str_get (load_dylib));
4177 			if (load_dylib) {
4178 				free (load_dylib);
4179 			}
4180 			break;
4181 		}
4182 		case LC_RPATH: {
4183 			char *rpath = r_buf_get_string (buf, addr + 4);
4184 			cb_printf ("0x%08" PFMT64x "  rpath       %s\n",
4185 				pvaddr + 4, r_str_get (rpath));
4186 			if (rpath) {
4187 				free (rpath);
4188 			}
4189 			break;
4190 		}
4191 		case LC_ENCRYPTION_INFO:
4192 		case LC_ENCRYPTION_INFO_64: {
4193 			ut32 word = r_buf_read_le32_at (buf, addr);
4194 			cb_printf ("0x%08"PFMT64x"  cryptoff   0x%08x\n", pvaddr, word);
4195 			word = r_buf_read_le32_at (buf, addr + 4);
4196 			cb_printf ("0x%08"PFMT64x"  cryptsize  %d\n", pvaddr + 4, word);
4197 			word = r_buf_read_le32_at (buf, addr + 8);
4198 			cb_printf ("0x%08"PFMT64x"  cryptid    %d\n", pvaddr + 8, word);
4199 			break;
4200 		}
4201 		case LC_CODE_SIGNATURE: {
4202 			ut32 words[2];
4203 			r_buf_read_at (buf, addr, (ut8 *)words, sizeof (words));
4204 			cb_printf ("0x%08"PFMT64x"  dataoff     0x%08x\n", pvaddr, words[0]);
4205 			cb_printf ("0x%08"PFMT64x"  datasize    %d\n", pvaddr + 4, words[1]);
4206 			cb_printf ("# wtf mach0.sign %d @ 0x%x\n", words[1], words[0]);
4207 			break;
4208 		}
4209 		}
4210 		addr += word - 8;
4211 		pvaddr += word - 8;
4212 	}
4213 	free (mh);
4214 }
4215 
MACH0_(mach_fields)4216 RList *MACH0_(mach_fields)(RBinFile *bf) {
4217 	RBuffer *buf = bf->buf;
4218 	ut64 length = r_buf_size (buf);
4219 	struct MACH0_(mach_header) *mh = MACH0_(get_hdr) (buf);
4220 	if (!mh) {
4221 		return NULL;
4222 	}
4223 	RList *ret = r_list_new ();
4224 	if (!ret) {
4225 		free (mh);
4226 		return NULL;
4227 	}
4228 	ret->free = free;
4229 	ut64 addr = pa2va (bf, 0);
4230 	ut64 paddr = 0;
4231 
4232 	r_list_append (ret, r_bin_field_new (addr, addr, 1, "header", "mach0_header", "mach0_header", true));
4233 	addr += 0x20 - 4;
4234 	paddr += 0x20 - 4;
4235 	bool is64 = mh->cputype >> 16;
4236 	if (is64) {
4237 		addr += 4;
4238 		paddr += 4;
4239 	}
4240 
4241 	bool isBe = false;
4242 	switch (mh->cputype) {
4243 	case CPU_TYPE_POWERPC:
4244 	case CPU_TYPE_POWERPC64:
4245 		isBe = true;
4246 		break;
4247 	}
4248 
4249 	int n;
4250 	for (n = 0; n < mh->ncmds; n++) {
4251 		ut32 lcType = r_buf_read_ble32_at (buf, paddr, isBe);
4252 		ut32 word = r_buf_read_ble32_at (buf, paddr + 4, isBe);
4253 		if (paddr + 8 > length) {
4254 			break;
4255 		}
4256 		ut32 lcSize = word;
4257 		word &= 0xFFFFFF;
4258 		if (lcSize < 1) {
4259 			eprintf ("Invalid size for a load command\n");
4260 			break;
4261 		}
4262 		if (word == 0) {
4263 			break;
4264 		}
4265 		const char *pf_definition = cmd_to_pf_definition (lcType);
4266 		if (pf_definition) {
4267 			r_list_append (ret, r_bin_field_new (addr, addr, 1, sdb_fmt ("load_command_%d_%s", n, cmd_to_string (lcType)), pf_definition, pf_definition, true));
4268 		}
4269 		switch (lcType) {
4270 		case LC_BUILD_VERSION: {
4271 			ut32 ntools = r_buf_read_le32_at (buf, paddr + 20);
4272 			ut64 off = 24;
4273 			int j = 0;
4274 			while (off < lcSize && ntools--) {
4275 				r_list_append (ret, r_bin_field_new (addr + off, addr + off, 1, sdb_fmt ("tool_%d", j++), "mach0_build_version_tool", "mach0_build_version_tool", true));
4276 				off += 8;
4277 			}
4278 			break;
4279 		}
4280 		case LC_SEGMENT:
4281 		case LC_SEGMENT_64: {
4282 			ut32 nsects = r_buf_read_le32_at (buf, addr + (is64 ? 64 : 48));
4283 			ut64 off = is64 ? 72 : 56;
4284 			size_t i, j = 0;
4285 			for (i = 0; i < nsects && (addr + off) < length && off < lcSize; i++) {
4286 				const char *sname = is64? "mach0_section64": "mach0_section";
4287 				RBinField *f = r_bin_field_new (addr + off, addr + off, 1,
4288 					sdb_fmt ("section_%zu", j++), sname, sname, true);
4289 				r_list_append (ret, f);
4290 				off += is64? 80: 68;
4291 			}
4292 			break;
4293 		default:
4294 			// TODO
4295 			break;
4296 		}
4297 		}
4298 		addr += word;
4299 		paddr += word;
4300 	}
4301 	free (mh);
4302 	return ret;
4303 }
4304 
MACH0_(mach_header)4305 struct MACH0_(mach_header) *MACH0_(get_hdr)(RBuffer *buf) {
4306 	ut8 magicbytes[sizeof (ut32)] = {0};
4307 	ut8 machohdrbytes[sizeof (struct MACH0_(mach_header))] = {0};
4308 	int len;
4309 	struct MACH0_(mach_header) *macho_hdr = R_NEW0 (struct MACH0_(mach_header));
4310 	bool big_endian = false;
4311 	if (!macho_hdr) {
4312 		return NULL;
4313 	}
4314 	if (r_buf_read_at (buf, 0, magicbytes, 4) < 1) {
4315 		free (macho_hdr);
4316 		return false;
4317 	}
4318 
4319 	if (r_read_le32 (magicbytes) == 0xfeedface) {
4320 		big_endian = false;
4321 	} else if (r_read_be32 (magicbytes) == 0xfeedface) {
4322 		big_endian = true;
4323 	} else if (r_read_le32 (magicbytes) == FAT_MAGIC) {
4324 		big_endian = false;
4325 	} else if (r_read_be32 (magicbytes) == FAT_MAGIC) {
4326 		big_endian = true;
4327 	} else if (r_read_le32 (magicbytes) == 0xfeedfacf) {
4328 		big_endian = false;
4329 	} else if (r_read_be32 (magicbytes) == 0xfeedfacf) {
4330 		big_endian = true;
4331 	} else {
4332 		/* also extract non-mach0s */
4333 #if 0
4334 		free (macho_hdr);
4335 		return NULL;
4336 #endif
4337 	}
4338 	len = r_buf_read_at (buf, 0, machohdrbytes, sizeof (machohdrbytes));
4339 	if (len != sizeof (struct MACH0_(mach_header))) {
4340 		free (macho_hdr);
4341 		return NULL;
4342 	}
4343 	macho_hdr->magic = r_read_ble (&machohdrbytes[0], big_endian, 32);
4344 	macho_hdr->cputype = r_read_ble (&machohdrbytes[4], big_endian, 32);
4345 	macho_hdr->cpusubtype = r_read_ble (&machohdrbytes[8], big_endian, 32);
4346 	macho_hdr->filetype = r_read_ble (&machohdrbytes[12], big_endian, 32);
4347 	macho_hdr->ncmds = r_read_ble (&machohdrbytes[16], big_endian, 32);
4348 	macho_hdr->sizeofcmds = r_read_ble (&machohdrbytes[20], big_endian, 32);
4349 	macho_hdr->flags = r_read_ble (&machohdrbytes[24], big_endian, 32);
4350 #if R_BIN_MACH064
4351 	macho_hdr->reserved = r_read_ble (&machohdrbytes[28], big_endian, 32);
4352 #endif
4353 	return macho_hdr;
4354 }
4355