mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-23 21:29:49 +00:00
Add initial support for QNX executables ##bin
This commit is contained in:
parent
e0b1d7a525
commit
68001dc8f8
@ -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
88
libr/bin/format/qnx/qnx.h
Normal 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
|
27
libr/bin/format/qnx/qnx_specs.h
Normal file
27
libr/bin/format/qnx/qnx_specs.h
Normal 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
|
@ -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
315
libr/bin/p/bin_qnx.c
Normal 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 = §ions,
|
||||
.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
11
libr/bin/p/qnx.mk
Normal 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)
|
@ -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;
|
||||
|
@ -135,6 +135,7 @@ bin.mbn
|
||||
bin.mdmp
|
||||
bin.mz
|
||||
bin.nes
|
||||
bin.qnx
|
||||
bin.nin3ds
|
||||
bin.ninds
|
||||
bin.ningb
|
||||
|
Loading…
Reference in New Issue
Block a user