mirror of
https://github.com/radareorg/radare2.git
synced 2025-01-14 17:48:28 +00:00
202 lines
5.0 KiB
C
202 lines
5.0 KiB
C
/* radare2 - LGPL - Copyright 2015-2017 - pancake */
|
|
|
|
#include <r_types.h>
|
|
#include <r_util.h>
|
|
#include <r_lib.h>
|
|
#include <r_bin.h>
|
|
|
|
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;
|
|
} SBLHDR;
|
|
|
|
// TODO avoid globals
|
|
static SBLHDR sb = {0};
|
|
|
|
static bool check_bytes(const ut8 *buf, ut64 bufsz) {
|
|
if (buf && bufsz >= sizeof (SBLHDR)) {
|
|
RBuffer *b = r_buf_new_with_pointers (buf, bufsz);
|
|
int ret = r_buf_fread_at (b, 0, (ut8*)&sb, "10i", 1);
|
|
r_buf_free (b);
|
|
if (!ret) {
|
|
return false;
|
|
}
|
|
if (sb.version != 3) { // NAND
|
|
return false;
|
|
}
|
|
if (sb.paddr + sizeof (SBLHDR) > bufsz) { // NAND
|
|
return false;
|
|
}
|
|
if (sb.vaddr < 0x100 || sb.psize > bufsz) { // 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 ?
|
|
#if 0
|
|
eprintf ("V=%d\n", sb.version);
|
|
eprintf ("PA=0x%08x sz=0x%x\n", sb.paddr, sb.psize);
|
|
eprintf ("VA=0x%08x sz=0x%x\n", sb.vaddr, sb.psize);
|
|
eprintf ("CODE=0x%08x\n", sb.code_pa + sb.vaddr+40);
|
|
eprintf ("SIGN=0x%08x sz=0x%x\n", sb.sign_va, sb.sign_sz);
|
|
if (sb.cert_sz > 0) {
|
|
eprintf ("CERT=0x%08x sz=0x%x\n", sb.cert_va, sb.cert_sz);
|
|
} else {
|
|
eprintf ("No certificate found.\n");
|
|
}
|
|
#endif
|
|
// TODO: Add more checks here
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void * load_bytes(RBinFile *arch, const ut8 *buf, ut64 sz, ut64 loadaddr, Sdb *sdb){
|
|
return (void*)(size_t)check_bytes (buf, sz);
|
|
}
|
|
|
|
static bool load(RBinFile *arch) {
|
|
if (arch && arch->buf) {
|
|
const ut8 *bytes = r_buf_buffer (arch->buf);
|
|
ut64 sz = r_buf_size (arch->buf);
|
|
return load_bytes (arch, bytes, sz, arch->o->loadaddr, arch->sdb) != NULL;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int destroy (RBinFile *arch) {
|
|
return true;
|
|
}
|
|
|
|
static ut64 baddr(RBinFile *arch) {
|
|
return sb.vaddr; // XXX
|
|
}
|
|
|
|
static RList* entries(RBinFile *arch) {
|
|
RList* ret;
|
|
RBinAddr *ptr = NULL;
|
|
|
|
if (!(ret = r_list_new ()))
|
|
return NULL;
|
|
ret->free = free;
|
|
if ((ptr = R_NEW0 (RBinAddr))) {
|
|
ptr->paddr = 40 + sb.code_pa;
|
|
ptr->vaddr = 40 + sb.code_pa + sb.vaddr;
|
|
r_list_append (ret, ptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static RList* sections(RBinFile *arch) {
|
|
RBinSection *ptr = NULL;
|
|
RList *ret = NULL;
|
|
int rc;
|
|
|
|
if (!(ret = r_list_new ()))
|
|
return NULL;
|
|
ret->free = free;
|
|
rc = r_buf_fread_at (arch->buf, 0, (ut8*)&sb, "10i", 1);
|
|
if (!rc) return false;
|
|
|
|
// add text segment
|
|
if (!(ptr = R_NEW0 (RBinSection)))
|
|
return ret;
|
|
strncpy (ptr->name, "text", R_BIN_SIZEOF_STRINGS);
|
|
ptr->size = sb.psize;
|
|
ptr->vsize = sb.psize;
|
|
ptr->paddr = sb.paddr + 40;
|
|
ptr->vaddr = sb.vaddr;
|
|
ptr->srwx = R_BIN_SCN_READABLE | R_BIN_SCN_EXECUTABLE | R_BIN_SCN_MAP; // r-x
|
|
ptr->add = true;
|
|
ptr->has_strings = true;
|
|
r_list_append (ret, ptr);
|
|
|
|
if (!(ptr = R_NEW0 (RBinSection)))
|
|
return ret;
|
|
strncpy (ptr->name, "sign", R_BIN_SIZEOF_STRINGS);
|
|
ptr->size = sb.sign_sz;
|
|
ptr->vsize = sb.sign_sz;
|
|
ptr->paddr = sb.sign_va - sb.vaddr;
|
|
ptr->vaddr = sb.sign_va;
|
|
ptr->srwx = R_BIN_SCN_READABLE | R_BIN_SCN_MAP; // r--
|
|
ptr->has_strings = true;
|
|
ptr->add = true;
|
|
r_list_append (ret, ptr);
|
|
|
|
if (sb.cert_sz && sb.cert_va > sb.vaddr) {
|
|
if (!(ptr = R_NEW0 (RBinSection)))
|
|
return ret;
|
|
strncpy (ptr->name, "cert", R_BIN_SIZEOF_STRINGS);
|
|
ptr->size = sb.cert_sz;
|
|
ptr->vsize = sb.cert_sz;
|
|
ptr->paddr = sb.cert_va - sb.vaddr;
|
|
ptr->vaddr = sb.cert_va;
|
|
ptr->srwx = R_BIN_SCN_READABLE | R_BIN_SCN_MAP; // r--
|
|
ptr->has_strings = true;
|
|
ptr->add = true;
|
|
r_list_append (ret, ptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static RBinInfo* info(RBinFile *arch) {
|
|
RBinInfo *ret = NULL;
|
|
const int bits = 16;
|
|
if (!(ret = R_NEW0 (RBinInfo)))
|
|
return NULL;
|
|
ret->file = strdup (arch->file);
|
|
ret->bclass = strdup ("bootloader");
|
|
ret->rclass = strdup ("mbn");
|
|
ret->os = strdup ("MBN");
|
|
ret->arch = strdup ("arm");
|
|
ret->machine = strdup (ret->arch);
|
|
ret->subsystem = strdup ("mbn");
|
|
ret->type = strdup ("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(RBinFile *arch) {
|
|
return sizeof (SBLHDR) + sb.psize;
|
|
}
|
|
|
|
RBinPlugin r_bin_plugin_mbn = {
|
|
.name = "mbn",
|
|
.desc = "MBN/SBL bootloader things",
|
|
.license = "LGPL3",
|
|
.minstrlen = 10,
|
|
.load = &load,
|
|
.load_bytes = &load_bytes,
|
|
.size = &size,
|
|
.destroy = &destroy,
|
|
.check_bytes = &check_bytes,
|
|
.baddr = &baddr,
|
|
.entries = &entries,
|
|
.sections = §ions,
|
|
.info = &info,
|
|
};
|
|
|
|
#ifndef CORELIB
|
|
RLibStruct radare_plugin = {
|
|
.type = R_LIB_TYPE_BIN,
|
|
.data = &r_bin_plugin_mbn,
|
|
.version = R2_VERSION
|
|
};
|
|
#endif
|