277 lines
6.8 KiB
C
277 lines
6.8 KiB
C
// SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
|
|
// SPDX-FileCopyrightText: 2016-2019 Oscar Salvador <osalvador.vilardaga@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_types.h>
|
|
#include <rz_util.h>
|
|
#include <rz_lib.h>
|
|
#include <rz_bin.h>
|
|
#include <rz_io.h>
|
|
#include "bflt/bflt.h"
|
|
|
|
#define VFILE_NAME_PATCHED "patched"
|
|
|
|
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
|
|
obj->bin_obj = rz_bflt_new_buf(buf, obj->opts.baseaddr, obj->opts.big_endian, obj->opts.patch_relocs);
|
|
return obj->bin_obj;
|
|
}
|
|
|
|
static RzList /*<RzBinAddr *>*/ *entries(RzBinFile *bf) {
|
|
RzBfltObj *obj = bf->o->bin_obj;
|
|
RzList *ret;
|
|
RzBinAddr *ptr;
|
|
|
|
if (!(ret = rz_list_newf(free))) {
|
|
return NULL;
|
|
}
|
|
ptr = rz_bflt_get_entry(obj);
|
|
if (!ptr) {
|
|
rz_list_free(ret);
|
|
return NULL;
|
|
}
|
|
rz_list_append(ret, ptr);
|
|
return ret;
|
|
}
|
|
|
|
static RzPVector /*<RzBinMap *>*/ *maps(RzBinFile *bf) {
|
|
RzBfltObj *obj = bf->o->bin_obj;
|
|
RzPVector *ret = rz_pvector_new((RzPVectorFree)rz_bin_map_free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
|
|
RzBinMap *map = RZ_NEW0(RzBinMap);
|
|
if (!map) {
|
|
rz_pvector_free(ret);
|
|
return NULL;
|
|
}
|
|
map->paddr = 0;
|
|
map->vaddr = rz_bflt_get_text_base(obj);
|
|
map->psize = obj->hdr.data_start;
|
|
map->vsize = obj->hdr.data_start;
|
|
map->perm = RZ_PERM_RWX;
|
|
map->name = strdup("hdr+text");
|
|
map->vfile_name = obj->buf_patched ? strdup(VFILE_NAME_PATCHED) : NULL;
|
|
rz_pvector_push(ret, map);
|
|
|
|
map = RZ_NEW0(RzBinMap);
|
|
if (!map) {
|
|
rz_pvector_free(ret);
|
|
return NULL;
|
|
}
|
|
map->paddr = obj->hdr.data_start;
|
|
map->vaddr = rz_bflt_get_data_base(obj);
|
|
map->psize = obj->hdr.data_end - obj->hdr.data_start;
|
|
map->vsize = rz_bflt_get_data_vsize(obj);
|
|
map->perm = RZ_PERM_RWX;
|
|
map->name = strdup("data+bss");
|
|
map->vfile_name = obj->buf_patched ? strdup(VFILE_NAME_PATCHED) : NULL;
|
|
rz_pvector_push(ret, map);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static RzPVector /*<RzBinSection *>*/ *sections(RzBinFile *bf) {
|
|
RzBfltObj *obj = bf->o->bin_obj;
|
|
RzPVector *ret = rz_pvector_new((RzPVectorFree)rz_bin_section_free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
|
|
// segments
|
|
|
|
RzBinSection *sec = RZ_NEW0(RzBinSection);
|
|
if (!sec) {
|
|
goto beach;
|
|
}
|
|
sec->paddr = 0;
|
|
sec->vaddr = rz_bflt_get_text_base(obj);
|
|
sec->size = obj->hdr.data_start;
|
|
sec->vsize = obj->hdr.data_start;
|
|
sec->perm = RZ_PERM_RWX;
|
|
sec->name = strdup("TEXT");
|
|
sec->is_segment = true;
|
|
rz_pvector_push(ret, sec);
|
|
|
|
sec = RZ_NEW0(RzBinSection);
|
|
if (!sec) {
|
|
goto beach;
|
|
}
|
|
sec->paddr = obj->hdr.data_start;
|
|
sec->vaddr = rz_bflt_get_data_base(obj);
|
|
sec->size = obj->hdr.data_start;
|
|
sec->vsize = rz_bflt_get_data_vsize(obj);
|
|
sec->perm = RZ_PERM_RWX;
|
|
sec->name = strdup("DATA");
|
|
sec->is_segment = true;
|
|
rz_pvector_push(ret, sec);
|
|
|
|
// sections
|
|
|
|
sec = RZ_NEW0(RzBinSection);
|
|
if (!sec) {
|
|
goto beach;
|
|
}
|
|
sec->paddr = 0;
|
|
sec->vaddr = rz_bflt_get_text_base(obj);
|
|
sec->size = BFLT_HDR_SIZE;
|
|
sec->vsize = BFLT_HDR_SIZE;
|
|
sec->perm = RZ_PERM_RWX;
|
|
sec->name = strdup("header");
|
|
rz_pvector_push(ret, sec);
|
|
|
|
sec = RZ_NEW0(RzBinSection);
|
|
if (!sec) {
|
|
goto beach;
|
|
}
|
|
sec->paddr = BFLT_HDR_SIZE;
|
|
sec->vaddr = rz_bflt_get_text_base(obj) + BFLT_HDR_SIZE;
|
|
sec->size = obj->hdr.data_start - BFLT_HDR_SIZE;
|
|
sec->vsize = obj->hdr.data_start - BFLT_HDR_SIZE;
|
|
sec->perm = RZ_PERM_RWX;
|
|
sec->name = strdup("text");
|
|
rz_pvector_push(ret, sec);
|
|
|
|
sec = RZ_NEW0(RzBinSection);
|
|
if (!sec) {
|
|
goto beach;
|
|
}
|
|
sec->paddr = obj->hdr.data_start;
|
|
sec->vaddr = rz_bflt_get_data_base(obj);
|
|
sec->size = obj->hdr.data_end - obj->hdr.data_start;
|
|
sec->vsize = obj->hdr.data_end - obj->hdr.data_start;
|
|
sec->perm = RZ_PERM_RWX;
|
|
sec->name = strdup("data");
|
|
sec->is_data = true;
|
|
rz_pvector_push(ret, sec);
|
|
|
|
sec = RZ_NEW0(RzBinSection);
|
|
if (!sec) {
|
|
goto beach;
|
|
}
|
|
sec->paddr = obj->hdr.data_end;
|
|
sec->vaddr = rz_bflt_get_data_base(obj) + obj->hdr.data_end - obj->hdr.data_start;
|
|
sec->size = 0;
|
|
sec->vsize = obj->hdr.bss_end - obj->hdr.data_end;
|
|
sec->perm = RZ_PERM_RWX;
|
|
sec->name = strdup("bss");
|
|
sec->is_data = true;
|
|
rz_pvector_push(ret, sec);
|
|
|
|
return ret;
|
|
beach:
|
|
rz_pvector_free(ret);
|
|
return NULL;
|
|
}
|
|
|
|
static RzPVector /*<RzBinVirtualFile *>*/ *virtual_files(RzBinFile *bf) {
|
|
RzBfltObj *obj = bf->o->bin_obj;
|
|
RzPVector *r = rz_pvector_new((RzPVectorFree)rz_bin_virtual_file_free);
|
|
if (!r) {
|
|
return NULL;
|
|
}
|
|
if (obj->buf_patched) {
|
|
RzBinVirtualFile *vf = RZ_NEW0(RzBinVirtualFile);
|
|
if (!vf) {
|
|
return r;
|
|
}
|
|
vf->buf = obj->buf_patched;
|
|
vf->name = strdup(VFILE_NAME_PATCHED);
|
|
rz_pvector_push(r, vf);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static void convert_relocs(RzBfltObj *bin, RzPVector /*<RzBinReloc *>*/ *out, RzVector /*<RzBfltReloc>*/ *relocs) {
|
|
RzBfltReloc *br;
|
|
rz_vector_foreach(relocs, br) {
|
|
RzBinReloc *r = RZ_NEW0(RzBinReloc);
|
|
if (!r) {
|
|
return;
|
|
}
|
|
r->type = RZ_BIN_RELOC_32;
|
|
r->paddr = br->reloc_paddr;
|
|
r->vaddr = rz_bflt_paddr_to_vaddr(bin, r->paddr);
|
|
|
|
// 0 preserved, see also patching in bflt.c
|
|
r->target_vaddr = br->value_orig ? rz_bflt_paddr_to_vaddr(bin, br->value_orig) : 0;
|
|
|
|
rz_pvector_push(out, r);
|
|
}
|
|
}
|
|
|
|
static RzPVector /*<RzBinReloc *>*/ *relocs(RzBinFile *bf) {
|
|
RzBfltObj *obj = (RzBfltObj *)bf->o->bin_obj;
|
|
RzPVector *vec = rz_pvector_new((RzPVectorFree)free);
|
|
if (!vec || !obj) {
|
|
rz_pvector_free(vec);
|
|
return NULL;
|
|
}
|
|
convert_relocs(obj, vec, &obj->got_relocs);
|
|
convert_relocs(obj, vec, &obj->relocs);
|
|
return vec;
|
|
}
|
|
|
|
static RzBinInfo *info(RzBinFile *bf) {
|
|
RzBfltObj *obj = NULL;
|
|
RzBinInfo *info = NULL;
|
|
if (!bf || !bf->o || !bf->o->bin_obj) {
|
|
return NULL;
|
|
}
|
|
obj = (RzBfltObj *)bf->o->bin_obj;
|
|
if (!(info = RZ_NEW0(RzBinInfo))) {
|
|
return NULL;
|
|
}
|
|
info->file = bf->file ? strdup(bf->file) : NULL;
|
|
info->rclass = strdup("bflt");
|
|
info->bclass = strdup("bflt");
|
|
info->type = strdup("bFLT (Executable file)");
|
|
info->os = strdup("Linux");
|
|
info->subsystem = strdup("uClinux");
|
|
info->arch = strdup("arm"); // this is a wild guess, the format does not specify any arch, but arm is probably the most popular
|
|
info->big_endian = obj->big_endian;
|
|
info->bits = 32;
|
|
info->has_va = true;
|
|
info->dbg_info = 0;
|
|
info->machine = strdup("unknown");
|
|
info->has_pi = true;
|
|
return info;
|
|
}
|
|
|
|
static bool check_buffer(RzBuffer *buf) {
|
|
ut8 tmp[4];
|
|
int r = rz_buf_read_at(buf, 0, tmp, sizeof(tmp));
|
|
return r == sizeof(tmp) && !memcmp(tmp, "bFLT", 4);
|
|
}
|
|
|
|
static void destroy(RzBinFile *bf) {
|
|
rz_bflt_free(bf->o->bin_obj);
|
|
}
|
|
|
|
static RzPVector /*<RzBinString *>*/ *strings(RzBinFile *bf) {
|
|
return rz_bin_file_strings(bf, bf->minstrlen, false);
|
|
}
|
|
|
|
RzBinPlugin rz_bin_plugin_bflt = {
|
|
.name = "bflt",
|
|
.desc = "bFLT uClinux executable",
|
|
.license = "LGPL3",
|
|
.load_buffer = &load_buffer,
|
|
.destroy = &destroy,
|
|
.check_buffer = &check_buffer,
|
|
.virtual_files = &virtual_files,
|
|
.maps = &maps,
|
|
.entries = &entries,
|
|
.sections = §ions,
|
|
.strings = &strings,
|
|
.info = &info,
|
|
.relocs = &relocs
|
|
};
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_BIN,
|
|
.data = &rz_bin_plugin_bflt,
|
|
.version = RZ_VERSION
|
|
};
|
|
#endif
|