Rizin
unix-like reverse engineering framework and cli tools
bin_nro.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2017-2019 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 // TODO: Support NRR and MODF
5 #include <rz_types.h>
6 #include <rz_util.h>
7 #include <rz_lib.h>
8 #include <rz_bin.h>
9 #include "nxo/nxo.h"
10 
11 #define NRO_OFF(x) (sizeof(NXOStart) + rz_offsetof(NROHeader, x))
12 #define NRO_OFFSET_MODMEMOFF rz_offsetof(NXOStart, mod_memoffset)
13 
14 // starting at 0x10 (16th byte)
15 typedef struct {
16  ut32 magic; // NRO0
17  ut32 unknown; // 4
18  ut32 size; // 8
19  ut32 unknown2; // 12
21  ut32 text_size; // 20
23  ut32 ro_size; // 28
25  ut32 data_size; // 36
26  ut32 bss_size; // 40
28 } NROHeader;
29 
30 static ut64 baddr(RzBinFile *bf) {
31  if (!bf) {
32  return 0;
33  }
34 
35  ut32 result;
36  if (!rz_buf_read_le32_at(bf->buf, NRO_OFFSET_MODMEMOFF, &result)) {
37  return 0;
38  }
39 
40  return result;
41 }
42 
43 static bool check_buffer(RzBuffer *b) {
44  ut8 magic[4];
45  if (rz_buf_read_at(b, NRO_OFF(magic), magic, sizeof(magic)) == 4) {
46  return fileType(magic) != NULL;
47  }
48  return false;
49 }
50 
51 static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) {
52  ut32 mod0;
54  return false;
55  }
56 
57  // XX bf->buf vs b :D this load_b
59  if (!bin) {
60  return false;
61  }
62 
63  ut64 ba = baddr(bf);
66  bin->classes_list = rz_list_newf((RzListFree)free);
67  parseMod(b, bin, mod0, ba);
68  obj->bin_obj = bin;
69 
70  return true;
71 }
72 
74  return NULL; // TODO
75 }
76 
77 static RzList *entries(RzBinFile *bf) {
78  RzList *ret;
79  RzBinAddr *ptr = NULL;
80  if (!(ret = rz_list_new())) {
81  return NULL;
82  }
83  ret->free = free;
84  if ((ptr = RZ_NEW0(RzBinAddr))) {
85  ptr->paddr = 0x80;
86  ptr->vaddr = ptr->paddr + baddr(bf);
87  rz_list_append(ret, ptr);
88  }
89  return ret;
90 }
91 
92 static Sdb *get_sdb(RzBinFile *bf) {
93  Sdb *kv = sdb_new0();
94  sdb_num_set(kv, "nro_start.offset", 0, 0);
95  sdb_num_set(kv, "nro_start.size", 16, 0);
96  sdb_set(kv, "nro_start.format", "xxq unused mod_memoffset padding", 0);
97  sdb_num_set(kv, "nro_header.offset", 16, 0);
98  sdb_num_set(kv, "nro_header.size", 0x70, 0);
99  sdb_set(kv, "nro_header.format", "xxxxxxxxxxxx magic unk size unk2 text_offset text_size ro_offset ro_size data_offset data_size bss_size unk3", 0);
100  sdb_ns_set(bf->sdb, "info", kv);
101  return kv;
102 }
103 
104 static RzList *maps(RzBinFile *bf) {
105  RzBuffer *b = bf->buf;
107  if (!ret) {
108  return NULL;
109  }
110 
111  ut64 ba = baddr(bf);
112  ut64 bufsz = rz_buf_size(bf->buf);
113 
114  ut32 sig0;
115  if (!rz_buf_read_le32_at(bf->buf, 0x18, &sig0)) {
116  rz_list_free(ret);
117  return NULL;
118  }
119 
120  RzBinMap *map = NULL;
121  if (sig0 && sig0 + 8 < bufsz) {
122  map = RZ_NEW0(RzBinMap);
123  if (!map) {
124  return ret;
125  }
126 
127  ut32 sig0sz;
128  if (!rz_buf_read_le32_at(bf->buf, sig0 + 4, &sig0sz)) {
129  rz_list_free(ret);
130  ret = NULL;
131  goto maps_err;
132  }
133 
134  map->name = strdup("sig0");
135  map->paddr = sig0;
136  map->psize = sig0sz;
137  map->vsize = sig0sz;
138  map->vaddr = sig0 + ba;
139  map->perm = RZ_PERM_R;
140  rz_list_append(ret, map);
141  } else {
142  RZ_LOG_ERROR("Invalid SIG0 address\n");
143  }
144 
145  // add text segment
146  if (!(map = RZ_NEW0(RzBinMap))) {
147  return ret;
148  }
149  map->name = strdup("text");
150  ut32 tmp;
151  if (!rz_buf_read_le32_at(b, NRO_OFF(text_memoffset), &tmp)) {
152  goto maps_err;
153  }
154  map->paddr = tmp;
155 
156  if (!rz_buf_read_le32_at(b, NRO_OFF(text_size), &tmp)) {
157  goto maps_err;
158  }
159  map->psize = tmp;
160 
161  map->vsize = map->psize;
162  map->vaddr = map->paddr + ba;
163  map->perm = RZ_PERM_RX;
164  rz_list_append(ret, map);
165 
166  // add ro segment
167  if (!(map = RZ_NEW0(RzBinMap))) {
168  return ret;
169  }
170  map->name = strdup("ro");
171  if (!rz_buf_read_le32_at(b, NRO_OFF(ro_memoffset), &tmp)) {
172  goto maps_err;
173  }
174  map->paddr = tmp;
175 
176  if (!rz_buf_read_le32_at(b, NRO_OFF(ro_size), &tmp)) {
177  goto maps_err;
178  }
179  map->psize = tmp;
180 
181  map->vsize = map->psize;
182  map->vaddr = map->paddr + ba;
183  map->perm = RZ_PERM_R;
184  rz_list_append(ret, map);
185 
186  // add data segment
187  if (!(map = RZ_NEW0(RzBinMap))) {
188  return ret;
189  }
190  map->name = strdup("data");
191  if (!rz_buf_read_le32_at(b, NRO_OFF(data_memoffset), &tmp)) {
192  goto maps_err;
193  }
194  map->paddr = tmp;
195 
196  if (!rz_buf_read_le32_at(b, NRO_OFF(data_size), &tmp)) {
197  goto maps_err;
198  }
199  map->psize = tmp;
200 
201  map->vsize = map->psize;
202  map->vaddr = map->paddr + ba;
203  map->perm = RZ_PERM_RW;
204  rz_list_append(ret, map);
205  return ret;
206 
207 maps_err:
208  free(map);
209  return ret;
210 }
211 
212 static RzList *sections(RzBinFile *bf) {
213  RzList *ret = NULL;
214  RzBinSection *ptr = NULL;
216  return NULL;
217  }
218 
219  ut64 ba = baddr(bf);
220 
221  if (!(ptr = RZ_NEW0(RzBinSection))) {
222  return ret;
223  }
224  ptr->name = strdup("header");
225  ptr->size = 0x80;
226  ptr->vsize = 0x80;
227  ptr->paddr = 0;
228  ptr->vaddr = 0;
229  ptr->perm = RZ_PERM_R;
230  rz_list_append(ret, ptr);
231 
232  int bufsz = rz_buf_size(bf->buf);
233 
234  ut32 mod0;
235  if (!rz_buf_read_le32_at(bf->buf, NRO_OFFSET_MODMEMOFF, &mod0)) {
236  free(ret);
237  return NULL;
238  }
239 
240  if (mod0 && mod0 + 8 < bufsz) {
241  if (!(ptr = RZ_NEW0(RzBinSection))) {
242  return ret;
243  }
244  ut32 mod0sz;
245  if (!rz_buf_read_le32_at(bf->buf, mod0 + 4, &mod0sz)) {
246  free(ret);
247  return NULL;
248  }
249  ptr->name = strdup("mod0");
250  ptr->size = mod0sz;
251  ptr->vsize = mod0sz;
252  ptr->paddr = mod0;
253  ptr->vaddr = mod0 + ba;
254  ptr->perm = RZ_PERM_R; // rw-
255  rz_list_append(ret, ptr);
256  } else {
257  RZ_LOG_ERROR("Invalid MOD0 address\n");
258  }
259 
260  RzList *mappies = maps(bf);
261  if (mappies) {
262  RzList *msecs = rz_bin_sections_of_maps(mappies);
263  if (msecs) {
264  rz_list_join(ret, msecs);
265  rz_list_free(msecs);
266  }
267  rz_list_free(mappies);
268  }
269  return ret;
270 }
271 
272 static RzList *symbols(RzBinFile *bf) {
273  RzBinNXOObj *bin;
274  if (!bf || !bf->o || !bf->o->bin_obj) {
275  return NULL;
276  }
277  bin = (RzBinNXOObj *)bf->o->bin_obj;
278  return bin->methods_list;
279 }
280 
281 static RzList *imports(RzBinFile *bf) {
282  RzBinNXOObj *bin;
283  if (!bf || !bf->o || !bf->o->bin_obj) {
284  return NULL;
285  }
286  bin = (RzBinNXOObj *)bf->o->bin_obj;
287  return bin->imports_list;
288 }
289 
290 static RzList *libs(RzBinFile *bf) {
291  return NULL;
292 }
293 
294 static RzBinInfo *info(RzBinFile *bf) {
295  RzBinInfo *ret = RZ_NEW0(RzBinInfo);
296  if (!ret) {
297  return NULL;
298  }
299  ut8 magic[4];
300  rz_buf_read_at(bf->buf, NRO_OFF(magic), magic, sizeof(magic));
301  const char *ft = fileType(magic);
302  if (!ft) {
303  ft = "nro";
304  }
305  ret->file = strdup(bf->file);
306  ret->rclass = strdup(ft);
307  ret->os = strdup("switch");
308  ret->arch = strdup("arm");
309  ret->machine = strdup("Nintendo Switch");
310  ret->subsystem = strdup(ft);
311  if (!strncmp(ft, "nrr", 3)) {
312  ret->bclass = strdup("program");
313  ret->type = strdup("EXEC (executable file)");
314  } else if (!strncmp(ft, "nro", 3)) {
315  ret->bclass = strdup("object");
316  ret->type = strdup("OBJECT (executable code)");
317  } else { // mod
318  ret->bclass = strdup("library");
319  ret->type = strdup("MOD (executable library)");
320  }
321  ret->bits = 64;
322  ret->has_va = true;
323  ret->big_endian = false;
324  ret->dbg_info = 0;
325  ret->dbg_info = 0;
326  return ret;
327 }
328 
329 #if !RZ_BIN_NRO
330 
332  .name = "nro",
333  .desc = "Nintendo Switch NRO0 binaries",
334  .license = "MIT",
335  .load_buffer = &load_buffer,
336  .check_buffer = &check_buffer,
337  .baddr = &baddr,
338  .binsym = &binsym,
339  .entries = &entries,
340  .maps = &maps,
341  .sections = &sections,
342  .get_sdb = &get_sdb,
343  .symbols = &symbols,
344  .imports = &imports,
345  .info = &info,
346  .libs = &libs,
347 };
348 
349 #ifndef RZ_PLUGIN_INCORE
352  .data = &rz_bin_plugin_nro,
354 };
355 #endif
356 #endif
RZ_API void rz_bin_symbol_free(RzBinSymbol *sym)
Definition: bin.c:175
RZ_API void rz_bin_map_free(RzBinMap *map)
Definition: bin.c:1023
RZ_API void rz_bin_import_free(RzBinImport *imp)
Definition: bin.c:137
RZ_API RzList * rz_bin_sections_of_maps(RzList *maps)
Create a list of RzBinSection from RzBinMaps.
Definition: bin.c:1084
RZ_API void rz_bin_section_free(RzBinSection *bs)
Definition: bin.c:1116
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb)
Definition: bin_nro.c:51
static Sdb * get_sdb(RzBinFile *bf)
Definition: bin_nro.c:92
static RzList * symbols(RzBinFile *bf)
Definition: bin_nro.c:272
static RzBinAddr * binsym(RzBinFile *bf, RzBinSpecialSymbol type)
Definition: bin_nro.c:73
#define NRO_OFF(x)
Definition: bin_nro.c:11
static RzList * libs(RzBinFile *bf)
Definition: bin_nro.c:290
RZ_API RzLibStruct rizin_plugin
Definition: bin_nro.c:350
static bool check_buffer(RzBuffer *b)
Definition: bin_nro.c:43
RzBinPlugin rz_bin_plugin_nro
Definition: bin_nro.c:331
static RzBinInfo * info(RzBinFile *bf)
Definition: bin_nro.c:294
static ut64 baddr(RzBinFile *bf)
Definition: bin_nro.c:30
static RzList * entries(RzBinFile *bf)
Definition: bin_nro.c:77
static RzList * maps(RzBinFile *bf)
Definition: bin_nro.c:104
static RzList * sections(RzBinFile *bf)
Definition: bin_nro.c:212
#define NRO_OFFSET_MODMEMOFF
Definition: bin_nro.c:12
static RzList * imports(RzBinFile *bf)
Definition: bin_nro.c:281
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
size_t map(int syms, int left, int len)
Definition: enough.c:237
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
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_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API bool rz_list_join(RZ_NONNULL RzList *list1, RZ_NONNULL RzList *list2)
Joins 2 list into one (list2 pointer needs to be freed by the user)
Definition: list.c:209
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")
int type
Definition: mipsasm.c:17
RZ_API int sdb_ns_set(Sdb *s, const char *name, Sdb *r)
Definition: ns.c:156
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
Definition: num.c:25
void parseMod(RzBuffer *buf, RzBinNXOObj *bin, ut32 mod0, ut64 baddr)
Definition: nxo.c:130
const char * fileType(const ut8 *buf)
Definition: nxo.c:24
RzBinSpecialSymbol
Definition: rz_bin.h:136
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
#define rz_buf_read_le32_at(b, addr, result)
Definition: rz_buf.h:271
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
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_RW
Definition: rz_types.h:96
#define RZ_PERM_RX
Definition: rz_types.h:97
#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
#define b(i)
Definition: sha256.c:42
ut32 ro_memoffset
Definition: bin_nro.c:22
ut32 unknown2
Definition: bin_nro.c:19
ut32 size
Definition: bin_nro.c:18
ut32 magic
Definition: bin_nro.c:16
ut32 unknown3
Definition: bin_nro.c:27
ut32 data_size
Definition: bin_nro.c:25
ut32 unknown
Definition: bin_nro.c:17
ut32 ro_size
Definition: bin_nro.c:23
ut32 text_size
Definition: bin_nro.c:21
ut32 bss_size
Definition: bin_nro.c:26
ut32 data_memoffset
Definition: bin_nro.c:24
ut32 text_memoffset
Definition: bin_nro.c:20
Definition: malloc.c:26
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
RZ_DEPRECATE Sdb * sdb
deprecated, put info in C structures instead of this
Definition: rz_bin.h:315
char * file
Definition: rz_bin.h:299
RzBuffer * buf
Definition: rz_bin.h:303
int has_va
Definition: rz_bin.h:228
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
char * bclass
Definition: rz_bin.h:212
char * file
Definition: rz_bin.h:210
ut64 dbg_info
Definition: rz_bin.h:240
char * rclass
Definition: rz_bin.h:213
char * arch
Definition: rz_bin.h:214
int big_endian
Definition: rz_bin.h:235
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
char * name
Definition: rz_bin.h:619
RzListFree free
Definition: rz_list.h:21
Definition: sdb.h:63
ut64(WINAPI *w32_GetEnabledXStateFeatures)()