Rizin
unix-like reverse engineering framework and cli tools
bin_qnx.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015-2019 deepakchethan <deepakchethan@outlook.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "qnx/qnx.h"
5 #include "../i/private.h"
6 
7 static int lmf_header_load(lmf_header *lmfh, RzBuffer *buf, Sdb *db) {
8  if (rz_buf_size(buf) < sizeof(lmf_header)) {
9  return false;
10  }
11  if (rz_buf_fread_at(buf, QNX_HEADER_ADDR, (ut8 *)lmfh, "iiiiiiiicccciiiicc", 1) < QNX_HDR_SIZE) {
12  return false;
13  }
14  sdb_set(db, "qnx.version", sdb_fmt("0x%xH", lmfh->version), 0);
15  sdb_set(db, "qnx.cflags", sdb_fmt("0x%xH", lmfh->cflags), 0);
16  sdb_set(db, "qnx.cpu", sdb_fmt("0x%xH", lmfh->cpu), 0);
17  sdb_set(db, "qnx.fpu", sdb_fmt("0x%xH", lmfh->fpu), 0);
18  sdb_set(db, "qnx.code_index", sdb_fmt("0x%x", lmfh->code_index), 0);
19  sdb_set(db, "qnx.stack_index", sdb_fmt("0x%x", lmfh->stack_index), 0);
20  sdb_set(db, "qnx.heap_index", sdb_fmt("0x%x", lmfh->heap_index), 0);
21  sdb_set(db, "qnx.argv_index", sdb_fmt("0x%x", lmfh->argv_index), 0);
22  sdb_set(db, "qnx.code_offset", sdb_fmt("0x%x", lmfh->code_offset), 0);
23  sdb_set(db, "qnx.stack_nbytes", sdb_fmt("0x%x", lmfh->stack_nbytes), 0);
24  sdb_set(db, "qnx.heap_nbytes", sdb_fmt("0x%x", lmfh->heap_nbytes), 0);
25  sdb_set(db, "qnx.image_base", sdb_fmt("0x%x", lmfh->image_base), 0);
26  return true;
27 }
28 
29 static bool check_buffer(RzBuffer *buf) {
30  ut8 tmp[6];
31  int r = rz_buf_read_at(buf, 0, tmp, sizeof(tmp));
32  return r == sizeof(tmp) && !memcmp(tmp, QNX_MAGIC, sizeof(tmp));
33 }
34 
35 // Frees the bin_obj of the binary file
36 static void destroy(RzBinFile *bf) {
37  QnxObj *qo = bf->o->bin_obj;
38  rz_list_free(qo->sections);
39  rz_list_free(qo->maps);
40  rz_list_free(qo->fixups);
41  bf->o->bin_obj = NULL;
42  free(qo);
43 }
44 
45 static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
46  lmf_record lrec;
47  lmf_resource lres;
48  lmf_data ldata;
50 
51  QnxObj *qo = RZ_NEW0(QnxObj);
52  if (!qo) {
53  return false;
54  }
55 
58  RzList *fixups = rz_list_newf(free);
59  if (!sections || !maps || !fixups) {
60  goto beach;
61  }
62  qo->kv = sdb_new0();
63  if (!qo->kv) {
64  goto beach;
65  }
66  // Read the first record
67  if (rz_buf_fread_at(bf->buf, 0, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
68  goto beach;
69  }
70  // Load the header
71  lmf_header_load(&qo->lmfh, bf->buf, qo->kv);
72  offset += lrec.data_nbytes;
73 
74  for (;;) {
75  if (rz_buf_fread_at(bf->buf, offset, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
76  goto beach;
77  }
78  offset += sizeof(lmf_record);
79 
80  if (lrec.rec_type == LMF_IMAGE_END_REC) {
81  break;
82  } else if (lrec.rec_type == LMF_RESOURCE_REC) {
83  if (rz_buf_fread_at(bf->buf, offset, (ut8 *)&lres, "ssss", 1) < sizeof(lmf_resource)) {
84  goto beach;
85  }
87  if (!ptr) {
88  goto beach;
89  }
90  ptr->name = strdup("LMF_RESOURCE");
91  ptr->paddr = offset;
92  ptr->vsize = lrec.data_nbytes - sizeof(lmf_resource);
93  ptr->size = ptr->vsize;
95 
97  if (!map) {
98  goto beach;
99  }
100  map->name = ptr->name ? strdup(ptr->name) : NULL;
101  map->paddr = ptr->paddr;
102  map->psize = ptr->size;
103  map->vsize = ptr->vsize;
105  } else if (lrec.rec_type == LMF_LOAD_REC) {
107  if (!ptr) {
108  goto beach;
109  }
110  if (rz_buf_fread_at(bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof(lmf_data)) {
111  free(ptr);
112  goto beach;
113  }
114  ptr->name = strdup("LMF_LOAD");
115  ptr->paddr = offset;
116  ptr->vaddr = ldata.offset;
117  ptr->vsize = lrec.data_nbytes - sizeof(lmf_data);
118  ptr->size = ptr->vsize;
119  rz_list_append(sections, ptr);
120 
122  if (!map) {
123  goto beach;
124  }
125  map->name = ptr->name ? strdup(ptr->name) : NULL;
126  map->paddr = ptr->paddr;
127  map->psize = ptr->size;
128  map->vsize = ptr->vsize;
130  } else if (lrec.rec_type == LMF_FIXUP_REC) {
131  RzBinReloc *ptr = RZ_NEW0(RzBinReloc);
132  if (!ptr || rz_buf_fread_at(bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof(lmf_data)) {
133  free(ptr);
134  goto beach;
135  }
136  ptr->vaddr = ptr->paddr = ldata.offset;
137  ptr->type = 'f'; // "LMF_FIXUP";
138  rz_list_append(fixups, ptr);
139  } else if (lrec.rec_type == LMF_8087_FIXUP_REC) {
140  RzBinReloc *ptr = RZ_NEW0(RzBinReloc);
141  if (!ptr || rz_buf_fread_at(bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof(lmf_data)) {
142  free(ptr);
143  goto beach;
144  }
145  ptr->vaddr = ptr->paddr = ldata.offset;
146  ptr->type = 'F'; // "LMF_8087_FIXUP";
147  rz_list_append(fixups, ptr);
148  } else if (lrec.rec_type == LMF_RW_END_REC) {
149  rz_buf_fread_at(bf->buf, offset, (ut8 *)&qo->rwend, "si", 1);
150  }
151  offset += lrec.data_nbytes;
152  }
153  sdb_ns_set(sdb, "info", qo->kv);
154  qo->sections = sections;
155  qo->maps = maps;
156  qo->fixups = fixups;
157  obj->bin_obj = qo;
158  return true;
159 beach:
160  free(qo);
161  rz_list_free(fixups);
164  return false;
165 }
166 
167 /*
168  * Provides the info about the binary file
169  * @param RzBinFile to extract the data from
170  * @return RzBinInfo file with the info
171  */
172 static RzBinInfo *info(RzBinFile *bf) {
173  rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, NULL);
174  RzBinInfo *ret = RZ_NEW0(RzBinInfo);
175  if (!ret) {
176  return NULL;
177  }
178  ret->file = bf->file ? strdup(bf->file) : NULL;
179  ret->type = strdup("QNX Executable");
180  ret->bclass = strdup("qnx");
181  ret->machine = strdup("i386");
182  ret->rclass = strdup("QNX");
183  ret->arch = strdup("x86");
184  ret->os = strdup("any");
185  ret->subsystem = strdup("any");
186  ret->lang = "C/C++";
187  ret->signature = true;
188  return ret;
189 }
190 
191 static RzList *relocs(RzBinFile *bf) {
192  rz_return_val_if_fail(bf && bf->o, NULL);
193  QnxObj *qo = bf->o->bin_obj;
194  return rz_list_clone(qo->fixups);
195 }
196 
197 static void header(RzBinFile *bf) {
198  rz_return_if_fail(bf && bf->o && bf->rbin);
199  QnxObj *bin = bf->o->bin_obj;
200  RzBin *rbin = bf->rbin;
201  rbin->cb_printf("QNX file header:\n");
202  rbin->cb_printf("version : 0x%xH\n", bin->lmfh.version);
203  rbin->cb_printf("cflags : 0x%xH\n", bin->lmfh.cflags);
204  rbin->cb_printf("cpu : 0x%xH\n", bin->lmfh.cpu);
205  rbin->cb_printf("fpu : 0x%xH\n", bin->lmfh.fpu);
206  rbin->cb_printf("code_index : 0x%xH\n", bin->lmfh.code_index);
207  rbin->cb_printf("stack_index : 0x%xH\n", bin->lmfh.stack_index);
208  rbin->cb_printf("heap_index : 0x%xH\n", bin->lmfh.heap_index);
209  rbin->cb_printf("argv_index : 0x%xH\n", bin->lmfh.argv_index);
210  rbin->cb_printf("spare2[4] : 0x0H\n");
211  rbin->cb_printf("code_offset : 0x%xH\n", bin->lmfh.code_offset);
212  rbin->cb_printf("stack_nbytes : 0x%xH\n", bin->lmfh.stack_nbytes);
213  rbin->cb_printf("heap_nbytes : 0x%xH\n", bin->lmfh.heap_nbytes);
214  rbin->cb_printf("image_base : 0x%xH\n", bin->lmfh.image_base);
215  rbin->cb_printf("spare3[2] : 0x0H\n");
216 }
217 
218 /*
219  * No mention of symbols in the doc
220  */
221 static RzList *symbols(RzBinFile *bf) {
222  return NULL;
223 }
224 
225 static RzList *maps(RzBinFile *bf) {
226  rz_return_val_if_fail(bf && bf->o, NULL);
227  QnxObj *qo = bf->o->bin_obj;
228  return rz_list_clone(qo->maps);
229 }
230 
231 // Returns the sections
232 static RzList *sections(RzBinFile *bf) {
233  rz_return_val_if_fail(bf && bf->o, NULL);
234  QnxObj *qo = bf->o->bin_obj;
235  return rz_list_clone(qo->sections);
236 }
237 
238 /*
239  * Returns the sdb
240  * @param RzBinFile
241  * @return sdb of the bin_obj
242  */
243 static Sdb *get_sdb(RzBinFile *bf) {
244  RzBinObject *o = bf->o;
245  if (!o) {
246  return NULL;
247  }
248  QnxObj *qo = o->bin_obj;
249  return qo ? qo->kv : NULL;
250 }
251 
252 /*
253  * Returns the base address of the image from the binary header
254  * @param RzBinFile
255  * @return image_base address
256  */
257 static ut64 baddr(RzBinFile *bf) {
258  QnxObj *qo = bf->o->bin_obj;
259  return qo ? qo->lmfh.image_base : 0;
260 }
261 
262 /*
263  * Currently both physical and virtual address are set to 0
264  * The memory map has different values for entry
265  */
266 static RzList *entries(RzBinFile *bf) {
267  RzList *ret;
268  RzBinAddr *ptr = NULL;
269  QnxObj *qo = bf->o->bin_obj;
270  if (!(ret = rz_list_new())) {
271  return NULL;
272  }
273  ret->free = free;
274  if (!(ptr = RZ_NEW0(RzBinAddr))) {
275  return ret;
276  }
277  ptr->paddr = qo->lmfh.code_offset;
278  ptr->vaddr = qo->lmfh.code_offset + baddr(bf);
279  rz_list_append(ret, ptr);
280  return ret;
281 }
282 
283 /*
284  * @param RzBinFile
285  * @return signature of the binary
286  */
287 static char *signature(RzBinFile *bf, bool json) {
288  char buf[64];
289  QnxObj *qo = bf->o->bin_obj;
290  if (!qo) {
291  return NULL;
292  }
293  if (json) {
294  PJ *pj = pj_new();
295  pj_n(pj, qo->rwend.signature);
296  return pj_drain(pj);
297  } else {
298  return rz_str_dup(NULL, sdb_itoa(qo->rwend.signature, buf, 10));
299  }
300 }
301 
302 /*
303  * @return: returns the vaddr
304  */
305 static ut64 get_vaddr(RzBinFile *bf, ut64 baddr, ut64 paddr, ut64 vaddr) {
306  return vaddr;
307 }
308 
309 // Declaration of the plugin
311  .name = "qnx",
312  .desc = "QNX executable file support",
313  .license = "LGPL3",
314  .load_buffer = &load_buffer,
315  .destroy = &destroy,
316  .relocs = &relocs,
317  .baddr = &baddr,
318  .author = "deepakchethan",
319  .check_buffer = &check_buffer,
320  .header = &header,
321  .get_sdb = &get_sdb,
322  .entries = &entries,
323  .maps = &maps,
324  .sections = &sections,
325  .symbols = &symbols,
326  .signature = &signature,
327  .get_vaddr = &get_vaddr,
328  .info = &info
329 };
330 
331 #ifndef RZ_PLUGIN_INCORE
334  .data = &rz_bin_plugin_qnx,
336 };
337 #endif
RZ_API void rz_bin_map_free(RzBinMap *map)
Definition: bin.c:1023
RZ_API void rz_bin_section_free(RzBinSection *bs)
Definition: bin.c:1116
static Sdb * get_sdb(RzBinFile *bf)
Definition: bin_qnx.c:243
static char * signature(RzBinFile *bf, bool json)
Definition: bin_qnx.c:287
static bool check_buffer(RzBuffer *buf)
Definition: bin_qnx.c:29
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb)
Definition: bin_qnx.c:45
static RzList * symbols(RzBinFile *bf)
Definition: bin_qnx.c:221
static void header(RzBinFile *bf)
Definition: bin_qnx.c:197
static void destroy(RzBinFile *bf)
Definition: bin_qnx.c:36
RzBinPlugin rz_bin_plugin_qnx
Definition: bin_qnx.c:310
RZ_API RzLibStruct rizin_plugin
Definition: bin_qnx.c:332
static RzBinInfo * info(RzBinFile *bf)
Definition: bin_qnx.c:172
static ut64 baddr(RzBinFile *bf)
Definition: bin_qnx.c:257
static int lmf_header_load(lmf_header *lmfh, RzBuffer *buf, Sdb *db)
Definition: bin_qnx.c:7
static RzList * entries(RzBinFile *bf)
Definition: bin_qnx.c:266
static RzList * maps(RzBinFile *bf)
Definition: bin_qnx.c:225
static RzList * sections(RzBinFile *bf)
Definition: bin_qnx.c:232
static ut64 get_vaddr(RzBinFile *bf, ut64 baddr, ut64 paddr, ut64 vaddr)
Definition: bin_qnx.c:305
static RzList * relocs(RzBinFile *bf)
Definition: bin_qnx.c:191
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
size_t map(int syms, int left, int len)
Definition: enough.c:237
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_OWN RzList * rz_list_clone(RZ_NONNULL const RzList *list)
Shallow copies of the list (but doesn't free its elements)
Definition: list.c:496
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
RZ_API int sdb_ns_set(Sdb *s, const char *name, Sdb *r)
Definition: ns.c:156
@ LMF_LOAD_REC
Definition: qnx.h:17
@ LMF_RESOURCE_REC
Definition: qnx.h:21
@ LMF_FIXUP_REC
Definition: qnx.h:18
@ LMF_RW_END_REC
Definition: qnx.h:22
@ LMF_IMAGE_END_REC
Definition: qnx.h:20
@ LMF_8087_FIXUP_REC
Definition: qnx.h:19
#define QNX_MAGIC
Definition: qnx_specs.h:15
#define QNX_RECORD_SIZE
Definition: qnx_specs.h:17
#define QNX_HEADER_ADDR
Definition: qnx_specs.h:18
#define QNX_HDR_SIZE
Definition: qnx_specs.h:16
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API st64 rz_buf_fread_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL ut8 *buf, RZ_NONNULL const char *fmt, int n)
...
Definition: buf.c:1001
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
@ RZ_LIB_TYPE_BIN
Definition: rz_lib.h:75
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API char * pj_drain(PJ *j)
Definition: pj.c:50
RZ_API PJ * pj_n(PJ *j, ut64 n)
Definition: pj.c:252
RZ_API char * rz_str_dup(char *ptr, const char *string)
Definition: str.c:1021
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_VERSION
Definition: rz_version.h:8
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
RZ_API Sdb * sdb_new0(void)
Definition: sdb.c:43
RZ_API char * sdb_itoa(ut64 n, char *s, int base)
Definition: util.c:38
Definition: malloc.c:26
Definition: rz_pj.h:12
ut64 vaddr
Definition: rz_bin.h:186
ut64 paddr
Definition: rz_bin.h:187
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RzBinObject * o
Definition: rz_bin.h:305
struct rz_bin_t * rbin
Definition: rz_bin.h:316
char * file
Definition: rz_bin.h:299
RzBuffer * buf
Definition: rz_bin.h:303
char * type
Definition: rz_bin.h:211
char * os
Definition: rz_bin.h:219
char * subsystem
Definition: rz_bin.h:220
char * machine
Definition: rz_bin.h:216
const char * lang
Definition: rz_bin.h:224
char * bclass
Definition: rz_bin.h:212
char * file
Definition: rz_bin.h:210
bool signature
Definition: rz_bin.h:239
char * rclass
Definition: rz_bin.h:213
char * arch
Definition: rz_bin.h:214
Description of a single memory mapping into virtual memory from a binary.
Definition: rz_bin.h:602
void * bin_obj
Definition: rz_bin.h:293
char * name
Definition: rz_bin.h:509
char * version
Definition: rz_bin.h:512
ut64 paddr
the paddr where the value should be patched into
Definition: rz_bin.h:717
RzBinRelocType type
Definition: rz_bin.h:712
ut64 vaddr
the vaddr where the value should be patched into
Definition: rz_bin.h:716
char * name
Definition: rz_bin.h:619
PrintfCallback cb_printf
Definition: rz_bin.h:345
RzListFree free
Definition: rz_list.h:21
Definition: sdb.h:63
ut64(WINAPI *w32_GetEnabledXStateFeatures)()