Expose MBN plugin functions for other Bin plugins.
This commit is contained in:
parent
3200b9e836
commit
28bd9cfa24
4 changed files with 380 additions and 198 deletions
212
librz/bin/format/mbn/mbn.c
Normal file
212
librz/bin/format/mbn/mbn.c
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
// SPDX-FileCopyrightText: 2015-2019 pancake <pancake@nopcode.org>
|
||||
// SPDX-FileCopyrightText: 2025 Rot127 <unisono@quyllur.org>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
/**
|
||||
* \file The MBN file format is not publicly documented currently.
|
||||
* It is used in Qualcomm firmware images to verify the firmware binaries against the root of trust.
|
||||
* There are more than one version of the MBN file format.
|
||||
* This implementation only handles the signature bundle for the Qualcomm secure boot mechanism.
|
||||
* For details see:
|
||||
* https://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/secure-boot-and-image-authentication-version_final.pdf
|
||||
*
|
||||
* Another, more complete, MBN implantation can be found here:
|
||||
* https://github.com/openpst/libopenpst/blob/master/include/qualcomm/mbn.h
|
||||
*/
|
||||
|
||||
#include "mbn.h"
|
||||
#include <stddef.h>
|
||||
|
||||
bool mbn_read_sbl_header(RzBuffer *b, SblHeader *sb, ut64 *offset) {
|
||||
return rz_buf_read_le32_offset(b, offset, &sb->image_id) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->version) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->paddr) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->vaddr) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->psize) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->code_pa) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->sign_va) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->sign_sz) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->cert_va) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->cert_sz);
|
||||
}
|
||||
|
||||
bool mbn_check_buffer(RzBuffer *b) {
|
||||
ut64 offset = 0;
|
||||
SblHeader sb = { 0 };
|
||||
rz_return_val_if_fail(b, false);
|
||||
if (!mbn_read_sbl_header(b, &sb, &offset)) {
|
||||
return false;
|
||||
}
|
||||
if (sb.version != 3) { // NAND
|
||||
return false;
|
||||
}
|
||||
if (sb.paddr + sizeof(SblHeader) > offset) { // NAND
|
||||
return false;
|
||||
}
|
||||
if (sb.vaddr < 0x100 || sb.psize > offset) { // NAND
|
||||
return false;
|
||||
}
|
||||
if (sb.cert_va < sb.vaddr) {
|
||||
return false;
|
||||
}
|
||||
if (sb.cert_sz >= 0xf0000) {
|
||||
return false;
|
||||
}
|
||||
if (sb.sign_va < sb.vaddr) {
|
||||
return false;
|
||||
}
|
||||
if (sb.sign_sz >= 0xf0000) {
|
||||
return false;
|
||||
}
|
||||
if (sb.image_id == RZ_MBN_kMbnImageNone || sb.image_id > RZ_MBN_kMbnImageLast) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mbn_load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) {
|
||||
ut64 offset = 0;
|
||||
SblHeader *sb = RZ_NEW0(SblHeader);
|
||||
if (!sb || !mbn_read_sbl_header(b, sb, &offset)) {
|
||||
free(sb);
|
||||
return false;
|
||||
}
|
||||
|
||||
obj->bin_obj = sb;
|
||||
return true;
|
||||
}
|
||||
|
||||
ut64 mbn_baddr(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
return sb->vaddr;
|
||||
}
|
||||
|
||||
RzPVector /*<RzBinAddr *>*/ *mbn_entries(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
RzPVector *ret = rz_pvector_new(free);
|
||||
if (ret) {
|
||||
RzBinAddr *ptr = RZ_NEW0(RzBinAddr);
|
||||
if (ptr) {
|
||||
ptr->paddr = 40 + sb->code_pa;
|
||||
ptr->vaddr = 40 + sb->code_pa + sb->vaddr;
|
||||
rz_pvector_push(ret, ptr);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
RzPVector /*<RzBinSection *>*/ *mbn_sections(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
RzBinSection *ptr = NULL;
|
||||
RzPVector *ret = NULL;
|
||||
if (!(ret = rz_pvector_new(free))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// add text segment
|
||||
if (!(ptr = RZ_NEW0(RzBinSection))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->name = rz_str_dup("text");
|
||||
ptr->size = sb->psize;
|
||||
ptr->vsize = sb->psize;
|
||||
ptr->paddr = sb->paddr + 40;
|
||||
ptr->vaddr = sb->vaddr;
|
||||
ptr->perm = RZ_PERM_RX; // r-x
|
||||
ptr->has_strings = true;
|
||||
rz_pvector_push(ret, ptr);
|
||||
|
||||
if (!(ptr = RZ_NEW0(RzBinSection))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->name = rz_str_dup("sign");
|
||||
ptr->size = sb->sign_sz;
|
||||
ptr->vsize = sb->sign_sz;
|
||||
ptr->paddr = sb->sign_va - sb->vaddr;
|
||||
ptr->vaddr = sb->sign_va;
|
||||
ptr->perm = RZ_PERM_R; // r--
|
||||
ptr->has_strings = true;
|
||||
rz_pvector_push(ret, ptr);
|
||||
|
||||
if (sb->cert_sz && sb->cert_va > sb->vaddr) {
|
||||
if (!(ptr = RZ_NEW0(RzBinSection))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->name = rz_str_dup("cert");
|
||||
ptr->size = sb->cert_sz;
|
||||
ptr->vsize = sb->cert_sz;
|
||||
ptr->paddr = sb->cert_va - sb->vaddr;
|
||||
ptr->vaddr = sb->cert_va;
|
||||
ptr->perm = RZ_PERM_R; // r--
|
||||
ptr->has_strings = true;
|
||||
rz_pvector_push(ret, ptr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
RzBinInfo *mbn_info(RzBinFile *bf) {
|
||||
RzBinInfo *ret = NULL;
|
||||
const int bits = 16;
|
||||
if (!(ret = RZ_NEW0(RzBinInfo))) {
|
||||
return NULL;
|
||||
}
|
||||
ret->file = rz_str_dup(bf->file);
|
||||
ret->bclass = rz_str_dup("bootloader");
|
||||
ret->rclass = rz_str_dup("mbn");
|
||||
ret->os = rz_str_dup("MBN");
|
||||
ret->arch = rz_str_dup("arm");
|
||||
ret->machine = rz_str_dup(ret->arch);
|
||||
ret->subsystem = rz_str_dup("mbn");
|
||||
ret->type = rz_str_dup("sbl"); // secondary boot loader
|
||||
ret->bits = bits;
|
||||
ret->has_va = true;
|
||||
ret->has_crypto = true; // must be false if there' no sign or cert sections
|
||||
ret->has_pi = false;
|
||||
ret->has_nx = false;
|
||||
ret->big_endian = false;
|
||||
ret->dbg_info = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ut64 mbn_size(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
return sizeof(SblHeader) + sb->psize;
|
||||
}
|
||||
|
||||
void mbn_destroy_obj(SblHeader *sb) {
|
||||
free(sb);
|
||||
}
|
||||
|
||||
void mbn_destroy(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
mbn_destroy_obj(sb);
|
||||
}
|
||||
|
||||
RzPVector /*<RzBinString *>*/ *mbn_strings(RzBinFile *bf) {
|
||||
RzBinStringSearchOpt opt;
|
||||
rz_bin_string_search_opt_init(&opt);
|
||||
// we only search strings with a minimum length of 10 bytes.
|
||||
opt.mode = RZ_BIN_STRING_SEARCH_MODE_READ_ONLY_SECTIONS;
|
||||
opt.min_length = 10;
|
||||
return rz_bin_file_strings(bf, &opt);
|
||||
}
|
||||
|
||||
void mbn_header_obj(SblHeader *sb, RZ_NONNULL PrintfCallback cb) {
|
||||
rz_return_if_fail(sb && cb);
|
||||
cb("0x%02" PFMTSZx " image_id: %s (0x%" PFMT32x ")\n", offsetof(SblHeader, image_id), rz_mbn_image_id_str(sb->image_id), sb->image_id);
|
||||
cb("0x%02" PFMTSZx " version: 0x%" PFMT32x "\n", offsetof(SblHeader, version), sb->version);
|
||||
cb("0x%02" PFMTSZx " paddr: 0x%" PFMT32x "\n", offsetof(SblHeader, paddr), sb->paddr);
|
||||
cb("0x%02" PFMTSZx " vaddr: 0x%" PFMT32x "\n", offsetof(SblHeader, vaddr), sb->vaddr);
|
||||
cb("0x%02" PFMTSZx " psize: 0x%" PFMT32x "\n", offsetof(SblHeader, psize), sb->psize);
|
||||
cb("0x%02" PFMTSZx " code_pa: 0x%" PFMT32x "\n", offsetof(SblHeader, code_pa), sb->code_pa);
|
||||
cb("0x%02" PFMTSZx " sign_va: 0x%" PFMT32x "\n", offsetof(SblHeader, sign_va), sb->sign_va);
|
||||
cb("0x%02" PFMTSZx " sign_sz: 0x%" PFMT32x "\n", offsetof(SblHeader, sign_sz), sb->sign_sz);
|
||||
cb("0x%02" PFMTSZx " cert_va: 0x%" PFMT32x "\n", offsetof(SblHeader, cert_va), sb->cert_va);
|
||||
cb("0x%02" PFMTSZx " cert_sz: 0x%" PFMT32x "\n", offsetof(SblHeader, cert_sz), sb->cert_sz);
|
||||
}
|
||||
|
||||
void mbn_header(RzBinFile *bf) {
|
||||
rz_return_if_fail(bf && bf->o && bf->o->bin_obj && bf->rbin && bf->rbin->cb_printf);
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
mbn_header_obj(sb, bf->rbin->cb_printf);
|
||||
}
|
||||
156
librz/bin/format/mbn/mbn.h
Normal file
156
librz/bin/format/mbn/mbn.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// SPDX-FileCopyrightText: 2015-2019 pancake <pancake@nopcode.org>
|
||||
// SPDX-FileCopyrightText: 2025 Rot127 <unisono@quyllur.org>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_types.h>
|
||||
#include <rz_util.h>
|
||||
#include <rz_lib.h>
|
||||
#include <rz_bin.h>
|
||||
|
||||
#define mbn_file_get_hdr(bf) ((SblHeader *)bf->o->bin_obj)
|
||||
|
||||
/**
|
||||
* \brief A 40 bytes MBN header for a chain of attestation.
|
||||
* For a more general intro to MBN, see the file comment in mbn.c.
|
||||
*
|
||||
* For firmware attestation scheme details see:
|
||||
* https://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/secure-boot-and-image-authentication-version_final.pdf
|
||||
*/
|
||||
typedef struct sbl_header {
|
||||
ut32 /*<RzMBNImageId>*/ image_id; ///< Identifies the type of image this header represents (OEM SBL, AMSS, Apps boot loader, etc.).
|
||||
ut32 version; ///< Header version
|
||||
ut32 paddr; ///< Offset from the _end of the header_ where the image starts.
|
||||
ut32 vaddr; ///< Memory address it is loaded at.
|
||||
ut32 psize; ///< Size of complete image in bytes.
|
||||
ut32 code_pa; ///< Size of code region in bytes.
|
||||
ut32 sign_va; ///< Memory address to the attestation signature.
|
||||
ut32 sign_sz; ///< Size of the attestation signature in bytes.
|
||||
ut32 cert_va; ///< Memory address to the chain of attestation of this image.
|
||||
ut32 cert_sz; ///< Size of the attestation chain in bytes.
|
||||
} SblHeader;
|
||||
|
||||
/**
|
||||
* \brief Known MBN image IDs.
|
||||
*
|
||||
* Reference:
|
||||
* https://github.com/openpst/libopenpst/blob/master/include/qualcomm/mbn.h
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_MBN_kMbnImageNone = 0x00,
|
||||
RZ_MBN_kMbnImageOemSbl = 0x01,
|
||||
RZ_MBN_kMbnImageAmss = 0x02,
|
||||
RZ_MBN_kMbnImageOcbl = 0x03,
|
||||
RZ_MBN_kMbnImageHash = 0x04,
|
||||
RZ_MBN_kMbnImageAppbl = 0x05,
|
||||
RZ_MBN_kMbnImageApps = 0x06,
|
||||
RZ_MBN_kMbnImageHostDl = 0x07,
|
||||
RZ_MBN_kMbnImageDsp1 = 0x08,
|
||||
RZ_MBN_kMbnImageFsbl = 0x09,
|
||||
RZ_MBN_kMbnImageDbl = 0x0A,
|
||||
RZ_MBN_kMbnImageOsbl = 0x0B,
|
||||
RZ_MBN_kMbnImageDsp2 = 0x0C,
|
||||
RZ_MBN_kMbnImageEhostdl = 0x0D,
|
||||
RZ_MBN_kMbnImageNandprg = 0x0E,
|
||||
RZ_MBN_kMbnImageNorprg = 0x0F,
|
||||
RZ_MBN_kMbnImageRamfs1 = 0x10,
|
||||
RZ_MBN_kMbnImageRamfs2 = 0x11,
|
||||
RZ_MBN_kMbnImageAdspQ5 = 0x12,
|
||||
RZ_MBN_kMbnImageAppsKernel = 0x13,
|
||||
RZ_MBN_kMbnImageBackupRamfs = 0x14,
|
||||
RZ_MBN_kMbnImageSbl1 = 0x15,
|
||||
RZ_MBN_kMbnImageSbl2 = 0x16,
|
||||
RZ_MBN_kMbnImageRpm = 0x17,
|
||||
RZ_MBN_kMbnImageSbl3 = 0x18,
|
||||
RZ_MBN_kMbnImageTz = 0x19,
|
||||
RZ_MBN_kMbnImageSsdKeys = 0x1A,
|
||||
RZ_MBN_kMbnImageGen = 0x1B,
|
||||
RZ_MBN_kMbnImageDsp3 = 0x1C,
|
||||
RZ_MBN_kMbnImageAcdb = 0x1D,
|
||||
RZ_MBN_kMbnImageWdt = 0x1E,
|
||||
RZ_MBN_kMbnImageMba = 0x1F,
|
||||
RZ_MBN_kMbnImageLast = RZ_MBN_kMbnImageMba
|
||||
} RzMBNImageId;
|
||||
|
||||
static inline const char *rz_mbn_image_id_str(RzMBNImageId id) {
|
||||
switch (id) {
|
||||
case RZ_MBN_kMbnImageNone:
|
||||
return "kMbnImageNone";
|
||||
case RZ_MBN_kMbnImageOemSbl:
|
||||
return "kMbnImageOemSbl";
|
||||
case RZ_MBN_kMbnImageAmss:
|
||||
return "kMbnImageAmss";
|
||||
case RZ_MBN_kMbnImageOcbl:
|
||||
return "kMbnImageOcbl";
|
||||
case RZ_MBN_kMbnImageHash:
|
||||
return "kMbnImageHash";
|
||||
case RZ_MBN_kMbnImageAppbl:
|
||||
return "kMbnImageAppbl";
|
||||
case RZ_MBN_kMbnImageApps:
|
||||
return "kMbnImageApps";
|
||||
case RZ_MBN_kMbnImageHostDl:
|
||||
return "kMbnImageHostDl";
|
||||
case RZ_MBN_kMbnImageDsp1:
|
||||
return "kMbnImageDsp1";
|
||||
case RZ_MBN_kMbnImageFsbl:
|
||||
return "kMbnImageFsbl";
|
||||
case RZ_MBN_kMbnImageDbl:
|
||||
return "kMbnImageDbl";
|
||||
case RZ_MBN_kMbnImageOsbl:
|
||||
return "kMbnImageOsbl";
|
||||
case RZ_MBN_kMbnImageDsp2:
|
||||
return "kMbnImageDsp2";
|
||||
case RZ_MBN_kMbnImageEhostdl:
|
||||
return "kMbnImageEhostdl";
|
||||
case RZ_MBN_kMbnImageNandprg:
|
||||
return "kMbnImageNandprg";
|
||||
case RZ_MBN_kMbnImageNorprg:
|
||||
return "kMbnImageNorprg";
|
||||
case RZ_MBN_kMbnImageRamfs1:
|
||||
return "kMbnImageRamfs1";
|
||||
case RZ_MBN_kMbnImageRamfs2:
|
||||
return "kMbnImageRamfs2";
|
||||
case RZ_MBN_kMbnImageAdspQ5:
|
||||
return "kMbnImageAdspQ5";
|
||||
case RZ_MBN_kMbnImageAppsKernel:
|
||||
return "kMbnImageAppsKernel";
|
||||
case RZ_MBN_kMbnImageBackupRamfs:
|
||||
return "kMbnImageBackupRamfs";
|
||||
case RZ_MBN_kMbnImageSbl1:
|
||||
return "kMbnImageSbl1";
|
||||
case RZ_MBN_kMbnImageSbl2:
|
||||
return "kMbnImageSbl2";
|
||||
case RZ_MBN_kMbnImageRpm:
|
||||
return "kMbnImageRpm";
|
||||
case RZ_MBN_kMbnImageSbl3:
|
||||
return "kMbnImageSbl3";
|
||||
case RZ_MBN_kMbnImageTz:
|
||||
return "kMbnImageTz";
|
||||
case RZ_MBN_kMbnImageSsdKeys:
|
||||
return "kMbnImageSsdKeys";
|
||||
case RZ_MBN_kMbnImageGen:
|
||||
return "kMbnImageGen";
|
||||
case RZ_MBN_kMbnImageDsp3:
|
||||
return "kMbnImageDsp3";
|
||||
case RZ_MBN_kMbnImageAcdb:
|
||||
return "kMbnImageAcdb";
|
||||
case RZ_MBN_kMbnImageWdt:
|
||||
return "kMbnImageWdt";
|
||||
case RZ_MBN_kMbnImageMba:
|
||||
return "kMbnImageMba";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
bool mbn_read_sbl_header(RzBuffer *b, SblHeader *sb, ut64 *offset);
|
||||
bool mbn_check_buffer(RzBuffer *b);
|
||||
bool mbn_load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb);
|
||||
ut64 mbn_baddr(RzBinFile *bf);
|
||||
RzPVector /*<RzBinAddr *>*/ *mbn_entries(RzBinFile *bf);
|
||||
RzPVector /*<RzBinSection *>*/ *mbn_sections(RzBinFile *bf);
|
||||
RzBinInfo *mbn_info(RzBinFile *bf);
|
||||
ut64 mbn_size(RzBinFile *bf);
|
||||
void mbn_destroy_obj(SblHeader *sb);
|
||||
void mbn_destroy(RzBinFile *bf);
|
||||
RzPVector /*<RzBinString *>*/ *mbn_strings(RzBinFile *bf);
|
||||
void mbn_header_obj(SblHeader *sb, RZ_NONNULL PrintfCallback cb);
|
||||
void mbn_header(RzBinFile *bf);
|
||||
|
|
@ -215,6 +215,7 @@ rz_bin_sources = [
|
|||
'format/mach0/mach064.c',
|
||||
'format/mach0/mach064_relocs.c',
|
||||
'format/mach0/mach064_chained_fixups.c',
|
||||
'format/mbn/mbn.c',
|
||||
'format/xnu/rz_cf_dict.c',
|
||||
'format/mdmp/mdmp.c',
|
||||
'format/mdmp/mdmp_pe.c',
|
||||
|
|
|
|||
|
|
@ -1,211 +1,24 @@
|
|||
// SPDX-FileCopyrightText: 2015-2019 pancake <pancake@nopcode.org>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_types.h>
|
||||
#include <rz_util.h>
|
||||
#include <rz_lib.h>
|
||||
#include <rz_bin.h>
|
||||
|
||||
#define mbn_file_get_hdr(bf) ((SblHeader *)bf->o->bin_obj)
|
||||
|
||||
typedef struct sbl_header {
|
||||
ut32 load_index;
|
||||
ut32 version; // (flash_partition_version) 3 = nand
|
||||
ut32 paddr; // This + 40 is the start of the code in the file
|
||||
ut32 vaddr; // Where it's loaded in memory
|
||||
ut32 psize; // code_size + signature_size + cert_chain_size
|
||||
ut32 code_pa; // Only what's loaded to memory
|
||||
ut32 sign_va;
|
||||
ut32 sign_sz;
|
||||
ut32 cert_va; // Max of 3 certs?
|
||||
ut32 cert_sz;
|
||||
} SblHeader;
|
||||
|
||||
static bool read_sbl_header(RzBuffer *b, SblHeader *sb, ut64 *offset) {
|
||||
return rz_buf_read_le32_offset(b, offset, &sb->load_index) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->version) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->paddr) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->vaddr) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->psize) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->code_pa) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->sign_va) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->sign_sz) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->cert_va) &&
|
||||
rz_buf_read_le32_offset(b, offset, &sb->cert_sz);
|
||||
}
|
||||
|
||||
static bool check_buffer(RzBuffer *b) {
|
||||
ut64 offset = 0;
|
||||
SblHeader sb = { 0 };
|
||||
rz_return_val_if_fail(b, false);
|
||||
if (!read_sbl_header(b, &sb, &offset)) {
|
||||
return false;
|
||||
}
|
||||
if (sb.version != 3) { // NAND
|
||||
return false;
|
||||
}
|
||||
if (sb.paddr + sizeof(SblHeader) > offset) { // NAND
|
||||
return false;
|
||||
}
|
||||
if (sb.vaddr < 0x100 || sb.psize > offset) { // NAND
|
||||
return false;
|
||||
}
|
||||
if (sb.cert_va < sb.vaddr) {
|
||||
return false;
|
||||
}
|
||||
if (sb.cert_sz >= 0xf0000) {
|
||||
return false;
|
||||
}
|
||||
if (sb.sign_va < sb.vaddr) {
|
||||
return false;
|
||||
}
|
||||
if (sb.sign_sz >= 0xf0000) {
|
||||
return false;
|
||||
}
|
||||
if (sb.load_index < 1 || sb.load_index > 0x40) {
|
||||
return false; // should be 0x19 ?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) {
|
||||
ut64 offset = 0;
|
||||
SblHeader *sb = RZ_NEW0(SblHeader);
|
||||
if (!sb || !read_sbl_header(b, sb, &offset)) {
|
||||
free(sb);
|
||||
return false;
|
||||
}
|
||||
|
||||
obj->bin_obj = sb;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ut64 baddr(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
return sb->vaddr;
|
||||
}
|
||||
|
||||
static RzPVector /*<RzBinAddr *>*/ *entries(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
RzPVector *ret = rz_pvector_new(free);
|
||||
if (ret) {
|
||||
RzBinAddr *ptr = RZ_NEW0(RzBinAddr);
|
||||
if (ptr) {
|
||||
ptr->paddr = 40 + sb->code_pa;
|
||||
ptr->vaddr = 40 + sb->code_pa + sb->vaddr;
|
||||
rz_pvector_push(ret, ptr);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RzPVector /*<RzBinSection *>*/ *sections(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
RzBinSection *ptr = NULL;
|
||||
RzPVector *ret = NULL;
|
||||
if (!(ret = rz_pvector_new(free))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// add text segment
|
||||
if (!(ptr = RZ_NEW0(RzBinSection))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->name = rz_str_dup("text");
|
||||
ptr->size = sb->psize;
|
||||
ptr->vsize = sb->psize;
|
||||
ptr->paddr = sb->paddr + 40;
|
||||
ptr->vaddr = sb->vaddr;
|
||||
ptr->perm = RZ_PERM_RX; // r-x
|
||||
ptr->has_strings = true;
|
||||
rz_pvector_push(ret, ptr);
|
||||
|
||||
if (!(ptr = RZ_NEW0(RzBinSection))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->name = rz_str_dup("sign");
|
||||
ptr->size = sb->sign_sz;
|
||||
ptr->vsize = sb->sign_sz;
|
||||
ptr->paddr = sb->sign_va - sb->vaddr;
|
||||
ptr->vaddr = sb->sign_va;
|
||||
ptr->perm = RZ_PERM_R; // r--
|
||||
ptr->has_strings = true;
|
||||
rz_pvector_push(ret, ptr);
|
||||
|
||||
if (sb->cert_sz && sb->cert_va > sb->vaddr) {
|
||||
if (!(ptr = RZ_NEW0(RzBinSection))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->name = rz_str_dup("cert");
|
||||
ptr->size = sb->cert_sz;
|
||||
ptr->vsize = sb->cert_sz;
|
||||
ptr->paddr = sb->cert_va - sb->vaddr;
|
||||
ptr->vaddr = sb->cert_va;
|
||||
ptr->perm = RZ_PERM_R; // r--
|
||||
ptr->has_strings = true;
|
||||
rz_pvector_push(ret, ptr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RzBinInfo *info(RzBinFile *bf) {
|
||||
RzBinInfo *ret = NULL;
|
||||
const int bits = 16;
|
||||
if (!(ret = RZ_NEW0(RzBinInfo))) {
|
||||
return NULL;
|
||||
}
|
||||
ret->file = rz_str_dup(bf->file);
|
||||
ret->bclass = rz_str_dup("bootloader");
|
||||
ret->rclass = rz_str_dup("mbn");
|
||||
ret->os = rz_str_dup("MBN");
|
||||
ret->arch = rz_str_dup("arm");
|
||||
ret->machine = rz_str_dup(ret->arch);
|
||||
ret->subsystem = rz_str_dup("mbn");
|
||||
ret->type = rz_str_dup("sbl"); // secondary boot loader
|
||||
ret->bits = bits;
|
||||
ret->has_va = true;
|
||||
ret->has_crypto = true; // must be false if there' no sign or cert sections
|
||||
ret->has_pi = false;
|
||||
ret->has_nx = false;
|
||||
ret->big_endian = false;
|
||||
ret->dbg_info = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ut64 size(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
return sizeof(SblHeader) + sb->psize;
|
||||
}
|
||||
|
||||
static void destroy(RzBinFile *bf) {
|
||||
SblHeader *sb = mbn_file_get_hdr(bf);
|
||||
free(sb);
|
||||
}
|
||||
|
||||
static RzPVector /*<RzBinString *>*/ *strings(RzBinFile *bf) {
|
||||
RzBinStringSearchOpt opt;
|
||||
rz_bin_string_search_opt_init(&opt);
|
||||
// we only search strings with a minimum length of 10 bytes.
|
||||
opt.mode = RZ_BIN_STRING_SEARCH_MODE_READ_ONLY_SECTIONS;
|
||||
opt.min_length = 10;
|
||||
return rz_bin_file_strings(bf, &opt);
|
||||
}
|
||||
#include "../format/mbn/mbn.h"
|
||||
|
||||
RzBinPlugin rz_bin_plugin_mbn = {
|
||||
.name = "mbn",
|
||||
.desc = "MBN/SBL bootloader binary",
|
||||
.license = "LGPL3",
|
||||
.author = "pancake",
|
||||
.load_buffer = &load_buffer,
|
||||
.destroy = &destroy,
|
||||
.size = &size,
|
||||
.check_buffer = &check_buffer,
|
||||
.baddr = &baddr,
|
||||
.entries = &entries,
|
||||
.load_buffer = &mbn_load_buffer,
|
||||
.destroy = &mbn_destroy,
|
||||
.header = &mbn_header,
|
||||
.size = &mbn_size,
|
||||
.check_buffer = &mbn_check_buffer,
|
||||
.baddr = &mbn_baddr,
|
||||
.entries = &mbn_entries,
|
||||
.maps = &rz_bin_maps_of_file_sections,
|
||||
.sections = §ions,
|
||||
.strings = &strings,
|
||||
.info = &info,
|
||||
.sections = &mbn_sections,
|
||||
.strings = &mbn_strings,
|
||||
.info = &mbn_info,
|
||||
};
|
||||
|
||||
#ifndef RZ_PLUGIN_INCORE
|
||||
|
|
|
|||
Loading…
Reference in a new issue