Add initial support for QNX executables ##bin

This commit is contained in:
Deepak Chethan 2019-03-06 00:57:44 +05:30 committed by radare
parent e0b1d7a525
commit 68001dc8f8
8 changed files with 445 additions and 2 deletions

View File

@ -50,7 +50,7 @@ MCORE, mcs96, RSP, SuperH-4, VAX.
ELF, Mach-O, Fatmach-O, PE, PE+, MZ, COFF, OMF, TE, XBE, BIOS/UEFI,
Dyldcache, DEX, ART, CGC, Java class, Android boot image, Plan9 executable,
ZIMG, MBN/SBL bootloader, ELF coredump, MDMP (Windows minidump),
WASM (WebAssembly binary), Commodore VICE emulator,
WASM (WebAssembly binary), Commodore VICE emulator, QNX,
Game Boy (Advance), Nintendo DS ROMs and Nintendo 3DS FIRMs, various filesystems.
## Operating Systems

88
libr/bin/format/qnx/qnx.h Normal file
View File

@ -0,0 +1,88 @@
/* radare - LGPL - 2019 - deepakchethan */
#ifndef _QNX_H
#define _QNX_H
#include "qnx_specs.h"
#include <r_util.h>
#include <r_lib.h>
#include <r_types.h>
#include <r_bin.h>
enum {
LMF_HEADER_REC = 0,
LMF_COMMENT_REC,
LMF_LOAD_REC,
LMF_FIXUP_REC,
LMF_8087_FIXUP_REC,
LMF_IMAGE_END_REC,
LMF_RESOURCE_REC,
LMF_RW_END_REC,
LMF_LINEAR_FIXUP_REC
};
R_PACKED (
typedef struct lmf_record {
ut8 rec_type;
ut8 reserved; // must be 0
ut16 data_nbytes; // size of the data record after this.
ut16 spare; // must be 0
}) lmf_record;
R_PACKED (
typedef struct lmf_data {
ut16 segment;
ut32 offset;
}) lmf_data;
R_PACKED (
typedef struct lmf_header {
ut16 version;
ut16 cflags;
ut16 cpu; // 86,186,286,386,486
ut16 fpu; // 0, 87,287,387
ut16 code_index; // segment of code start;
ut16 stack_index; // segment to put the stack
ut16 heap_index; // segment to start DS at.
ut16 argv_index; // segment to put argv & environment.
ut16 spare2[4]; // must be zero;
ut32 code_offset; // starting offset of code.
ut32 stack_nbytes; // stack size
ut32 heap_nbytes; // initial size of heap (optional).
ut32 image_base; // starting address of image
ut32 spare3[2];
}) lmf_header;
R_PACKED (
typedef struct lmf_eof {
ut8 spare[6];
}) lmf_eof;
/* values for the res_type field in the lmf_resource structure */
enum {
RES_USAGE = 0
};
R_PACKED (
typedef struct lmf_resource {
ut16 res_type;
ut16 spare[3];
}) lmf_resource;
R_PACKED (
typedef struct lmf_rw_end {
ut16 verify;
ut32 signature;
}) lmf_rw_end;
R_PACKED (
typedef struct {
Sdb *kv;
lmf_header lmfh;
RList* fixups;
RList* sections;
lmf_rw_end rwend;
}) QnxObj;
#endif

View File

@ -0,0 +1,27 @@
#ifndef QNX_SPECS_H_
#define QNX_SPECS_H_
#define QNX_VERSION 400
#define VERIFY_OFFSET 36
#define QNX_MAX_REC_SIZE (0x8000 - 512) // was 0xFFFF
#define QNX_MAX_DATA_SIZE (QNX_MAX_REC_SIZE - sizeof(lmf_data))
#define VERIFY_END (VERIFY_OFFSET + sizeof(RWEndRec.verify))
#define QNX_MAX_FIXUPS (0x8000 - 512)
#define QNX_MAGIC "\x00\x00\x38\x00\x00\x00"
#define QNX_HDR_SIZE sizeof (lmf_header)
#define QNX_RECORD_SIZE sizeof (lmf_record)
#define QNX_HEADER_ADDR sizeof (lmf_record)
#define _TCF_LONG_LIVED 0x0001
#define _TCF_32BIT 0x0002
#define _TCF_PRIV_MASK 0x000c
#define _TCF_FLAT 0x0010
#define SEG16_CODE_FIXUP 0x0004
#define LINEAR32_CODE_FIXUP 0x80000000
#define LINEAR32_SELF_RELATIVE_FIXUP 0x40000000
#endif

View File

