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 = §ions,
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