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