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 #include "mach0/dyldcache.h"
8 #include "mach0/mach0.h"
9 
10 static RBinXtrData * extract(RBin *bin, int idx);
11 static RList * extractall(RBin *bin);
12 static RBinXtrData * oneshot(RBin *bin, const ut8 *buf, ut64 size, int idx);
13 static RList * oneshotall(RBin *bin, const ut8 *buf, ut64 size);
14 
check_buffer(RBuffer * buf)15 static bool check_buffer(RBuffer *buf) {
16 	ut8 b[4] = {0};
17 	r_buf_read_at (buf, 0, b, sizeof (b));
18 	return !memcmp (buf, "dyld", 4);
19 }
20 
free_xtr(void * xtr_obj)21 static void free_xtr(void *xtr_obj) {
22 	r_bin_dyldcache_free ((struct r_bin_dyldcache_obj_t*)xtr_obj);
23 }
24 
destroy(RBin * bin)25 static void destroy(RBin *bin) {
26 	free_xtr (bin->cur->xtr_obj);
27 }
28 
load(RBin * bin)29 static bool load(RBin *bin) {
30 	if (!bin || !bin->cur) {
31 	    return false;
32 	}
33 	if (!bin->cur->xtr_obj) {
34 		bin->cur->xtr_obj = r_bin_dyldcache_new (bin->cur->file);
35 	}
36 	if (!bin->file) {
37 	   	bin->file = bin->cur->file;
38 	}
39 	return bin->cur->xtr_obj? true : false;
40 }
41 
extractall(RBin * bin)42 static RList * extractall(RBin *bin) {
43 	RList *result = NULL;
44 	int nlib, i = 0;
45 	RBinXtrData *data = extract (bin, i);
46 	if (!data) {
47 		return result;
48 	}
49 	// XXX - how do we validate a valid nlib?
50 	nlib = data->file_count;
51 	result = r_list_newf (r_bin_xtrdata_free);
52 	if (!result) {
53 		r_bin_xtrdata_free (data);
54 		return NULL;
55 	}
56 	r_list_append (result, data);
57 	for (i = 1; data && i < nlib; i++) {
58 		data = extract (bin, i);
59 		r_list_append (result, data);
60 	}
61 	return result;
62 }
63 
fill_metadata_info_from_hdr(RBinXtrMetadata * meta,struct MACH0_ (mach_header)* hdr)64 static inline void fill_metadata_info_from_hdr(RBinXtrMetadata *meta, struct MACH0_ (mach_header) *hdr) {
65 	meta->arch = strdup (MACH0_(get_cputype_from_hdr) (hdr));
66 	meta->bits = MACH0_(get_bits_from_hdr) (hdr);
67 	meta->machine = MACH0_(get_cpusubtype_from_hdr) (hdr);
68 	meta->type = MACH0_(get_filetype_from_hdr) (hdr);
69 }
70 
extract(RBin * bin,int idx)71 static RBinXtrData *extract(RBin *bin, int idx) {
72 	int nlib = 0;
73 	RBinXtrData *res = NULL;
74 	char *libname;
75 	struct MACH0_(mach_header) *hdr;
76 	struct r_bin_dyldcache_lib_t *lib = r_bin_dyldcache_extract (
77 		(struct r_bin_dyldcache_obj_t*)bin->cur->xtr_obj, idx, &nlib);
78 
79 	if (lib) {
80 		RBinXtrMetadata *metadata = R_NEW0(RBinXtrMetadata);
81 		if (!metadata) {
82 			free (lib);
83 			return NULL;
84 		}
85 		hdr = MACH0_(get_hdr) (lib->b);
86 		if (!hdr) {
87 			free (lib);
88 			R_FREE (metadata);
89 			free (hdr);
90 			return NULL;
91 		}
92 		fill_metadata_info_from_hdr (metadata, hdr);
93 		r_bin_dydlcache_get_libname (lib, &libname);
94 		metadata->libname = strdup (libname);
95 
96 		res = r_bin_xtrdata_new (lib->b, lib->offset, lib->size, nlib, metadata);
97 		r_buf_free (lib->b);
98 		free (lib);
99 		free (hdr);
100 	}
101 	return res;
102 }
103 
oneshot(RBin * bin,const ut8 * buf,ut64 size,int idx)104 static RBinXtrData *oneshot(RBin *bin, const ut8* buf, ut64 size, int idx) {
105 	RBinXtrData *res = NULL;
106 	struct r_bin_dyldcache_obj_t *xtr_obj;
107 	struct r_bin_dyldcache_lib_t *lib;
108 	int nlib = 0;
109 	char *libname;
110 	struct MACH0_(mach_header) *hdr;
111 
112 	if (!load (bin)) {
113 		return NULL;
114 	}
115 
116 	xtr_obj = bin->cur->xtr_obj;
117 	lib = r_bin_dyldcache_extract (xtr_obj, idx, &nlib);
118 	if (!lib) {
119 		free_xtr (xtr_obj);
120 		bin->cur->xtr_obj = NULL;
121 		return NULL;
122 	}
123 	RBinXtrMetadata *metadata = R_NEW0 (RBinXtrMetadata);
124 	if (!metadata) {
125 		free (lib);
126 		return NULL;
127 	}
128 	hdr = MACH0_(get_hdr) (lib->b);
129 	if (!hdr) {
130 		free (lib);
131 		free (metadata);
132 		return NULL;
133 	}
134 	fill_metadata_info_from_hdr (metadata, hdr);
135 	r_bin_dydlcache_get_libname (lib, &libname);
136 	metadata->libname = strdup (libname);
137 
138 	res = r_bin_xtrdata_new (lib->b, lib->offset, r_buf_size (lib->b), nlib, metadata);
139 	r_buf_free (lib->b);
140 	free (hdr);
141 	free (lib);
142 	return res;
143 }
144 
oneshotall(RBin * bin,const ut8 * buf,ut64 size)145 static RList * oneshotall(RBin *bin, const ut8* buf, ut64 size) {
146 	RBinXtrData *data = NULL;
147 	RList *res = NULL;
148 	int nlib, i = 0;
149 	if (!bin->file) {
150 		if (!load (bin)) {
151 			return NULL;
152 		}
153 	}
154 	data = oneshot (bin, buf, size, i);
155 	if (!data) {
156 		return res;
157 	}
158 	// XXX - how do we validate a valid nlib?
159 	nlib = data->file_count;
160 	res = r_list_newf (r_bin_xtrdata_free);
161 	if (!res) {
162 		r_bin_xtrdata_free (data);
163 		return NULL;
164 	}
165 	r_list_append (res, data);
166 	for (i = 1; data && i < nlib; i++) {
167 		data = oneshot (bin, buf, size, i);
168 		r_list_append (res, data);
169 	}
170 	return res;
171 }
172 
173 RBinXtrPlugin r_bin_xtr_plugin_xtr_dyldcache = {
174 	.name = "xtr.dyldcache",
175 	.desc = "dyld cache bin extractor plugin",
176 	.license = "LGPL3",
177 	.load = &load,
178 	.extract = &extract,
179 	.extractall = &extractall,
180 	.destroy = &destroy,
181 	.extract_from_bytes = &oneshot,
182 	.extractall_from_bytes = &oneshotall,
183 	.free_xtr = &free_xtr,
184 	.check_buffer = &check_buffer,
185 };
186 
187 #ifndef R2_PLUGIN_INCORE
188 R_API RLibStruct radare_plugin = {
189 	.type = R_LIB_TYPE_BIN_XTR,
190 	.data = &r_bin_xtr_plugin_dyldcache,
191 	.version = R2_VERSION
192 };
193 #endif
194