librz/bin: refactor bootimg to support v1-v4 structures. (#5897)

* Fixes and support for v0-v4 formats
* Remove useless check on omf
This commit is contained in:
Giovanni 2026-02-10 02:10:22 +08:00 committed by GitHub
parent f8aec15519
commit 78574a1f2d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 715 additions and 185 deletions

View file

@ -1,3 +1,4 @@
// SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-FileCopyrightText: 2015-2019 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
@ -6,18 +7,26 @@
#include <rz_lib.h>
#include <rz_bin.h>
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
#define BOOT_EXTRA_ARGS_SIZE 1024
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
#define BOOT_EXTRA_ARGS_SIZE 1024
#define BOOT_HEADER_VERSION_OFFSET 0x28
#define BOOT_IMAGE_HEADER_V3_PAGESIZE 4096
#define BOOT_KERNEL_ADDR_DEFAULT 0x00008000
#define BOOT_SECOND_ADDR_DEFAULT 0x00f00000
#define BOOT_RAMDISK_ADDR_DEFAULT 0x01000000
#define BOOT_DTB_ADDR_DEFAULT 0x01f00000
#define ADD_REMAINDER(val, aln) ((val) + ((aln) != 0 ? ((val) % (aln)) : 0))
#define ROUND_DOWN(val, aln) ((aln) != 0 ? (((val) / (aln)) * (aln)) : (val))
typedef struct boot_img_hdr {
/**
* Boot image version 0
*/
typedef struct boot_img_hdr_0 {
ut8 magic[BOOT_MAGIC_SIZE];
ut32 kernel_size; ///< size in bytes
ut32 kernel_addr; ///< physical load addr
ut32 ramdisk_size; ///< size in bytes
@ -26,21 +35,136 @@ typedef struct boot_img_hdr {
ut32 second_addr; ///< physical load addr
ut32 tags_addr; ///< physical addr for kernel tags
ut32 page_size; ///< flash page size we assume
ut32 unused[2]; ///< future expansion: should be 0
ut8 name[BOOT_NAME_SIZE]; ///< asciiz product name
ut8 cmdline[BOOT_ARGS_SIZE];
ut32 unused; ///< must be 0
ut32 os_version; ///< OS version
char name[BOOT_NAME_SIZE]; ///< asciiz product name
char cmdline[BOOT_ARGS_SIZE];
ut32 id[8]; ///< timestamp / checksum / sha1 / etc
/*
* Supplemental command line data; kept here to maintain
* binary compatibility with older versions of mkbootimg
*/
ut8 extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} BootImage;
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} BootImage0;
static bool bootimg_read_header(RzBuffer *buf, BootImage *h) {
ut64 off = 0;
return rz_buf_read_offset(buf, &off, h->magic, BOOT_MAGIC_SIZE) &&
/**
* Boot image version 1
*/
typedef struct boot_img_hdr_1 {
ut8 magic[BOOT_MAGIC_SIZE];
ut32 kernel_size; ///< size in bytes
ut32 kernel_addr; ///< physical load addr
ut32 ramdisk_size; ///< size in bytes
ut32 ramdisk_addr; ///< physical load addr
ut32 second_size; ///< size in bytes
ut32 second_addr; ///< physical load addr
ut32 tags_addr; ///< physical addr for kernel tags
ut32 page_size; ///< flash page size we assume
ut32 header_version; ///< Must be 1
ut32 os_version;
char name[BOOT_NAME_SIZE]; ///< asciiz product name
char cmdline[BOOT_ARGS_SIZE];
ut32 id[8]; ///< timestamp / checksum / sha1 / etc
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
ut32 recovery_dtbo_acpio_size; ///< size of recovery image
ut64 recovery_dtbo_acpio_offset; ///< offset in boot image
ut32 header_size; ///< size of boot image header in bytes
} BootImage1;
/**
* Boot image version 2
*/
typedef struct boot_img_hdr_2 {
ut8 magic[BOOT_MAGIC_SIZE];
ut32 kernel_size; ///< size in bytes
ut32 kernel_addr; ///< physical load addr
ut32 ramdisk_size; ///< size in bytes
ut32 ramdisk_addr; ///< physical load addr
ut32 second_size; ///< size in bytes
ut32 second_addr; ///< physical load addr
ut32 tags_addr; ///< physical addr for kernel tags
ut32 page_size; ///< flash page size we assume
ut32 header_version;
ut32 os_version;
char name[BOOT_NAME_SIZE]; ///< asciiz product name
char cmdline[BOOT_ARGS_SIZE];
ut32 id[8]; ///< timestamp / checksum / sha1 / etc
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
ut32 recovery_dtbo_acpio_size; ///< size of recovery image
ut64 recovery_dtbo_acpio_offset; ///< offset in boot image
ut32 header_size; ///< size of boot image header in bytes
ut32 dtb_size; ///< size of dtb image
ut64 dtb_addr; ///< physical load address
} BootImage2;
/**
* Boot image version 3
*/
typedef struct boot_img_hdr_3 {
ut8 magic[BOOT_MAGIC_SIZE];
ut32 kernel_size; ///< size in bytes
ut32 ramdisk_size; ///< size in bytes
ut32 os_version;
ut32 header_size; ///< size of boot image header in bytes
ut32 reserved[4];
ut32 header_version; ///< offset remains constant for version check
char cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
} BootImage3;
/**
* Boot image version 4
*/
typedef struct boot_img_hdr_4 {
ut8 magic[BOOT_MAGIC_SIZE];
ut32 kernel_size; ///< size in bytes
ut32 ramdisk_size; ///< size in bytes
ut32 os_version;
ut32 header_size; ///< size of boot image header in bytes
ut32 reserved[4];
ut32 header_version; ///< offset remains constant for version check
char cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
ut32 signature_size; ///< size in bytes
} BootImage4;
typedef struct boot_image_obj_s {
Sdb *kv;
ut32 version;
ut32 header_size;
union {
BootImage0 v0;
BootImage1 v1;
BootImage2 v2;
BootImage3 v3;
BootImage4 v4;
} bootimg;
} BootImageObj;
static bool bootimg_set_sdb_value(Sdb *db, const char *key, const char *value, size_t v_size) {
if (RZ_STR_ISEMPTY(value)) {
// ignore empty strings.
sdb_set(db, key, "(empty)");
return true;
}
char *safe = rz_str_ndup(value, v_size);
if (!safe) {
return false;
}
sdb_set(db, key, safe);
free(safe);
return true;
}
static bool bootimg_set_sdb_array32(Sdb *db, const char *key, const ut32 *value, size_t array_size) {
for (size_t i = 0; i < array_size; i++) {
sdb_array_insert_num(db, "id", i, value[i]);
}
return true;
}
static bool bootimg_parse_v0(RzBuffer *buf, ut64 off, BootImage0 *h, Sdb *db) {
return rz_buf_read_offset(buf, &off, h->magic, sizeof(h->magic)) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_size) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_size) &&
@ -49,10 +173,10 @@ static bool bootimg_read_header(RzBuffer *buf, BootImage *h) {
rz_buf_read_le32_offset(buf, &off, &h->second_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->tags_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->page_size) &&
rz_buf_read_le32_offset(buf, &off, &h->unused[0]) &&
rz_buf_read_le32_offset(buf, &off, &h->unused[1]) &&
rz_buf_read_offset(buf, &off, h->name, BOOT_NAME_SIZE) &&
rz_buf_read_offset(buf, &off, h->cmdline, BOOT_ARGS_SIZE) &&
rz_buf_read_le32_offset(buf, &off, &h->unused) &&
rz_buf_read_le32_offset(buf, &off, &h->os_version) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->name, sizeof(h->name)) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->cmdline, sizeof(h->cmdline)) &&
rz_buf_read_le32_offset(buf, &off, &h->id[0]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[1]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[2]) &&
@ -61,41 +185,182 @@ static bool bootimg_read_header(RzBuffer *buf, BootImage *h) {
rz_buf_read_le32_offset(buf, &off, &h->id[5]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[6]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[7]) &&
rz_buf_read_offset(buf, &off, h->extra_cmdline, BOOT_EXTRA_ARGS_SIZE);
rz_buf_read_offset(buf, &off, (ut8 *)h->extra_cmdline, sizeof(h->extra_cmdline)) &&
bootimg_set_sdb_value(db, "name", h->name, sizeof(h->name)) &&
bootimg_set_sdb_value(db, "cmdline", h->cmdline, sizeof(h->cmdline)) &&
bootimg_set_sdb_array32(db, "id", h->id, RZ_ARRAY_SIZE(h->id)) &&
bootimg_set_sdb_value(db, "extra_cmdline", h->extra_cmdline, sizeof(h->extra_cmdline));
}
typedef struct {
Sdb *kv;
BootImage bi;
RzBuffer *buf;
} BootImageObj;
static bool bootimg_parse_v1(RzBuffer *buf, ut64 off, BootImage1 *h, Sdb *db) {
return rz_buf_read_offset(buf, &off, h->magic, sizeof(h->magic)) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_size) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_size) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->second_size) &&
rz_buf_read_le32_offset(buf, &off, &h->second_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->tags_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->page_size) &&
rz_buf_read_le32_offset(buf, &off, &h->header_version) &&
rz_buf_read_le32_offset(buf, &off, &h->os_version) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->name, sizeof(h->name)) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->cmdline, sizeof(h->cmdline)) &&
rz_buf_read_le32_offset(buf, &off, &h->id[0]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[1]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[2]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[3]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[4]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[5]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[6]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[7]) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->extra_cmdline, sizeof(h->extra_cmdline)) &&
rz_buf_read_le32_offset(buf, &off, &h->recovery_dtbo_acpio_size) &&
rz_buf_read_le64_offset(buf, &off, &h->recovery_dtbo_acpio_offset) &&
rz_buf_read_le32_offset(buf, &off, &h->header_size) &&
bootimg_set_sdb_value(db, "name", h->name, sizeof(h->name)) &&
bootimg_set_sdb_value(db, "cmdline", h->cmdline, sizeof(h->cmdline)) &&
bootimg_set_sdb_array32(db, "id", h->id, RZ_ARRAY_SIZE(h->id)) &&
bootimg_set_sdb_value(db, "extra_cmdline", h->extra_cmdline, sizeof(h->extra_cmdline));
}
static int bootimg_header_load(BootImageObj *obj, Sdb *db) {
char *n;
int i;
if (!bootimg_read_header(obj->buf, &obj->bi)) {
static bool bootimg_parse_v2(RzBuffer *buf, ut64 off, BootImage2 *h, Sdb *db) {
return rz_buf_read_offset(buf, &off, h->magic, sizeof(h->magic)) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_size) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_size) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->second_size) &&
rz_buf_read_le32_offset(buf, &off, &h->second_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->tags_addr) &&
rz_buf_read_le32_offset(buf, &off, &h->page_size) &&
rz_buf_read_le32_offset(buf, &off, &h->header_version) &&
rz_buf_read_le32_offset(buf, &off, &h->os_version) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->name, sizeof(h->name)) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->cmdline, sizeof(h->cmdline)) &&
rz_buf_read_le32_offset(buf, &off, &h->id[0]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[1]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[2]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[3]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[4]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[5]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[6]) &&
rz_buf_read_le32_offset(buf, &off, &h->id[7]) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->extra_cmdline, sizeof(h->extra_cmdline)) &&
rz_buf_read_le32_offset(buf, &off, &h->recovery_dtbo_acpio_size) &&
rz_buf_read_le64_offset(buf, &off, &h->recovery_dtbo_acpio_offset) &&
rz_buf_read_le32_offset(buf, &off, &h->header_size) &&
rz_buf_read_le32_offset(buf, &off, &h->dtb_size) &&
rz_buf_read_le64_offset(buf, &off, &h->dtb_addr) &&
bootimg_set_sdb_value(db, "name", h->name, sizeof(h->name)) &&
bootimg_set_sdb_value(db, "cmdline", h->cmdline, sizeof(h->cmdline)) &&
bootimg_set_sdb_array32(db, "id", h->id, RZ_ARRAY_SIZE(h->id)) &&
bootimg_set_sdb_value(db, "extra_cmdline", h->extra_cmdline, sizeof(h->extra_cmdline));
}
static bool bootimg_parse_v3(RzBuffer *buf, ut64 off, BootImage3 *h, Sdb *db) {
return rz_buf_read_offset(buf, &off, h->magic, sizeof(h->magic)) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_size) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_size) &&
rz_buf_read_le32_offset(buf, &off, &h->os_version) &&
rz_buf_read_le32_offset(buf, &off, &h->header_size) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[0]) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[1]) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[2]) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[3]) &&
rz_buf_read_le32_offset(buf, &off, &h->header_version) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->cmdline, sizeof(h->cmdline)) &&
bootimg_set_sdb_value(db, "cmdline", h->cmdline, sizeof(h->cmdline));
}
static bool bootimg_parse_v4(RzBuffer *buf, ut64 off, BootImage4 *h, Sdb *db) {
return rz_buf_read_offset(buf, &off, h->magic, sizeof(h->magic)) &&
rz_buf_read_le32_offset(buf, &off, &h->kernel_size) &&
rz_buf_read_le32_offset(buf, &off, &h->ramdisk_size) &&
rz_buf_read_le32_offset(buf, &off, &h->os_version) &&
rz_buf_read_le32_offset(buf, &off, &h->header_size) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[0]) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[1]) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[2]) &&
rz_buf_read_le32_offset(buf, &off, &h->reserved[3]) &&
rz_buf_read_le32_offset(buf, &off, &h->header_version) &&
rz_buf_read_offset(buf, &off, (ut8 *)h->cmdline, sizeof(h->cmdline)) &&
rz_buf_read_le32_offset(buf, &off, &h->signature_size) &&
bootimg_set_sdb_value(db, "cmdline", h->cmdline, sizeof(h->cmdline));
}
static void bootimg_free(BootImageObj *bio) {
if (!bio) {
return;
}
sdb_free(bio->kv);
free(bio);
}
static bool bootimg_parse(RzBuffer *buf, ut64 off, BootImageObj *img) {
sdb_num_set(img->kv, "header_version", img->version);
switch (img->version) {
case 0:
img->header_size = sizeof(BootImage0);
return bootimg_parse_v0(buf, off, &img->bootimg.v0, img->kv);
case 1:
img->header_size = sizeof(BootImage1);
return bootimg_parse_v1(buf, off, &img->bootimg.v1, img->kv);
case 2:
img->header_size = sizeof(BootImage2);
return bootimg_parse_v2(buf, off, &img->bootimg.v2, img->kv);
case 3:
img->header_size = sizeof(BootImage3);
return bootimg_parse_v3(buf, off, &img->bootimg.v3, img->kv);
case 4:
img->header_size = sizeof(BootImage4);
return bootimg_parse_v4(buf, off, &img->bootimg.v4, img->kv);
default:
RZ_LOG_ERROR("bootimg: unsupported version v%u\n", img->version);
return false;
}
BootImage *bi = &obj->bi;
if ((n = rz_str_ndup((char *)bi->name, BOOT_NAME_SIZE))) {
sdb_set(db, "name", n);
free(n);
}
static bool bootimg_check_buffer(RzBuffer *buf) {
ut8 tmp[8] = { 0 };
if (rz_buf_read_at(buf, 0, tmp, 8) != 8) {
return false;
}
if ((n = rz_str_ndup((char *)bi->cmdline, BOOT_ARGS_SIZE))) {
sdb_set(db, "cmdline", n);
free(n);
return !memcmp(tmp, (const ut8 *)"ANDROID!", 8);
}
static bool bootimg_load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
BootImageObj *img = RZ_NEW0(BootImageObj);
if (!img) {
return false;
}
for (i = 0; i < 8; i++) {
sdb_num_set(db, "id", (ut64)bi->id[i]);
if (!rz_buf_read_le32_at(buf, BOOT_HEADER_VERSION_OFFSET, &img->version)) {
bootimg_free(img);
return false;
}
if ((n = rz_str_ndup((char *)bi->extra_cmdline, BOOT_EXTRA_ARGS_SIZE))) {
sdb_set(db, "extra_cmdline", n);
free(n);
img->kv = sdb_new0();
if (!img->kv || !bootimg_parse(buf, 0, img)) {
bootimg_free(img);
return false;
}
sdb_ns_set(sdb, "info", img->kv);
obj->bin_obj = img;
return true;
}
static Sdb *get_sdb(RzBinFile *bf) {
static void bootimg_destroy(RzBinFile *bf) {
if (!bf || !bf->o || !bf->o->bin_obj) {
return;
}
BootImageObj *img = bf->o->bin_obj;
bf->o->bin_obj = NULL;
bootimg_free(img);
}
static Sdb *bootimg_get_sdb(RzBinFile *bf) {
RzBinObject *o = bf->o;
BootImageObj *ao;
if (!o) {
@ -105,127 +370,336 @@ static Sdb *get_sdb(RzBinFile *bf) {
return ao ? ao->kv : NULL;
}
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
BootImageObj *bio = RZ_NEW0(BootImageObj);
if (!bio) {
return false;
static ut64 bootimg_kernel_vaddr(const BootImageObj *bio) {
switch (bio->version) {
case 0:
return bio->bootimg.v0.kernel_addr;
case 1:
return bio->bootimg.v1.kernel_addr;
case 2:
return bio->bootimg.v2.kernel_addr;
case 3:
// TODO: requires parsing the vendor boot header.
rz_warn_if_reached();
return BOOT_KERNEL_ADDR_DEFAULT;
case 4:
// TODO: requires parsing the vendor boot header.
rz_warn_if_reached();
return BOOT_KERNEL_ADDR_DEFAULT;
default:
// default based on mkbootimg
return BOOT_KERNEL_ADDR_DEFAULT;
}
bio->kv = sdb_new0();
if (!bio->kv) {
free(bio);
return false;
}
bio->buf = rz_buf_ref(buf);
if (!bootimg_header_load(bio, bio->kv)) {
sdb_free(bio->kv);
rz_buf_free(bio->buf);
free(bio);
return false;
}
sdb_ns_set(sdb, "info", bio->kv);
obj->bin_obj = bio;
return true;
}
static void destroy(RzBinFile *bf) {
if (!bf || !bf->o || !bf->o->bin_obj) {
return;
static ut64 bootimg_page_size(const BootImageObj *bio) {
// before v3 the page_size is available, afterwards is at 4096
switch (bio->version) {
case 0:
return bio->bootimg.v0.page_size;
case 1:
return bio->bootimg.v1.page_size;
case 2:
return bio->bootimg.v2.page_size;
default:
return BOOT_IMAGE_HEADER_V3_PAGESIZE;
}
}
static ut64 bootimg_kernel_size(const BootImageObj *bio) {
switch (bio->version) {
case 0:
return bio->bootimg.v0.kernel_size;
case 1:
return bio->bootimg.v1.kernel_size;
case 2:
return bio->bootimg.v2.kernel_size;
case 3:
return bio->bootimg.v3.kernel_size;
case 4:
return bio->bootimg.v4.kernel_size;
default:
return 0;
}
}
static ut64 bootimg_ramdisk_vaddr(const BootImageObj *bio) {
switch (bio->version) {
case 0:
return bio->bootimg.v0.ramdisk_addr;
case 1:
return bio->bootimg.v1.ramdisk_addr;
case 2:
return bio->bootimg.v2.ramdisk_addr;
case 3:
// TODO: requires parsing the vendor boot header.
rz_warn_if_reached();
return BOOT_RAMDISK_ADDR_DEFAULT;
case 4:
// TODO: requires parsing the vendor boot header.
rz_warn_if_reached();
return BOOT_RAMDISK_ADDR_DEFAULT;
default:
// default based on mkbootimg
return BOOT_RAMDISK_ADDR_DEFAULT;
}
}
static ut64 bootimg_ramdisk_size(const BootImageObj *bio) {
switch (bio->version) {
case 0:
return bio->bootimg.v0.ramdisk_size;
case 1:
return bio->bootimg.v1.ramdisk_size;
case 2:
return bio->bootimg.v2.ramdisk_size;
case 3:
return bio->bootimg.v3.ramdisk_size;
case 4:
return bio->bootimg.v4.ramdisk_size;
default:
return 0;
}
}
static ut64 bootimg_second_vaddr(const BootImageObj *bio) {
switch (bio->version) {
case 0:
return bio->bootimg.v0.second_addr;
case 1:
return bio->bootimg.v1.second_addr;
case 2:
return bio->bootimg.v2.second_addr;
default:
// from v3 the secondary bootloader does not exists.
return 0;
}
}
static ut64 bootimg_second_size(const BootImageObj *bio) {
switch (bio->version) {
case 0:
return bio->bootimg.v0.second_size;
case 1:
return bio->bootimg.v1.second_size;
case 2:
return bio->bootimg.v2.second_size;
default:
// from v3 the secondary bootloader does not exists.
return 0;
}
}
static ut64 bootimg_baddr(RzBinFile *bf) {
BootImageObj *bio = bf->o->bin_obj;
rz_buf_free(bio->buf);
sdb_free(bio->kv);
RZ_FREE(bf->o->bin_obj);
return bootimg_kernel_vaddr(bio);
}
static ut64 baddr(RzBinFile *bf) {
BootImageObj *bio = bf->o->bin_obj;
return bio ? bio->bi.kernel_addr : 0;
}
static RzPVector /*<RzBinString *>*/ *strings(RzBinFile *bf) {
return NULL;
}
static RzBinInfo *info(RzBinFile *bf) {
RzBinInfo *ret;
static RzBinInfo *bootimg_info(RzBinFile *bf) {
if (!bf || !bf->o || !bf->o->bin_obj) {
return NULL;
}
ret = RZ_NEW0(RzBinInfo);
RzBinInfo *ret = RZ_NEW0(RzBinInfo);
if (!ret) {
return NULL;
}
BootImageObj *bio = bf->o->bin_obj;
ret->lang = NULL;
ret->file = rz_str_dup(bf->file);
ret->type = rz_str_dup("Android Boot Image");
ret->type = rz_str_newf("Android Boot Image)");
ret->bclass = rz_str_newf("Android Boot Image (v%u)", bio->version);
ret->os = rz_str_dup("android");
ret->subsystem = rz_str_dup("unknown");
ret->machine = rz_str_dup("arm");
ret->arch = rz_str_dup("arm");
ret->has_va = 1;
ret->has_pi = 0;
ret->bits = 16;
ret->bits = 32;
ret->big_endian = 0;
ret->dbg_info = 0;
ret->rclass = rz_str_dup("image");
ret->rclass = rz_str_dup("bootimg");
return ret;
}
static bool check_buffer(RzBuffer *buf) {
ut8 tmp[13];
int r = rz_buf_read_at(buf, 0, tmp, sizeof(tmp));
return r > 12 && !strncmp((const char *)tmp, "ANDROID!", 8);
static void bootimg_structure_v0(const BootImage0 *bi, RzStructuredData *root) {
rz_structured_data_map_add_bytes(root, "magic", bi->magic, sizeof(bi->magic), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
rz_structured_data_map_add_unsigned(root, "kernel_size", bi->kernel_size, false);
rz_structured_data_map_add_unsigned(root, "kernel_addr", bi->kernel_addr, true);
rz_structured_data_map_add_unsigned(root, "ramdisk_size", bi->ramdisk_size, false);
rz_structured_data_map_add_unsigned(root, "ramdisk_addr", bi->ramdisk_addr, true);
rz_structured_data_map_add_unsigned(root, "second_size", bi->second_size, false);
rz_structured_data_map_add_unsigned(root, "second_addr", bi->second_addr, true);
rz_structured_data_map_add_unsigned(root, "tags_addr", bi->tags_addr, true);
rz_structured_data_map_add_unsigned(root, "page_size", bi->page_size, false);
rz_structured_data_map_add_unsigned(root, "unused", bi->unused, true);
rz_structured_data_map_add_unsigned(root, "os_version", bi->os_version, true);
rz_structured_data_map_add_string_n(root, "name", bi->name, sizeof(bi->name));
rz_structured_data_map_add_string_n(root, "cmdline", bi->cmdline, sizeof(bi->cmdline));
RzStructuredData *id_array = rz_structured_data_map_add_array(root, "id");
if (id_array) {
rz_structured_data_array_add_unsigned(id_array, bi->id[0], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[1], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[2], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[3], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[4], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[5], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[6], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[7], true);
}
rz_structured_data_map_add_string_n(root, "extra_cmdline", bi->extra_cmdline, sizeof(bi->extra_cmdline));
}
static void bootimg_structure_v1(const BootImage1 *bi, RzStructuredData *root) {
rz_structured_data_map_add_bytes(root, "magic", bi->magic, sizeof(bi->magic), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
rz_structured_data_map_add_unsigned(root, "kernel_size", bi->kernel_size, false);
rz_structured_data_map_add_unsigned(root, "kernel_addr", bi->kernel_addr, true);
rz_structured_data_map_add_unsigned(root, "ramdisk_size", bi->ramdisk_size, false);
rz_structured_data_map_add_unsigned(root, "ramdisk_addr", bi->ramdisk_addr, true);
rz_structured_data_map_add_unsigned(root, "second_size", bi->second_size, false);
rz_structured_data_map_add_unsigned(root, "second_addr", bi->second_addr, true);
rz_structured_data_map_add_unsigned(root, "tags_addr", bi->tags_addr, true);
rz_structured_data_map_add_unsigned(root, "page_size", bi->page_size, false);
rz_structured_data_map_add_unsigned(root, "header_version", bi->header_version, true);
rz_structured_data_map_add_unsigned(root, "os_version", bi->os_version, true);
rz_structured_data_map_add_string_n(root, "name", bi->name, sizeof(bi->name));
rz_structured_data_map_add_string_n(root, "cmdline", bi->cmdline, sizeof(bi->cmdline));
RzStructuredData *id_array = rz_structured_data_map_add_array(root, "id");
if (id_array) {
rz_structured_data_array_add_unsigned(id_array, bi->id[0], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[1], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[2], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[3], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[4], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[5], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[6], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[7], true);
}
rz_structured_data_map_add_string_n(root, "extra_cmdline", bi->extra_cmdline, sizeof(bi->extra_cmdline));
rz_structured_data_map_add_unsigned(root, "recovery_dtbo_acpio_size", bi->recovery_dtbo_acpio_size, false);
rz_structured_data_map_add_unsigned(root, "recovery_dtbo_acpio_offset", bi->recovery_dtbo_acpio_offset, true);
rz_structured_data_map_add_unsigned(root, "header_size", bi->header_size, false);
}
static void bootimg_structure_v2(const BootImage2 *bi, RzStructuredData *root) {
rz_structured_data_map_add_bytes(root, "magic", bi->magic, sizeof(bi->magic), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
rz_structured_data_map_add_unsigned(root, "kernel_size", bi->kernel_size, false);
rz_structured_data_map_add_unsigned(root, "kernel_addr", bi->kernel_addr, true);
rz_structured_data_map_add_unsigned(root, "ramdisk_size", bi->ramdisk_size, false);
rz_structured_data_map_add_unsigned(root, "ramdisk_addr", bi->ramdisk_addr, true);
rz_structured_data_map_add_unsigned(root, "second_size", bi->second_size, false);
rz_structured_data_map_add_unsigned(root, "second_addr", bi->second_addr, true);
rz_structured_data_map_add_unsigned(root, "tags_addr", bi->tags_addr, true);
rz_structured_data_map_add_unsigned(root, "page_size", bi->page_size, false);
rz_structured_data_map_add_unsigned(root, "header_version", bi->header_version, true);
rz_structured_data_map_add_unsigned(root, "os_version", bi->os_version, true);
rz_structured_data_map_add_string_n(root, "name", bi->name, sizeof(bi->name));
rz_structured_data_map_add_string_n(root, "cmdline", bi->cmdline, sizeof(bi->cmdline));
RzStructuredData *id_array = rz_structured_data_map_add_array(root, "id");
if (id_array) {
rz_structured_data_array_add_unsigned(id_array, bi->id[0], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[1], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[2], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[3], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[4], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[5], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[6], true);
rz_structured_data_array_add_unsigned(id_array, bi->id[7], true);
}
rz_structured_data_map_add_string_n(root, "extra_cmdline", bi->extra_cmdline, sizeof(bi->extra_cmdline));
rz_structured_data_map_add_unsigned(root, "recovery_dtbo_acpio_size", bi->recovery_dtbo_acpio_size, false);
rz_structured_data_map_add_unsigned(root, "recovery_dtbo_acpio_offset", bi->recovery_dtbo_acpio_offset, true);
rz_structured_data_map_add_unsigned(root, "header_size", bi->header_size, false);
rz_structured_data_map_add_unsigned(root, "dtb_size", bi->dtb_size, false);
rz_structured_data_map_add_unsigned(root, "dtb_addr", bi->dtb_addr, true);
}
static void bootimg_structure_v3(const BootImage3 *bi, RzStructuredData *root) {
rz_structured_data_map_add_bytes(root, "magic", bi->magic, sizeof(bi->magic), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
rz_structured_data_map_add_unsigned(root, "kernel_size", bi->kernel_size, false);
rz_structured_data_map_add_unsigned(root, "ramdisk_size", bi->ramdisk_size, false);
rz_structured_data_map_add_unsigned(root, "os_version", bi->os_version, true);
rz_structured_data_map_add_unsigned(root, "header_size", bi->header_size, false);
RzStructuredData *reserved = rz_structured_data_map_add_array(root, "reserved");
if (reserved) {
rz_structured_data_array_add_unsigned(reserved, bi->reserved[0], true);
rz_structured_data_array_add_unsigned(reserved, bi->reserved[1], true);
rz_structured_data_array_add_unsigned(reserved, bi->reserved[2], true);
rz_structured_data_array_add_unsigned(reserved, bi->reserved[3], true);
}
rz_structured_data_map_add_unsigned(root, "header_version", bi->header_version, false);
rz_structured_data_map_add_string_n(root, "cmdline", bi->cmdline, sizeof(bi->cmdline));
}
static void bootimg_structure_v4(const BootImage4 *bi, RzStructuredData *root) {
rz_structured_data_map_add_bytes(root, "magic", bi->magic, sizeof(bi->magic), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
rz_structured_data_map_add_unsigned(root, "kernel_size", bi->kernel_size, false);
rz_structured_data_map_add_unsigned(root, "ramdisk_size", bi->ramdisk_size, false);
rz_structured_data_map_add_unsigned(root, "os_version", bi->os_version, true);
rz_structured_data_map_add_unsigned(root, "header_size", bi->header_size, false);
RzStructuredData *reserved = rz_structured_data_map_add_array(root, "reserved");
if (reserved) {
rz_structured_data_array_add_unsigned(reserved, bi->reserved[0], true);
rz_structured_data_array_add_unsigned(reserved, bi->reserved[1], true);
rz_structured_data_array_add_unsigned(reserved, bi->reserved[2], true);
rz_structured_data_array_add_unsigned(reserved, bi->reserved[3], true);
}
rz_structured_data_map_add_unsigned(root, "header_version", bi->header_version, false);
rz_structured_data_map_add_string_n(root, "cmdline", bi->cmdline, sizeof(bi->cmdline));
rz_structured_data_map_add_unsigned(root, "signature_size", bi->signature_size, false);
}
static RzStructuredData *bootimg_structure(RzBinFile *bf) {
rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, NULL);
BootImageObj *bio = bf->o->bin_obj;
BootImage *bi = &bio->bi;
BootImageObj *img = bf->o->bin_obj;
RzStructuredData *info = rz_structured_data_new_map();
if (!info) {
return NULL;
}
RzStructuredData *boot = rz_structured_data_map_add_map(info, "bootimg");
if (!boot) {
RzStructuredData *root = rz_structured_data_map_add_map(info, "bootimg");
if (!root) {
rz_structured_data_free(info);
return NULL;
}
rz_structured_data_map_add_string(boot, "magic", "ANDROID!");
rz_structured_data_map_add_unsigned(boot, "kernel_size", bi->kernel_size, false);
rz_structured_data_map_add_unsigned(boot, "kernel_addr", bi->kernel_addr, true);
rz_structured_data_map_add_unsigned(boot, "ramdisk_size", bi->ramdisk_size, false);
rz_structured_data_map_add_unsigned(boot, "ramdisk_addr", bi->ramdisk_addr, true);
rz_structured_data_map_add_unsigned(boot, "second_size", bi->second_size, false);
rz_structured_data_map_add_unsigned(boot, "second_addr", bi->second_addr, true);
rz_structured_data_map_add_unsigned(boot, "tags_addr", bi->tags_addr, true);
rz_structured_data_map_add_unsigned(boot, "page_size", bi->page_size, false);
char structure_bootimg[BOOT_EXTRA_ARGS_SIZE + 1] = { 0 };
rz_str_ncpy(structure_bootimg, (const char *)bi->name, BOOT_NAME_SIZE);
rz_structured_data_map_add_string(boot, "name", structure_bootimg);
rz_str_ncpy(structure_bootimg, (const char *)bi->cmdline, BOOT_ARGS_SIZE);
rz_structured_data_map_add_string(boot, "cmdline", structure_bootimg);
rz_str_ncpy(structure_bootimg, (const char *)bi->extra_cmdline, BOOT_EXTRA_ARGS_SIZE);
rz_structured_data_map_add_string(boot, "extra_cmdline", structure_bootimg);
switch (img->version) {
case 0:
bootimg_structure_v0(&img->bootimg.v0, root);
break;
case 1:
bootimg_structure_v1(&img->bootimg.v1, root);
break;
case 2:
bootimg_structure_v2(&img->bootimg.v2, root);
break;
case 3:
bootimg_structure_v3(&img->bootimg.v3, root);
break;
case 4:
bootimg_structure_v4(&img->bootimg.v4, root);
break;
default:
rz_structured_data_free(info);
return NULL;
}
return info;
}
static RzPVector /*<RzBinAddr *>*/ *entries(RzBinFile *bf) {
BootImageObj *bio = bf->o->bin_obj;
static RzPVector /*<RzBinAddr *>*/ *bootimg_entries(RzBinFile *bf) {
BootImageObj *img = bf->o->bin_obj;
RzBinAddr *ptr = NULL;
if (!bio) {
if (!img) {
return NULL;
}
BootImage *bi = &bio->bi;
RzPVector *ret;
if (!(ret = rz_pvector_new(free))) {
@ -234,74 +708,102 @@ static RzPVector /*<RzBinAddr *>*/ *entries(RzBinFile *bf) {
if (!(ptr = RZ_NEW0(RzBinAddr))) {
return ret;
}
ptr->paddr = bi->page_size;
ptr->vaddr = bi->kernel_addr;
ptr->paddr = bootimg_page_size(img);
ptr->vaddr = bootimg_kernel_vaddr(img);
rz_pvector_push(ret, ptr);
return ret;
}
static RzPVector /*<RzBinSection *>*/ *sections(RzBinFile *bf) {
BootImageObj *bio = bf->o->bin_obj;
if (!bio) {
static RzBinSection *bootimg_bin_section_new(const char *name, ut64 paddr, size_t psize, ut64 vaddr, size_t vsize, ut32 perm) {
RzBinSection *sec = RZ_NEW0(RzBinSection);
if (!sec) {
return NULL;
}
sec->name = rz_str_dup(name);
if (!sec->name) {
free(sec);
return NULL;
}
sec->paddr = paddr;
sec->size = psize;
sec->vaddr = vaddr;
sec->vsize = vsize;
sec->perm = perm;
return sec;
}
static void bootimg_sections_add_ramdisk(BootImageObj *img, RzPVector /*<RzBinSection *>*/ *ret) {
ut64 kernel_size = bootimg_kernel_size(img);
ut64 ramdisk_size = bootimg_ramdisk_size(img);
ut64 page_size = bootimg_page_size(img);
ut64 ramdisk_addr = bootimg_ramdisk_vaddr(img);
if (ramdisk_size < 1) {
return;
}
ut64 base = kernel_size + 2 * page_size - 1;
ut64 paddr = ROUND_DOWN(base, page_size);
size_t vsize = ADD_REMAINDER(ramdisk_size, page_size);
RzBinSection *ptr = bootimg_bin_section_new("ramdisk", paddr, ramdisk_size, ramdisk_addr, vsize, RZ_PERM_RX);
if (!ptr || !rz_pvector_push(ret, ptr)) {
rz_bin_section_free(ptr);
}
}
static void bootimg_sections_add_secondary_bootloader(BootImageObj *img, RzPVector /*<RzBinSection *>*/ *ret) {
ut64 second_size = bootimg_second_size(img);
ut64 second_addr = bootimg_second_vaddr(img);
ut64 kernel_size = bootimg_kernel_size(img);
ut64 ramdisk_size = bootimg_ramdisk_size(img);
ut64 page_size = bootimg_page_size(img);
if (second_size < 1) {
return;
}
ut64 base = kernel_size + ramdisk_size + 2 * page_size - 1;
ut64 paddr = ROUND_DOWN(base, page_size);
size_t vsize = ADD_REMAINDER(second_size, page_size);
RzBinSection *ptr = bootimg_bin_section_new("second", paddr, second_size, second_addr, vsize, RZ_PERM_RX);
if (!ptr || !rz_pvector_push(ret, ptr)) {
rz_bin_section_free(ptr);
}
}
static RzPVector /*<RzBinSection *>*/ *bootimg_sections(RzBinFile *bf) {
BootImageObj *img = bf->o->bin_obj;
if (!img) {
return NULL;
}
BootImage *bi = &bio->bi;
RzPVector *ret = NULL;
RzBinSection *ptr = NULL;
ut64 kernel_size = bootimg_kernel_size(img);
ut64 page_size = bootimg_page_size(img);
ut64 kernel_vaddr = bootimg_kernel_vaddr(img);
if (!(ret = rz_pvector_new(free))) {
return NULL;
}
if (!(ptr = RZ_NEW0(RzBinSection))) {
ptr = bootimg_bin_section_new("header", 0, img->header_size, 0, page_size, RZ_PERM_R);
if (!ptr || !rz_pvector_push(ret, ptr)) {
rz_bin_section_free(ptr);
return ret;
}
ptr->name = rz_str_dup("header");
ptr->size = sizeof(BootImage);
ptr->vsize = bi->page_size;
ptr->paddr = 0;
ptr->vaddr = 0;
ptr->perm = RZ_PERM_R; // r--
rz_pvector_push(ret, ptr);
if (!(ptr = RZ_NEW0(RzBinSection))) {
size_t kernel_vsize = ADD_REMAINDER(kernel_size, page_size);
ptr = bootimg_bin_section_new("kernel", page_size, kernel_size, kernel_vaddr, kernel_vsize, RZ_PERM_R);
if (!ptr || !rz_pvector_push(ret, ptr)) {
rz_bin_section_free(ptr);
return ret;
}
ptr->name = rz_str_dup("kernel");
ptr->size = bi->kernel_size;
ptr->vsize = ADD_REMAINDER(ptr->size, bi->page_size);
ptr->paddr = bi->page_size;
ptr->vaddr = bi->kernel_addr;
ptr->perm = RZ_PERM_R; // r--
rz_pvector_push(ret, ptr);
if (bi->ramdisk_size > 0) {
ut64 base = bi->kernel_size + 2 * bi->page_size - 1;
if (!(ptr = RZ_NEW0(RzBinSection))) {
return ret;
}
ptr->name = rz_str_dup("ramdisk");
ptr->size = bi->ramdisk_size;
ptr->vsize = ADD_REMAINDER(bi->ramdisk_size, bi->page_size);
ptr->paddr = ROUND_DOWN(base, bi->page_size);
ptr->vaddr = bi->ramdisk_addr;
ptr->perm = RZ_PERM_RX; // r-x
rz_pvector_push(ret, ptr);
}
if (bi->second_size > 0) {
ut64 base = bi->kernel_size + bi->ramdisk_size + 2 * bi->page_size - 1;
if (!(ptr = RZ_NEW0(RzBinSection))) {
return ret;
}
ptr->name = rz_str_dup("second");
ptr->size = bi->second_size;
ptr->vsize = ADD_REMAINDER(bi->second_size, bi->page_size);
ptr->paddr = ROUND_DOWN(base, bi->page_size);
ptr->vaddr = bi->second_addr;
ptr->perm = RZ_PERM_RX; // r-x
rz_pvector_push(ret, ptr);
}
bootimg_sections_add_ramdisk(img, ret);
bootimg_sections_add_secondary_bootloader(img, ret);
return ret;
}
@ -311,16 +813,15 @@ RzBinPlugin rz_bin_plugin_bootimg = {
.desc = "Android Boot Image",
.license = "LGPL3",
.author = "pancake",
.get_sdb = &get_sdb,
.load_buffer = &load_buffer,
.destroy = &destroy,
.check_buffer = &check_buffer,
.baddr = &baddr,
.get_sdb = &bootimg_get_sdb,
.load_buffer = &bootimg_load_buffer,
.destroy = &bootimg_destroy,
.check_buffer = &bootimg_check_buffer,
.baddr = &bootimg_baddr,
.maps = rz_bin_maps_of_file_sections,
.sections = &sections,
.entries = entries,
.strings = &strings,
.info = &info,
.sections = &bootimg_sections,
.entries = &bootimg_entries,
.info = &bootimg_info,
.bin_structure = &bootimg_structure
};

View file

@ -222,10 +222,8 @@ static void omf_structure_add_section(RzStructuredData *sections, OMF_segment *s
}
const char *name = omf_segment_name(obj, seg);
if (name) {
rz_structured_data_map_add_string(section, "name", rz_str_get(name));
}
rz_structured_data_map_add_string(section, "name", rz_str_get(name));
rz_structured_data_map_add_unsigned(section, "name_idx", seg->name_idx, false);
rz_structured_data_map_add_unsigned(section, "vaddr", seg->vaddr, true);
rz_structured_data_map_add_unsigned(section, "size", seg->size, false);

View file

@ -1,16 +1,24 @@
NAME=empty.img
FILE=bins/bootimg/empty.img
CMDS=iI;iH
CMDS=<<EOF
iI
echo ---
iH
echo ---
ik
echo ---
iS
EOF
EXPECT=<<EOF
arch arm
cpu N/A
features N/A
baddr 0x40200000
binsz 0x00001800
bintype image
bits 16
bintype bootimg
bits 32
retguard false
class N/A
class Android Boot Image (v0)
compiler N/A
dbg_file N/A
endian LE
@ -21,10 +29,10 @@ laddr 0x00000000
lang N/A
machine arm
maxopsz 4
minopsz 2
minopsz 4
os android
cc N/A
pcalign 2
pcalign 4
rpath N/A
subsys unknown
stripped false
@ -39,8 +47,9 @@ canary false
PIE false
RELROCS false
NX false
---
bootimg:
magic: "ANDROID!"
magic: "41 4e 44 52 4f 49 44 21 |ANDROID! |"
kernel_size: 128
kernel_addr: 0x40200000
ramdisk_size: 0
@ -49,10 +58,32 @@ bootimg:
second_addr: 0x41100000
tags_addr: 0x40200100
page_size: 2048
unused: 0x0
os_version: 0x0
name: "d1-nezha"
cmdline: ""
id:
- 0xbd563c5
- 0x697b3fe8
- 0x262502ad
- 0xa2d21d53
- 0x813eafa8
- 0x0
- 0x0
- 0x0
extra_cmdline: ""
---
cmdline=(empty)
extra_cmdline=(empty)
header_version=0
id=0xbd563c5,0x697b3fe8,0x262502ad,0xa2d21d53,0x813eafa8,0,0,0
name=d1-nezha
---
paddr size vaddr vsize align perm name type flags
---------------------------------------------------------------
0x00000000 0x660 0x00000000 0x800 0x0 -r-- header
0x00000800 0x80 0x40200000 0x100 0x0 -r-- kernel
EOF
RUN