@ -22,7 +22,7 @@ FORMATS+=bios.mk mach064.mk dyldcache.mk java.mk
FORMATS+=dex.mk fs.mk ningb.mk coff.mk ningba.mk xbe.mk zimg.mk
FORMATS+=omf.mk cgc.mk dol.mk nes.mk mbn.mk psxexe.mk spc700.mk
FORMATS+=vsf.mk nin3ds.mk bflt.mk wasm.mk sfc.mk
FORMATS+=mdmp.mk z64.mk
FORMATS+=mdmp.mk z64.mk qnx.mk
FORMATS+=xtr_dyldcache.mk
FORMATS+=xtr_fatmach0.mk

315
libr/bin/p/bin_qnx.c Normal file
View File

@ -0,0 +1,315 @@
/* radare2 - LGPL3 - 2015-2019 - deepakchethan */
#include "qnx/qnx.h"
static int lmf_header_load(lmf_header *lmfh, RBuffer *buf, Sdb *db) {
if (r_buf_size (buf) < sizeof (lmf_header)) {
return false;
}
if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) < QNX_HDR_SIZE) {
return false;
}
sdb_set (db, "qnx.version", sdb_fmt ("0x%xH", lmfh->version), 0);
sdb_set (db, "qnx.cflags", sdb_fmt ("0x%xH", lmfh->cflags), 0);
sdb_set (db, "qnx.cpu", sdb_fmt ("0x%xH", lmfh->cpu), 0);
sdb_set (db, "qnx.fpu", sdb_fmt ("0x%xH", lmfh->fpu), 0);
sdb_set (db, "qnx.code_index", sdb_fmt ("0x%x", lmfh->code_index), 0);
sdb_set (db, "qnx.stack_index", sdb_fmt ("0x%x", lmfh->stack_index), 0);
sdb_set (db, "qnx.heap_index", sdb_fmt ("0x%x", lmfh->heap_index), 0);
sdb_set (db, "qnx.argv_index", sdb_fmt ("0x%x", lmfh->argv_index), 0);
sdb_set (db, "qnx.code_offset", sdb_fmt ("0x%x", lmfh->code_offset), 0);
sdb_set (db, "qnx.stack_nbytes", sdb_fmt ("0x%x", lmfh->stack_nbytes), 0);
sdb_set (db, "qnx.heap_nbytes", sdb_fmt ("0x%x", lmfh->heap_nbytes), 0);
sdb_set (db, "qnx.image_base", sdb_fmt ("0x%x", lmfh->image_base), 0);
return true;
}
/*
* Verifies the magic of the binary file
* @param buffer and length of signature
* @return bool outcome of the verification
*/
static bool check_bytes(const ut8 *buf, ut64 length) {
if (!buf || length < 6) {
return false;
}
return (!memcmp (buf, QNX_MAGIC, 6));
}
// Frees the bin_obj of the binary file
static int destroy(RBinFile *bf) {
QnxObj *qo = bf->o->bin_obj;
r_list_free (qo->sections);
r_list_free (qo->fixups);
bf->o->bin_obj = NULL;
free (qo);
return true;
}
/*
* Method that loads the binary file into bin_obj
*/
static bool load_bytes(RBinFile *bf, void **bin_obj, const ut8 *buf, ut64 sz, ut64 loadaddr, Sdb *sdb){
QnxObj *qo = R_NEW0 (QnxObj);
lmf_record *lrec = R_NEW0 (lmf_record);
lmf_resource *lres = R_NEW0 (lmf_resource);
lmf_data *ldata = R_NEW0 (lmf_data);
ut64 offset = QNX_RECORD_SIZE;
RList *sections = NULL;
RList *fixups = NULL;
if (!qo) {
return false;
}
if (!(sections = r_list_new ()) || !(fixups = r_list_new ())) {
return false;
}
qo->kv = sdb_new0 ();
if (!qo->kv) {
free (qo);
return false;
}
// Read the first record
if (r_buf_fread_at (bf->buf, 0, (ut8 *) lrec, "iiii", 1) < QNX_RECORD_SIZE) {
return false;
}
// Load the header
lmf_header_load (&qo->lmfh, bf->buf, qo->kv);
offset += lrec->data_nbytes;
for( ;; ) {
if (r_buf_fread_at (bf->buf, offset, (ut8 *) lrec, "iiii", 1) < QNX_RECORD_SIZE) {
return false;
}
offset += sizeof (lmf_record);
if (lrec->rec_type == LMF_IMAGE_END_REC) {
break;
} else if (lrec->rec_type == LMF_RESOURCE_REC) {
RBinSection *ptr = R_NEW0 (RBinSection);
if (r_buf_fread_at (bf->buf, offset, (ut8 *) lres, "iccc", 1) < sizeof (lmf_resource)) {
return false;
}
if (!ptr) {
return false;
}
ptr->name = strdup ("LMF_RESOURCE");
ptr->paddr = offset;
ptr->vsize = lrec->data_nbytes - sizeof (lmf_resource);
ptr->size = ptr->vsize;
ptr->add = true;
r_list_append (sections, ptr);
} else if (lrec->rec_type == LMF_LOAD_REC) {
RBinSection *ptr = R_NEW0 (RBinSection);
if (r_buf_fread_at (bf->buf, offset, (ut8 *) ldata, "ii", 1) < sizeof (lmf_data)) {
return false;
}
if (!ptr) {
return false;
}
ptr->name = strdup ("LMF_LOAD");
ptr->paddr = offset;
ptr->vaddr = ldata->offset;
ptr->vsize = lrec->data_nbytes - sizeof (lmf_data);
ptr->size = ptr->vsize;
ptr->add = true;
r_list_append (sections, ptr);
} else if (lrec->rec_type == LMF_FIXUP_REC) {
RBinReloc *ptr = R_NEW0(RBinReloc);
if (r_buf_fread_at (bf->buf, offset, (ut8 *) ldata, "ii", 1) < sizeof (lmf_data)) {
return false;
}
if (!ptr) {
return false;
}
ptr->vaddr = ptr->paddr = ldata->offset;
ptr->type = "LMF_FIXUP";
r_list_append (fixups, ptr);
} else if (lrec->rec_type == LMF_8087_FIXUP_REC) {
RBinReloc *ptr = R_NEW0(RBinReloc);
if (r_buf_fread_at (bf->buf, offset, (ut8 *) ldata, "ii", 1) < sizeof (lmf_data)) {
return false;
}
if (!ptr) {
return false;
}
ptr->vaddr = ptr->paddr = ldata->offset;
ptr->type = "LMF_8087_FIXUP";
r_list_append (fixups, ptr);
} else if (lrec->rec_type == LMF_RW_END_REC) {
r_buf_fread_at (bf->buf, offset, (ut8 *) &qo->rwend, "ii", 1);
}
offset += lrec->data_nbytes;
}
sdb_ns_set (sdb, "info", qo->kv);
qo->sections = sections;
qo->fixups = fixups;
*bin_obj = qo;
free (lrec);
free (lres);
free (ldata);
return true;
}
static bool load(RBinFile *bf) {
r_return_val_if_fail (bf && bf->o, false);
ut64 size = bf? r_buf_size (bf->buf): 0;
const ut8 *byte = bf? r_buf_get_at (bf->buf, 0, NULL): NULL;
return load_bytes (bf, &bf->o->bin_obj, bf->buf, size, bf->o->loadaddr, bf->sdb);
}
/*
* Provides the info about the binary file
* @param RBinFile to extract the data from
* @return RBinInfo file with the info
*/
static RBinInfo *info(RBinFile *bf) {
r_return_val_if_fail (bf && bf->o && bf->o->bin_obj, NULL);
RBinInfo *ret = R_NEW0 (RBinInfo);
if (!ret) {
return NULL;
}
ret->file = bf->file? strdup (bf->file): NULL;
ret->type = strdup ("QNX Executable");
ret->bclass = strdup ("qnx");
ret->machine = strdup ("i386");
ret->rclass = strdup ("QNX");
ret->arch = strdup ("x86");
ret->os = strdup ("any");
ret->subsystem = strdup ("any");
ret->lang = strdup ("C/C++");
ret->signature = true;
return ret;
}
static RList *relocs(RBinFile *bf) {
r_return_val_if_fail (bf && bf->o, NULL);
QnxObj *qo = bf->o->bin_obj;
return r_list_clone (qo->fixups);
}
static void header(RBinFile *bf) {
r_return_if_fail (bf && bf->o && bf->rbin);
QnxObj *bin = bf->o->bin_obj;
RBin *rbin = bf->rbin;
rbin->cb_printf ("QNX file header:\n");
rbin->cb_printf ("version : 0x%xH\n", bin->lmfh.version);
rbin->cb_printf ("cflags : 0x%xH\n", bin->lmfh.cflags);
rbin->cb_printf ("cpu : 0x%xH\n", bin->lmfh.cpu);
rbin->cb_printf ("fpu : 0x%xH\n", bin->lmfh.fpu);
rbin->cb_printf ("code_index : 0x%xH\n", bin->lmfh.code_index);
rbin->cb_printf ("stack_index : 0x%xH\n", bin->lmfh.stack_index);
rbin->cb_printf ("heap_index : 0x%xH\n", bin->lmfh.heap_index);
rbin->cb_printf ("argv_index : 0x%xH\n", bin->lmfh.argv_index);
rbin->cb_printf ("spare2[4] : 0x0H\n", bin->lmfh.spare2);
rbin->cb_printf ("code_offset : 0x%xH\n", bin->lmfh.code_offset);
rbin->cb_printf ("stack_nbytes : 0x%xH\n", bin->lmfh.stack_nbytes);
rbin->cb_printf ("heap_nbytes : 0x%xH\n", bin->lmfh.heap_nbytes);
rbin->cb_printf ("image_base : 0x%xH\n", bin->lmfh.image_base);
rbin->cb_printf ("spare3[2] : 0x0H\n");
}
/*
* No mention of symbols in the doc
*/
static RList* symbols(RBinFile *bf) {
return NULL;
}
// Returns the sections
static RList* sections(RBinFile *bf) {
r_return_val_if_fail (bf && bf->o, NULL);
QnxObj *qo = bf->o->bin_obj;
return r_list_clone (qo->sections);
}
/*
* Returns the sdb
* @param RBinFile
* @return sdb of the bin_obj
*/
static Sdb *get_sdb(RBinFile *bf) {
RBinObject *o = bf->o;
if (!o) {
return NULL;
}
QnxObj *qo = o->bin_obj;
return qo? qo->kv: NULL;
}
/*
* Returns the base address of the image from the binary header
* @param RBinFile
* @return image_base address
*/
static ut64 baddr(RBinFile *bf) {
QnxObj *qo = bf->o->bin_obj;
return qo? qo->lmfh.image_base: 0;
}
/*
* Currently both physical and virtual address are set to 0
* The memory map has different values for entry
*/
static RList* entries(RBinFile *bf) {
RList *ret;
RBinAddr *ptr = NULL;
QnxObj *qo = bf->o->bin_obj;
if (!(ret = r_list_new ())) {
return NULL;
}
ret->free = free;
if (!(ptr = R_NEW0 (RBinAddr))) {
return ret;
}
ptr->paddr = qo->lmfh.code_offset;
ptr->vaddr = qo->lmfh.code_offset + baddr (bf);
r_list_append (ret, ptr);
return ret;
}
/*
* @param RBinFile
* @return signature of the binary
*/
static char *signature(RBinFile *bf, bool json) {
char buf[64];
QnxObj *qo = bf->o->bin_obj;
return qo? r_str_dup (NULL, sdb_itoa (qo->rwend.signature, buf, 10)): NULL;
}
/*
* @return: returns the vaddr
*/
static ut64 get_vaddr(RBinFile *bf, ut64 baddr, ut64 paddr, ut64 vaddr) {
return vaddr;
}
// Declaration of the plugin
RBinPlugin r_bin_plugin_qnx = {
.name = "qnx",
.desc = "QNX executable file support",
.license = "LGPL3",
.load = &load,
.load_bytes = &load_bytes,
.destroy = &destroy,
.relocs = &relocs,
.baddr = &baddr,
.author = "deepakchethan",
.check_bytes = &check_bytes,
.header = &header,
.get_sdb = &get_sdb,
.entries = &entries,
.sections = &sections,
.symbols = &symbols,
.signature = &signature,
.get_vaddr = &get_vaddr,
.info = &info
};
#ifndef CORELIB
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_BIN,
.data = &r_bin_plugin_qnx,
.version = R2_VERSION
};
#endif

11
libr/bin/p/qnx.mk Normal file
View File

@ -0,0 +1,11 @@
OBJ_QNX+=bin_qnx.o
STATIC_OBJ+=${OBJ_QNX}
TARGET_QNX=bin_qnx.${EXT_SO}
ALL_TARGETS+=${TARGET_QNX}
${TARGET_QNX}: ${OBJ_QNX}
${CC} $(call libname,bin_qnx) -shared ${CFLAGS} \
-o ${TARGET_QNX} $(LINK) $(LDFLAGS)

View File

@ -788,6 +788,7 @@ extern RBinPlugin r_bin_plugin_art;
extern RBinPlugin r_bin_plugin_bootimg;
extern RBinPlugin r_bin_plugin_dol;
extern RBinPlugin r_bin_plugin_nes;
extern RBinPlugin r_bin_plugin_qnx;
extern RBinPlugin r_bin_plugin_mbn;
extern RBinPlugin r_bin_plugin_smd;
extern RBinPlugin r_bin_plugin_sms;

View File

@ -135,6 +135,7 @@ bin.mbn
bin.mdmp
bin.mz
bin.nes
bin.qnx
bin.nin3ds
bin.ninds
bin.ningb