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