1 /* radare - LGPL - Copyright 2009-2019 - nibble, pancake */
2
3 #include <r_types.h>
4 #include <r_util.h>
5 #include <r_lib.h>
6 #include <r_bin.h>
7
8 #define R_BIN_MACH064 1
9 #include "../format/mach0/mach0.h"
10 #include "../format/mach0/mach0_defines.h"
11
12 /* at offset 0x10f8 (pointer to it stored right after "legion2") */
13 typedef struct _RSepHdr64 {
14 ut8 kernel_uuid[16];
15 ut64 unknown0;
16 ut64 kernel_base_paddr;
17 ut64 kernel_max_paddr;
18 ut64 app_images_base_paddr;
19 ut64 app_images_max_paddr;
20 ut64 paddr_max; /* size of SEP firmware image */
21 ut64 unknown1;
22 ut64 unknown2;
23 ut64 unknown3;
24 ut64 init_base_paddr;
25 ut64 unknown4;
26 ut64 unknown5;
27 ut64 unknown6;
28 ut64 unknown7;
29 ut64 unknown8;
30 ut64 unknown9;
31 char init_name[16];
32 ut8 init_uuid[16];
33 ut64 unknown10;
34 ut64 unknown11;
35 ut64 n_apps;
36 } RSepHdr64;
37
38 /* right after the above, from offset 0x11c0 */
39 typedef struct _RSepApp64 {
40 ut64 phys_text;
41 ut64 size_text;
42 ut64 phys_data;
43 ut64 size_data;
44 ut64 virt;
45 ut64 entry;
46 ut64 unknown4;
47 ut64 unknown5;
48 ut64 unknown6;
49 ut32 minus_one;
50 ut32 unknown7;
51 char app_name[16];
52 ut8 app_uuid[16];
53 ut64 unknown8;
54 } RSepApp64;
55
56 typedef struct _RSepMachoInfo {
57 struct MACH0_(mach_header) * hdr;
58 ut64 total_size;
59 ut64 text_size;
60 ut64 data_offset;
61 ut64 data_size;
62 ut64 text_offset_in_whole;
63 ut64 data_offset_in_whole;
64 } RSepMachoInfo;
65
66 typedef struct _RSepSlice64 {
67 RBuffer * buf;
68 RBinXtrMetadata * meta;
69 ut64 nominal_offset;
70 ut64 total_size;
71 } RSepSlice64;
72
73 typedef struct _RSepXtr64Ctx {
74 RSepHdr64 * hdr;
75 RSepApp64 * apps;
76 } RSepXtr64Ctx;
77
78 static RSepXtr64Ctx * sep64_xtr_ctx_new(RBuffer * buf);
79 static void sep64_xtr_ctx_free(void * p);
80 static RSepSlice64 * sep64_xtr_ctx_get_slice(RSepXtr64Ctx * ctx, RBuffer * whole, int idx);
81
82 static RSepMachoInfo * mach0_info_new(RBuffer * buf, ut64 at, ut64 max_size);
83 static void mach0_info_free(RSepMachoInfo * info);
84
85 static ut32 read_arm64_ins(RBuffer *b, int idx);
86 static char * get_proper_name (const char * app_name);
87 static RBuffer * extract_slice(RBuffer * whole, RSepMachoInfo * info);
88 static inline void fill_metadata_info_from_hdr(RBinXtrMetadata *meta, struct MACH0_(mach_header) *hdr);
89
90 #define BTW(val, min, max) ((val) > min && (val) < max)
91
check_buffer(RBuffer * b)92 static bool check_buffer(RBuffer *b) {
93 r_return_val_if_fail (b, false);
94
95 const ut64 sz = r_buf_size (b);
96 if (sz < 0x11c0) {
97 return false;
98 }
99
100 ut32 msr_vbar_el1 = read_arm64_ins (b, 2);
101 if (msr_vbar_el1 != 0xd518c002) {
102 return false;
103 }
104 ut32 adr = read_arm64_ins (b, 1);
105 if (adr != 0x10003fe2) {
106 return false;
107 }
108
109 /* check exception vector */
110 if (read_arm64_ins (b, 512) != 0x14000000) {
111 return false;
112 }
113 if (read_arm64_ins (b, 1023) != 0x14000000) {
114 return false;
115 }
116
117 /* legion2 */
118 if (read_arm64_ins (b, 1028) != 0x326e6f69) {
119 return false;
120 }
121
122 /* data header start */
123 ut64 hdr_offset = read_arm64_ins (b, 1029);
124 if (hdr_offset >= sz) {
125 return false;
126 }
127
128 /* check size */
129 if (r_buf_read_le64_at (b, hdr_offset + 56) != sz) {
130 return false;
131 }
132
133 return true;
134 }
135
load(RBin * bin)136 static bool load(RBin *bin) {
137 return ((bin->cur->xtr_obj = sep64_xtr_ctx_new (bin->cur->buf)) != NULL);
138 }
139
destroy(RBin * bin)140 static void destroy(RBin *bin) {
141 sep64_xtr_ctx_free (bin->cur->xtr_obj);
142 }
143
size(RBin * bin)144 static int size(RBin *bin) {
145 // TODO
146 return 0;
147 }
148
oneshot_buffer(RBin * bin,RBuffer * b,int idx)149 static RBinXtrData *oneshot_buffer(RBin *bin, RBuffer *b, int idx) {
150 r_return_val_if_fail (bin && bin->cur, NULL);
151
152 if (!bin->cur->xtr_obj) {
153 bin->cur->xtr_obj = sep64_xtr_ctx_new (b);
154 }
155 RSepXtr64Ctx * ctx = bin->cur->xtr_obj;
156
157 RSepSlice64 * slice = sep64_xtr_ctx_get_slice (ctx, b, idx);
158 RBinXtrData * res = r_bin_xtrdata_new (slice->buf, slice->nominal_offset, slice->total_size, 3 + ctx->hdr->n_apps, slice->meta);
159
160 r_buf_free (slice->buf);
161 free (slice);
162 return res;
163 }
164
oneshotall_buffer(RBin * bin,RBuffer * b)165 static RList * oneshotall_buffer(RBin *bin, RBuffer *b) {
166 RBinXtrData *data = oneshot_buffer (bin, b, 0);
167 if (data) {
168 int narch = data->file_count;
169 RList *res = r_list_newf (r_bin_xtrdata_free);
170 if (!res) {
171 r_bin_xtrdata_free (data);
172 return NULL;
173 }
174 r_list_append (res, data);
175 int i;
176 for (i = 1; data && i < narch; i++) {
177 data = oneshot_buffer (bin, b, i);
178 r_list_append (res, data);
179 }
180 return res;
181 }
182 return NULL;
183 }
184
sep64_xtr_ctx_new(RBuffer * buf)185 static RSepXtr64Ctx * sep64_xtr_ctx_new(RBuffer * buf) {
186 RSepHdr64 * hdr = NULL;
187 RSepApp64 * apps = NULL;
188 RSepXtr64Ctx * ctx = NULL;
189
190 ut64 hdr_offset = r_buf_read_le64_at (buf, 0x1014);
191 if (hdr_offset == UT64_MAX) {
192 goto beach;
193 }
194
195 hdr = R_NEW0 (RSepHdr64);
196 if (!hdr) {
197 goto beach;
198 }
199 if (r_buf_fread_at (buf, hdr_offset, (ut8 *) hdr, "16c16l16c16c3l", 1) != sizeof (RSepHdr64)) {
200 goto beach;
201 }
202
203 if (!hdr->n_apps) {
204 goto beach;
205 }
206
207 ut64 apps_at = hdr_offset + sizeof (RSepHdr64);
208 apps = R_NEWS0 (RSepApp64, hdr->n_apps);
209 if (!apps) {
210 goto beach;
211 }
212 if (r_buf_fread_at (buf, apps_at, (ut8*) apps, "9l2i16c16cl", hdr->n_apps) != (sizeof (RSepApp64) * hdr->n_apps)) {
213 goto beach;
214 }
215
216 ctx = R_NEW0 (RSepXtr64Ctx);
217 if (!ctx) {
218 goto beach;
219 }
220
221 ctx->hdr = hdr;
222 ctx->apps = apps;
223
224 return ctx;
225 beach:
226 free (hdr);
227 free (apps);
228 free (ctx);
229
230 return NULL;
231 }
232
sep64_xtr_ctx_free(void * p)233 static void sep64_xtr_ctx_free(void * p) {
234 if (!p) {
235 return;
236 }
237
238 RSepXtr64Ctx * ctx = p;
239
240 R_FREE (ctx->hdr);
241 R_FREE (ctx->apps);
242
243 free (ctx);
244 }
245
sep64_xtr_ctx_get_slice(RSepXtr64Ctx * ctx,RBuffer * whole,int idx)246 static RSepSlice64 * sep64_xtr_ctx_get_slice(RSepXtr64Ctx * ctx, RBuffer * whole, int idx) {
247 if (idx >= ctx->hdr->n_apps + 3) {
248 return NULL;
249 }
250
251 ut64 whole_size = r_buf_size (whole);
252 RBuffer * slice_buf = NULL;
253 char * name = NULL;
254 RSepSlice64 * slice = NULL;
255 RSepMachoInfo * info = NULL;
256 RBinXtrMetadata * meta = NULL;
257 ut64 nominal_offset = 0;
258 ut64 total_size = 0;
259
260 if (idx == 0) {
261 name = strdup ("boot");
262 slice_buf = r_buf_new_slice (whole, 0, ctx->hdr->kernel_base_paddr);
263 total_size = ctx->hdr->kernel_base_paddr;
264 } else if (idx == 1) {
265 name = strdup ("kernel");
266 info = mach0_info_new (whole, ctx->hdr->kernel_base_paddr, whole_size - ctx->hdr->kernel_base_paddr);
267 if (!info) {
268 goto beach;
269 }
270 slice_buf = r_buf_new_slice (whole, ctx->hdr->kernel_base_paddr, info->total_size);
271 nominal_offset = ctx->hdr->kernel_base_paddr;
272 total_size = info->total_size;
273 } else if (idx == 2) {
274 name = get_proper_name (ctx->hdr->init_name);
275 info = mach0_info_new (whole, ctx->hdr->init_base_paddr, whole_size - ctx->hdr->init_base_paddr);
276 if (!info) {
277 goto beach;
278 }
279 slice_buf = extract_slice (whole, info);
280 nominal_offset = ctx->hdr->init_base_paddr;
281 total_size = info->total_size;
282 } else {
283 int app_idx = idx - 3;
284 name = get_proper_name (ctx->apps[app_idx].app_name);
285 info = mach0_info_new (whole, ctx->apps[app_idx].phys_text, whole_size - ctx->apps[app_idx].phys_text);
286 if (!info) {
287 goto beach;
288 }
289 info->data_offset_in_whole = ctx->apps[app_idx].phys_data;
290 slice_buf = extract_slice (whole, info);
291 nominal_offset = ctx->apps[app_idx].phys_text;
292 total_size = info->total_size;
293 }
294
295 if (!name || !slice_buf) {
296 goto beach;
297 }
298
299 meta = R_NEW0 (RBinXtrMetadata);
300 if (!meta) {
301 goto beach;
302 }
303
304 if (info) {
305 fill_metadata_info_from_hdr (meta, info->hdr);
306 } else {
307 meta->arch = strdup ("arm");
308 meta->bits = 64;
309 meta->machine = strdup ("arm64e");
310 meta->type = strdup ("Executable file");
311 }
312
313 meta->xtr_type = "SEP";
314 meta->libname = name;
315
316 slice = R_NEW0 (RSepSlice64);
317 if (!slice) {
318 goto beach;
319 }
320
321 slice->buf = slice_buf;
322 slice->nominal_offset = nominal_offset;
323 slice->total_size = total_size;
324 slice->meta = meta;
325
326 mach0_info_free (info);
327
328 return slice;
329 beach:
330 r_buf_free (slice_buf);
331 free (name);
332 free (slice);
333 free (meta);
334 mach0_info_free (info);
335 return NULL;
336 }
337
mach0_info_new(RBuffer * buf,ut64 at,ut64 max_size)338 static RSepMachoInfo * mach0_info_new(RBuffer * buf, ut64 at, ut64 max_size) {
339 r_return_val_if_fail (max_size >= 1024, NULL);
340
341 RSepMachoInfo * result = NULL;
342 struct MACH0_(mach_header) *hdr = NULL;
343 ut8 * commands = NULL;
344 ut64 total_size = 0, text_size = 0, data_offset = 0, data_size = 0;
345
346 ut32 hdr_size = sizeof (struct MACH0_(mach_header));
347 hdr = malloc (hdr_size);
348 if (!hdr) {
349 goto beach;
350 }
351 if (r_buf_read_at (buf, at, (ut8 *) hdr, hdr_size) != hdr_size) {
352 goto beach;
353 }
354 if (hdr->magic != MH_MAGIC_64 || !BTW (hdr->sizeofcmds, 0, max_size)) {
355 goto beach;
356 }
357
358 commands = malloc (hdr->sizeofcmds);
359 if (!commands) {
360 goto beach;
361 }
362 if (r_buf_read_at (buf, at + hdr_size, commands, hdr->sizeofcmds) != hdr->sizeofcmds) {
363 goto beach;
364 }
365
366 ut32 i;
367 ut8 * cursor = commands;
368 for (i = 0; i < hdr->ncmds; i++) {
369 const struct load_command * cmd = (struct load_command *) cursor;
370 if (cmd->cmd == LC_SEGMENT_64) {
371 const struct MACH0_(segment_command) * seg = (struct MACH0_(segment_command) *) cursor;
372 ut64 end = seg->fileoff + seg->filesize;
373 if (total_size < end) {
374 total_size = end;
375 }
376 if (!strcmp (seg->segname, "__TEXT")) {
377 text_size = seg->filesize;
378 } else if (!strcmp (seg->segname, "__DATA")) {
379 data_offset = seg->fileoff;
380 data_size = seg->filesize;
381 }
382 }
383 cursor = cursor + cmd->cmdsize;
384 }
385
386 if (total_size == 0 || text_size == 0 || data_offset == 0 || data_size == 0) {
387 goto beach;
388 }
389
390 result = R_NEW0 (RSepMachoInfo);
391 if (!result) {
392 goto beach;
393 }
394
395 result->hdr = hdr;
396 result->total_size = total_size;
397 result->text_size = text_size;
398 result->data_offset = data_offset;
399 result->data_size = data_size;
400 result->text_offset_in_whole = at;
401
402 free (commands);
403
404 return result;
405 beach:
406
407 free (result);
408 free (hdr);
409 free (commands);
410
411 return NULL;
412 }
413
mach0_info_free(RSepMachoInfo * info)414 static void mach0_info_free(RSepMachoInfo * info) {
415 if (!info) {
416 return;
417 }
418
419 free (info->hdr);
420 free (info);
421 }
422
extract_slice(RBuffer * whole,RSepMachoInfo * info)423 static RBuffer * extract_slice(RBuffer * whole, RSepMachoInfo * info) {
424 ut8 * content = NULL;
425
426 content = (ut8 *) malloc (info->total_size);
427 if (!content) {
428 goto beach;
429 }
430 if (r_buf_read_at (whole, info->text_offset_in_whole, content, info->text_size) != info->text_size) {
431 goto beach;
432 }
433 ut64 data_offset = info->data_offset_in_whole ? info->data_offset_in_whole : info->text_offset_in_whole + info->data_offset;
434 if (r_buf_read_at (whole, data_offset, content + info->data_offset, info->data_size) != info->data_size) {
435 goto beach;
436 }
437
438 return r_buf_new_with_pointers (content, info->total_size, true);
439 beach:
440 free (content);
441
442 return NULL;
443 }
444
fill_metadata_info_from_hdr(RBinXtrMetadata * meta,struct MACH0_ (mach_header)* hdr)445 static inline void fill_metadata_info_from_hdr(RBinXtrMetadata *meta, struct MACH0_(mach_header) *hdr) {
446 meta->arch = strdup (MACH0_(get_cputype_from_hdr) (hdr));
447 meta->bits = MACH0_(get_bits_from_hdr) (hdr);
448 meta->machine = MACH0_(get_cpusubtype_from_hdr) (hdr);
449 meta->type = MACH0_(get_filetype_from_hdr) (hdr);
450 }
451
get_proper_name(const char * app_name)452 static char * get_proper_name (const char * app_name) {
453 char * proper_name = calloc (13, 1);
454 if (!proper_name) {
455 return NULL;
456 }
457 int i;
458
459 for (i = 12; i != -1; i--) {
460 if (app_name[i] == ' ') {
461 proper_name[i] = 0;
462 } else {
463 proper_name[i] = app_name[i];
464 }
465 }
466
467 return proper_name;
468 }
469
read_arm64_ins(RBuffer * b,int idx)470 static ut32 read_arm64_ins(RBuffer *b, int idx) {
471 return r_buf_read_le32_at (b, idx * 4);
472 }
473
474 RBinXtrPlugin r_bin_xtr_plugin_xtr_sep64 = {
475 .name = "xtr.sep64",
476 .desc = "64-bit SEP bin extractor plugin",
477 .license = "LGPL3",
478 .check_buffer = check_buffer,
479 .load = &load,
480 .destroy = &destroy,
481 .size = &size,
482 .extract_from_buffer = &oneshot_buffer,
483 .extractall_from_buffer = &oneshotall_buffer,
484 .free_xtr = &sep64_xtr_ctx_free,
485 };
486
487 #ifndef R2_PLUGIN_INCORE
488 R_API RLibStruct radare_plugin = {
489 .type = R_LIB_TYPE_BIN_XTR,
490 .data = &r_bin_xtr_plugin_xtr_sep64,
491 .version = R2_VERSION
492 };
493 #endif
494