static RList *parseSegments(RBuffer *buf, int off, int count) { ut8 *b = calloc (count, 32); (void)r_buf_read_at (buf, off, b, count * 32); int x = off; int X = 0; int i; RList *segments = r_list_newf ((RListFree)r_bin_section_free); if (!segments) { return NULL; } // eprintf ("Segments: %d\n", count); for (i = 0; i < count; i++) { int A = r_read_le32 (b + X + 16); int B = r_read_le32 (b + X + 16 + 8); // eprintf ("0x%08x segment 0x%08x 0x%08x %s\n", // x, A, A + B, b + X); const char *cname = (const char *)(b + X); char *name = r_str_ndup (cname, r_str_nlen (cname, 16)); RBinSection *section = newSection (name, A, A + B, true); free (name); r_list_append (segments, section); x += 32; X += 32; } return segments; }
// metadata section starts at offset 0x40 and ends around 0xb0 depending on filenamelength static SymbolsMetadata parseMetadata(RBuffer *buf, int off) { SymbolsMetadata sm = { 0 }; ut8 b[0x100] = { 0 }; (void)r_buf_read_at (buf, off, b, sizeof (b)); sm.addr = off; sm.cputype = r_read_le32 (b); sm.arch = typeString (sm.cputype, &sm.bits); // eprintf ("0x%08x cputype 0x%x -> %s\n", 0x40, sm.cputype, typeString (sm.cputype)); // bits = (strstr (typeString (sm.cputype, &sm.bits), "64"))? 64: 32; sm.subtype = r_read_le32 (b + 4); sm.cpu = subtypeString (sm.subtype); // eprintf ("0x%08x subtype 0x%x -> %s\n", 0x44, sm.subtype, subtypeString (sm.subtype)); sm.n_segments = r_read_le32 (b + 8); // int count = r_read_le32 (b + 0x48); sm.namelen = r_read_le32 (b + 0xc); // eprintf ("0x%08x count %d\n", 0x48, count); // eprintf ("0x%08x strlen %d\n", 0x4c, sm.namelen); // eprintf ("0x%08x filename %s\n", 0x50, b + 16); int delta = 16; sm.segments = parseSegments (buf, off + sm.namelen + delta, sm.n_segments); sm.size = (sm.n_segments * 32) + 120; // hack to detect format ut32 nm, nm2, nm3; r_buf_read_at (buf, off + sm.size, (ut8*)&nm, sizeof (nm)); r_buf_read_at (buf, off + sm.size + 4, (ut8*)&nm2, sizeof (nm2)); r_buf_read_at (buf, off + sm.size + 8, (ut8*)&nm3, sizeof (nm3)); // eprintf ("0x%x next %x %x %x\n", off + sm.size, nm, nm2, nm3); if (r_read_le32 (&nm3) != 0xa1b22b1a) { sm.size -= 8; // is64 = true; } return sm; }
static void headers64(RBinFile *bf) { #define p bf->rbin->cb_printf const ut8 *buf = r_buf_get_at (bf->buf, 0, NULL); p ("0x00000000 ELF64 0x%08x\n", r_read_le32 (buf)); p ("0x00000010 Type 0x%04x\n", r_read_le16 (buf + 0x10)); p ("0x00000012 Machine 0x%04x\n", r_read_le16 (buf + 0x12)); p ("0x00000014 Version 0x%08x\n", r_read_le32 (buf + 0x14)); p ("0x00000018 Entrypoint 0x%08"PFMT64x"\n", r_read_le64 (buf + 0x18)); p ("0x00000020 PhOff 0x%08"PFMT64x"\n", r_read_le64 (buf + 0x20)); p ("0x00000028 ShOff 0x%08"PFMT64x"\n", r_read_le64 (buf + 0x28)); }
// header starts at offset 0 and ends at offset 0x40 static SymbolsHeader parseHeader(RBuffer *buf) { ut8 b[64]; SymbolsHeader sh = { 0 }; (void)r_buf_read_at (buf, 0, b, sizeof (b)); sh.magic = r_read_le32 (b); sh.version = r_read_le32 (b + 4); sh.valid = sh.magic == 0xff01ff02; int i; for (i = 0; i < 16; i++) { sh.uuid[i] = b[24 + i]; } sh.unk0 = r_read_le16 (b + 0x28); sh.unk1 = r_read_le16 (b + 0x2c); // is slotsize + 1 :? sh.slotsize = r_read_le16 (b + 0x2e); sh.size = 0x40; return sh; }
R_API ut64 r_mem_get_num(const ut8 *b, int size) { // LITTLE ENDIAN is the default for streams switch (size) { case 1: return r_read_le8 (b); case 2: return r_read_le16 (b); case 4: return r_read_le32 (b); case 8: return r_read_le64 (b); } return 0LL; }
static ut32 readLE32(RBuffer *buf, int off) { int left = 0; const ut8 *data = r_buf_get_at (buf, off, &left); return left > 3? r_read_le32 (data): 0; }
RBinDexObj *r_bin_dex_new_buf(RBuffer *buf) { RBinDexObj *bin = R_NEW0 (RBinDexObj); int i; ut8 *bufptr; struct dex_header_t *dexhdr; if (!bin) { goto fail; } bin->size = buf->length; bin->b = r_buf_new (); if (!r_buf_set_bytes (bin->b, buf->buf, bin->size)) { goto fail; } /* header */ if (bin->size < sizeof (struct dex_header_t)) { goto fail; } bufptr = bin->b->buf; dexhdr = &bin->header; //check boundaries of bufptr if (bin->size < 112) { goto fail; } memcpy (&dexhdr->magic, bufptr, 8); dexhdr->checksum = r_read_le32 (bufptr + 8); memcpy (&dexhdr->signature, bufptr + 12, 20); dexhdr->size = r_read_le32 (bufptr + 32); dexhdr->header_size = r_read_le32 (bufptr + 36); dexhdr->endian = r_read_le32 (bufptr + 40); // TODO: this offsets and size will be used for checking, // so they should be checked. Check overlap, < 0, > bin.size dexhdr->linksection_size = r_read_le32 (bufptr + 44); dexhdr->linksection_offset = r_read_le32 (bufptr + 48); dexhdr->map_offset = r_read_le32 (bufptr + 52); dexhdr->strings_size = r_read_le32 (bufptr + 56); dexhdr->strings_offset = r_read_le32 (bufptr + 60); dexhdr->types_size = r_read_le32 (bufptr + 64); dexhdr->types_offset = r_read_le32 (bufptr + 68); dexhdr->prototypes_size = r_read_le32 (bufptr + 72); dexhdr->prototypes_offset = r_read_le32 (bufptr + 76); dexhdr->fields_size = r_read_le32 (bufptr + 80); dexhdr->fields_offset = r_read_le32 (bufptr + 84); dexhdr->method_size = r_read_le32 (bufptr + 88); dexhdr->method_offset = r_read_le32 (bufptr + 92); dexhdr->class_size = r_read_le32 (bufptr + 96); dexhdr->class_offset = r_read_le32 (bufptr + 100); dexhdr->data_size = r_read_le32 (bufptr + 104); dexhdr->data_offset = r_read_le32 (bufptr + 108); /* strings */ #define STRINGS_SIZE ((dexhdr->strings_size + 1) * sizeof (ut32)) bin->strings = (ut32 *) calloc (dexhdr->strings_size + 1, sizeof (ut32)); if (!bin->strings) { goto fail; } if (dexhdr->strings_size > bin->size) { free (bin->strings); goto fail; } for (i = 0; i < dexhdr->strings_size; i++) { ut64 offset = dexhdr->strings_offset + i * sizeof (ut32); //make sure we can read from bufptr without oob if (offset + 4 > bin->size) { free (bin->strings); goto fail; } bin->strings[i] = r_read_le32 (bufptr + offset); } /* classes */ // TODO: not sure about if that is needed int classes_size = dexhdr->class_size * DEX_CLASS_SIZE; if (dexhdr->class_offset + classes_size >= bin->size) { classes_size = bin->size - dexhdr->class_offset; } if (classes_size < 0) { classes_size = 0; } dexhdr->class_size = classes_size / DEX_CLASS_SIZE; bin->classes = (struct dex_class_t *) calloc (dexhdr->class_size, sizeof (struct dex_class_t)); for (i = 0; i < dexhdr->class_size; i++) { ut64 offset = dexhdr->class_offset + i * DEX_CLASS_SIZE; if (offset + 32 > bin->size) { free (bin->strings); free (bin->classes); goto fail; } bin->classes[i].class_id = r_read_le32 (bufptr + offset + 0); bin->classes[i].access_flags = r_read_le32 (bufptr + offset + 4); bin->classes[i].super_class = r_read_le32 (bufptr + offset + 8); bin->classes[i].interfaces_offset = r_read_le32 (bufptr + offset + 12); bin->classes[i].source_file = r_read_le32 (bufptr + offset + 16); bin->classes[i].anotations_offset = r_read_le32 (bufptr + offset + 20); bin->classes[i].class_data_offset = r_read_le32 (bufptr + offset + 24); bin->classes[i].static_values_offset = r_read_le32 (bufptr + offset + 28); } /* methods */ int methods_size = dexhdr->method_size * sizeof (struct dex_method_t); if (dexhdr->method_offset + methods_size >= bin->size) { methods_size = bin->size - dexhdr->method_offset; } if (methods_size < 0) { methods_size = 0; } dexhdr->method_size = methods_size / sizeof (struct dex_method_t); bin->methods = (struct dex_method_t *) calloc (methods_size + 1, 1); for (i = 0; i < dexhdr->method_size; i++) { ut64 offset = dexhdr->method_offset + i * sizeof (struct dex_method_t); if (offset + 8 > bin->size) { free (bin->strings); free (bin->classes); free (bin->methods); goto fail; } bin->methods[i].class_id = r_read_le16 (bufptr + offset + 0); bin->methods[i].proto_id = r_read_le16 (bufptr + offset + 2); bin->methods[i].name_id = r_read_le32 (bufptr + offset + 4); } /* types */ int types_size = dexhdr->types_size * sizeof (struct dex_type_t); if (dexhdr->types_offset + types_size >= bin->size) { types_size = bin->size - dexhdr->types_offset; } if (types_size < 0) { types_size = 0; } dexhdr->types_size = types_size / sizeof (struct dex_type_t); bin->types = (struct dex_type_t *) calloc (types_size + 1, 1); for (i = 0; i < dexhdr->types_size; i++) { ut64 offset = dexhdr->types_offset + i * sizeof (struct dex_type_t); if (offset + 4 > bin->size) { free (bin->strings); free (bin->classes); free (bin->methods); free (bin->types); goto fail; } bin->types[i].descriptor_id = r_read_le32 (bufptr + offset); } /* fields */ int fields_size = dexhdr->fields_size * sizeof (struct dex_field_t); if (dexhdr->fields_offset + fields_size >= bin->size) { fields_size = bin->size - dexhdr->fields_offset; } if (fields_size < 0) { fields_size = 0; } dexhdr->fields_size = fields_size / sizeof (struct dex_field_t); bin->fields = (struct dex_field_t *) calloc (fields_size + 1, 1); for (i = 0; i < dexhdr->fields_size; i++) { ut64 offset = dexhdr->fields_offset + i * sizeof (struct dex_field_t); if (offset + 8 > bin->size) { free (bin->strings); free (bin->classes); free (bin->methods); free (bin->types); free (bin->fields); goto fail; } bin->fields[i].class_id = r_read_le16 (bufptr + offset + 0); bin->fields[i].type_id = r_read_le16 (bufptr + offset + 2); bin->fields[i].name_id = r_read_le32 (bufptr + offset + 4); } /* proto */ int protos_size = dexhdr->prototypes_size * sizeof (struct dex_proto_t); if (dexhdr->prototypes_offset + protos_size >= bin->size) { protos_size = bin->size - dexhdr->prototypes_offset; } if (protos_size < 1) { dexhdr->prototypes_size = 0; return bin; } dexhdr->prototypes_size = protos_size / sizeof (struct dex_proto_t); bin->protos = (struct dex_proto_t *) calloc (protos_size, 1); for (i = 0; i < dexhdr->prototypes_size; i++) { ut64 offset = dexhdr->prototypes_offset + i * sizeof (struct dex_proto_t); if (offset + 12 > bin->size) { free (bin->strings); free (bin->classes); free (bin->methods); free (bin->types); free (bin->fields); free (bin->protos); goto fail; } bin->protos[i].shorty_id = r_read_le32 (bufptr + offset + 0); bin->protos[i].return_type_id = r_read_le32 (bufptr + offset + 4); bin->protos[i].parameters_off = r_read_le32 (bufptr + offset + 8); } return bin; fail: if (bin) { r_buf_free (bin->b); free (bin); } return NULL; }
static ut32 readDword (RCoreObjc *objc, ut64 addr) { ut8 buf[4]; (void)r_io_read_at (objc->core->io, addr, buf, sizeof (buf)); return r_read_le32 (buf); }
static RList* symbols(RBinFile *arch) { ut32 *vtable = (ut32*)arch->buf->buf; RList *ret = NULL; const char *name; SMD_Header *hdr; int i; if (!(ret = r_list_new ())) return NULL; ret->free = free; // TODO: store all this stuff in SDB hdr = (SMD_Header*)(arch->buf->buf + 0x100); addsym (ret, "rom_start", hdr->RomStart); addsym (ret, "rom_end", hdr->RomEnd); addsym (ret, "ram_start", hdr->RamStart); addsym (ret, "ram_end", hdr->RamEnd); showstr ("Copyright", hdr->CopyRights, 32); showstr ("DomesticName", hdr->DomesticName, 48); showstr ("OverseasName", hdr->OverseasName, 48); showstr ("ProductCode", hdr->ProductCode, 14); eprintf ("Checksum: 0x%04x\n", (ut32)hdr->CheckSum); showstr ("Peripherials", hdr->Peripherials, 16); showstr ("SramCode", hdr->CountryCode, 12); showstr ("ModemCode", hdr->CountryCode, 12); showstr ("CountryCode", hdr->CountryCode, 16); /* parse vtable */ for (i=0; i<64; i++) { switch (i) { case 0: name = "SSP"; break; case 1: name = "Reset"; break; case 2: name = "BusErr"; break; case 3: name = "InvOpCode"; break; case 4: name = "DivBy0"; break; case 5: name = "Check"; break; case 6: name = "TrapV"; break; case 7: name = "GPF"; break; case 8: name = "Trace"; break; case 9: name = "Reserv0"; break; case 10: name = "Reserv1"; break; case 11: name = "Reserv2"; break; case 12: name = "Reserv3"; break; case 13: name = "Reserv4"; break; case 14: name = "BadInt"; break; case 15: name = "Reserv10"; break; case 16: name = "Reserv11"; break; case 17: name = "Reserv12"; break; case 18: name = "Reserv13"; break; case 19: name = "Reserv14"; break; case 20: name = "Reserv15"; break; case 21: name = "Reserv16"; break; case 22: name = "Reserv17"; break; case 23: name = "BadIRQ"; break; case 24: name = "IRQ1"; break; case 25: name = "EXT"; break; case 26: name = "IRQ3"; break; case 27: name = "HBLANK"; break; case 28: name = "IRQ5"; break; case 29: name = "VBLANK"; break; case 30: name = "IRQ7"; break; case 31: name = "Trap0"; break; case 32: name = "Trap1"; break; case 33: name = "Trap2"; break; case 34: name = "Trap3"; break; case 35: name = "Trap4"; break; case 36: name = "Trap5"; break; case 37: name = "Trap6"; break; case 38: name = "Trap7"; break; case 39: name = "Trap8"; break; case 40: name = "Trap9"; break; case 41: name = "Trap10"; break; case 42: name = "Trap11"; break; case 43: name = "Trap12"; break; case 44: name = "Trap13"; break; case 45: name = "Trap14"; break; case 46: name = "Trap15"; break; case 47: name = "Reserv30"; break; case 48: name = "Reserv31"; break; case 49: name = "Reserv32"; break; case 50: name = "Reserv33"; break; case 51: name = "Reserv34"; break; case 52: name = "Reserv35"; break; case 53: name = "Reserv36"; break; case 54: name = "Reserv37"; break; case 55: name = "Reserv38"; break; case 56: name = "Reserv39"; break; case 57: name = "Reserv3A"; break; case 58: name = "Reserv3B"; break; case 59: name = "Reserv3C"; break; case 60: name = "Reserv3D"; break; case 61: name = "Reserv3E"; break; case 62: name = "Reserv3F"; break; default: name = NULL; } if (name && vtable[i]) { ut32 addr = 0; // XXX don't know if always LE addr = r_read_le32 (&vtable[i]); addsym (ret, name, addr); } } return ret; }