1 /* radare - LGPL - Copyright 2015-2019 - pancake */
2 
3 #include <r_types.h>
4 #include <r_util.h>
5 #include <r_lib.h>
6 #include <r_bin.h>
7 
8 typedef struct boot_img_hdr BootImage;
9 
10 #define BOOT_MAGIC "ANDROID!"
11 #define BOOT_MAGIC_SIZE 8
12 #define BOOT_NAME_SIZE 16
13 #define BOOT_ARGS_SIZE 512
14 #define BOOT_EXTRA_ARGS_SIZE 1024
15 
16 #define ADD_REMAINDER(val, aln) ((val) + ((aln) != 0 ? ((val) % (aln)) : 0))
17 #define ROUND_DOWN(val, aln) ((aln) != 0 ? (((val) / (aln)) * (aln)) : (val))
18 
19 R_PACKED (
20 struct boot_img_hdr {
21 	ut8 magic[BOOT_MAGIC_SIZE];
22 
23 	ut32 kernel_size;  /* size in bytes */
24 	ut32 kernel_addr;  /* physical load addr */
25 
26 	ut32 ramdisk_size; /* size in bytes */
27 	ut32 ramdisk_addr; /* physical load addr */
28 
29 	ut32 second_size;  /* size in bytes */
30 	ut32 second_addr;  /* physical load addr */
31 
32 	ut32 tags_addr;    /* physical addr for kernel tags */
33 	ut32 page_size;    /* flash page size we assume */
34 	ut32 unused[2];    /* future expansion: should be 0 */
35 	ut8 name[BOOT_NAME_SIZE]; /* asciiz product name */
36 	ut8 cmdline[BOOT_ARGS_SIZE];
37 	ut32 id[8]; /* timestamp / checksum / sha1 / etc */
38 
39 	/* Supplemental command line data; kept here to maintain
40 	 * binary compatibility with older versions of mkbootimg */
41 	ut8 extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
42 });
43 
44 typedef struct {
45 	Sdb *kv;
46 	BootImage bi;
47 	RBuffer *buf;
48 } BootImageObj;
49 
bootimg_header_load(BootImageObj * obj,Sdb * db)50 static int bootimg_header_load(BootImageObj *obj, Sdb *db) {
51 	char *n;
52 	int i;
53 	if (r_buf_size (obj->buf) < sizeof (BootImage)) {
54 		return false;
55 	}
56 	// TODO make it endian-safe (void)r_buf_fread_at (buf, 0, (ut8*)bi, "IIiiiiiiiiiiii", 1);
57 	BootImage *bi = &obj->bi;
58 	(void) r_buf_read_at (obj->buf, 0, (ut8 *)bi, sizeof (BootImage));
59 	if ((n = r_str_ndup ((char *) bi->name, BOOT_NAME_SIZE))) {
60 		sdb_set (db, "name", n, 0);
61 		free (n);
62 	}
63 	if ((n = r_str_ndup ((char *) bi->cmdline, BOOT_ARGS_SIZE))) {
64 		sdb_set (db, "cmdline", n, 0);
65 		free (n);
66 	}
67 	for (i = 0; i < 8; i++) {
68 		sdb_num_set (db, "id", (ut64) bi->id[i], 0);
69 	}
70 	if ((n = r_str_ndup ((char *) bi->extra_cmdline, BOOT_EXTRA_ARGS_SIZE))) {
71 		sdb_set (db, "extra_cmdline", n, 0);
72 		free (n);
73 	}
74 	return true;
75 }
76 
get_sdb(RBinFile * bf)77 static Sdb *get_sdb(RBinFile *bf) {
78 	RBinObject *o = bf->o;
79 	BootImageObj *ao;
80 	if (!o) {
81 		return NULL;
82 	}
83 	ao = o->bin_obj;
84 	return ao? ao->kv: NULL;
85 }
86 
load_buffer(RBinFile * bf,void ** bin_obj,RBuffer * buf,ut64 loadaddr,Sdb * sdb)87 static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadaddr, Sdb *sdb) {
88 	BootImageObj *bio = R_NEW0 (BootImageObj);
89 	if (!bio) {
90 		return false;
91 	}
92 	bio->kv = sdb_new0 ();
93 	if (!bio->kv) {
94 		free (bio);
95 		return false;
96 	}
97 	bio->buf = r_buf_ref (buf);
98 	if (!bootimg_header_load (bio, bio->kv)) {
99 		free (bio);
100 		return false;
101 	}
102 	sdb_ns_set (sdb, "info", bio->kv);
103 	*bin_obj = bio;
104 	return true;
105 }
106 
destroy(RBinFile * bf)107 static void destroy(RBinFile *bf) {
108 	BootImageObj *bio = bf->o->bin_obj;
109 	r_buf_free (bio->buf);
110 	R_FREE (bf->o->bin_obj);
111 }
112 
baddr(RBinFile * bf)113 static ut64 baddr(RBinFile *bf) {
114 	BootImageObj *bio = bf->o->bin_obj;
115 	return bio? bio->bi.kernel_addr: 0;
116 }
117 
strings(RBinFile * bf)118 static RList *strings(RBinFile *bf) {
119 	return NULL;
120 }
121 
info(RBinFile * bf)122 static RBinInfo *info(RBinFile *bf) {
123 	RBinInfo *ret;
124 	if (!bf || !bf->o || !bf->o->bin_obj) {
125 		return NULL;
126 	}
127 	ret = R_NEW0 (RBinInfo);
128 	if (!ret) {
129 		return NULL;
130 	}
131 
132 	ret->lang = NULL;
133 	ret->file = bf->file? strdup (bf->file): NULL;
134 	ret->type = strdup ("Android Boot Image");
135 	ret->os = strdup ("android");
136 	ret->subsystem = strdup ("unknown");
137 	ret->machine = strdup ("arm");
138 	ret->arch = strdup ("arm");
139 	ret->has_va = 1;
140 	ret->has_pi = 0;
141 	ret->bits = 16;
142 	ret->big_endian = 0;
143 	ret->dbg_info = 0;
144 	ret->rclass = strdup ("image");
145 	return ret;
146 }
147 
check_buffer(RBuffer * buf)148 static bool check_buffer(RBuffer *buf) {
149 	ut8 tmp[13];
150 	int r = r_buf_read_at (buf, 0, tmp, sizeof (tmp));
151 	return r > 12 && !strncmp ((const char *)tmp, "ANDROID!", 8);
152 }
153 
entries(RBinFile * bf)154 static RList *entries(RBinFile *bf) {
155 	BootImageObj *bio = bf->o->bin_obj;
156 	RBinAddr *ptr = NULL;
157 	if (!bio) {
158 		return NULL;
159 	}
160 	BootImage *bi = &bio->bi;
161 	RList *ret;
162 
163 	if (!(ret = r_list_newf (free))) {
164 		return NULL;
165 	}
166 	if (!(ptr = R_NEW0 (RBinAddr))) {
167 		return ret;
168 	}
169 	ptr->paddr = bi->page_size;
170 	ptr->vaddr = bi->kernel_addr;
171 	r_list_append (ret, ptr);
172 	return ret;
173 }
174 
sections(RBinFile * bf)175 static RList *sections(RBinFile *bf) {
176 	BootImageObj *bio = bf->o->bin_obj;
177 	if (!bio) {
178 		return NULL;
179 	}
180 	BootImage *bi = &bio->bi;
181 	RList *ret = NULL;
182 	RBinSection *ptr = NULL;
183 
184 	if (!(ret = r_list_new ())) {
185 		return NULL;
186 	}
187 	ret->free = free;
188 
189 	if (!(ptr = R_NEW0 (RBinSection))) {
190 		return ret;
191 	}
192 	ptr->name = strdup ("header");
193 	ptr->size = sizeof (BootImage);
194 	ptr->vsize = bi->page_size;
195 	ptr->paddr = 0;
196 	ptr->vaddr = 0;
197 	ptr->perm = R_PERM_R; // r--
198 	ptr->add = true;
199 	r_list_append (ret, ptr);
200 
201 	if (!(ptr = R_NEW0 (RBinSection))) {
202 		return ret;
203 	}
204 	ptr->name = strdup ("kernel");
205 	ptr->size = bi->kernel_size;
206 	ptr->vsize = ADD_REMAINDER (ptr->size, bi->page_size);
207 	ptr->paddr = bi->page_size;
208 	ptr->vaddr = bi->kernel_addr;
209 	ptr->perm = R_PERM_R; // r--
210 	ptr->add = true;
211 	r_list_append (ret, ptr);
212 
213 	if (bi->ramdisk_size > 0) {
214 		ut64 base = bi->kernel_size + 2 * bi->page_size - 1;
215 		if (!(ptr = R_NEW0 (RBinSection))) {
216 			return ret;
217 		}
218 		ptr->name = strdup ("ramdisk");
219 		ptr->size = bi->ramdisk_size;
220 		ptr->vsize = ADD_REMAINDER (bi->ramdisk_size, bi->page_size);
221 		ptr->paddr = ROUND_DOWN (base, bi->page_size);
222 		ptr->vaddr = bi->ramdisk_addr;
223 		ptr->perm = R_PERM_RX; // r-x
224 		ptr->add = true;
225 		r_list_append (ret, ptr);
226 	}
227 
228 	if (bi->second_size > 0) {
229 		ut64 base = bi->kernel_size + bi->ramdisk_size + 2 * bi->page_size - 1;
230 		if (!(ptr = R_NEW0 (RBinSection))) {
231 			return ret;
232 		}
233 		ptr->name = strdup ("second");
234 		ptr->size = bi->second_size;
235 		ptr->vsize = ADD_REMAINDER (bi->second_size, bi->page_size);
236 		ptr->paddr = ROUND_DOWN (base, bi->page_size);
237 		ptr->vaddr = bi->second_addr;
238 		ptr->perm = R_PERM_RX; // r-x
239 		ptr->add = true;
240 		r_list_append (ret, ptr);
241 	}
242 
243 	return ret;
244 }
245 
246 RBinPlugin r_bin_plugin_bootimg = {
247 	.name = "bootimg",
248 	.desc = "Android Boot Image",
249 	.license = "LGPL3",
250 	.get_sdb = &get_sdb,
251 	.load_buffer = &load_buffer,
252 	.destroy = &destroy,
253 	.check_buffer = &check_buffer,
254 	.baddr = &baddr,
255 	.sections = &sections,
256 	.entries = entries,
257 	.strings = &strings,
258 	.info = &info,
259 };
260 
261 #ifndef R2_PLUGIN_INCORE
262 R_API RLibStruct radare_plugin = {
263 	.type = R_LIB_TYPE_BIN,
264 	.data = &r_bin_plugin_bootimg,
265 	.version = R2_VERSION
266 };
267 #endif
268