Use RRead APIs instead of shipping our ones

This commit is contained in:
pancake committed 2026-04-17 12:08:56 +02:00
1 parent 2b39ebd659
commit 43b593bda2
3 files changed
+117 -176

No files matched your search

+42 -62
View File
@@ -1,20 +1,6 @@
// Fast ELF parser for r2unity
#include "lib.h"
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
static inline ut32 RD_LE32 (const ut8 *p) {
return ((ut32)p[0]) | ((ut32)p[1] << 8) | ((ut32)p[2] << 16) | ((ut32)p[3] << 24);
}
static inline ut64 RD_LE64 (const ut8 *p) {
return ((ut64)p[0]) | ((ut64)p[1] << 8) | ((ut64)p[2] << 16) | ((ut64)p[3] << 24) |
((ut64)p[4] << 32) | ((ut64)p[5] << 40) | ((ut64)p[6] << 48) | ((ut64)p[7] << 56);
}
static inline ut16 RD_LE16 (const ut8 *p) {
return (ut16)((ut16)p[0] | ((ut16)p[1] << 8));
}
typedef struct {
ut64 vaddr;
@@ -36,54 +22,48 @@ typedef struct {
static bool elf_load (const char *path, ElfImg *e) {
memset (e, 0, sizeof (*e));
int fd = open (path, O_RDONLY);
if (fd < 0) return false;
struct stat st;
if (fstat (fd, &st) != 0 || st.st_size <= 0) { close (fd); return false; }
e->filesize = (ut64) st.st_size;
e->file = R_NEWS (ut8, e->filesize);
if (!e->file) { close (fd); return false; }
ssize_t rd = read (fd, e->file, (size_t) e->filesize);
close (fd);
if (rd < 0 || (ut64) rd != e->filesize) { R_FREE (e->file); return false; }
size_t sz = 0;
e->file = (ut8 *) r_file_slurp (path, &sz);
if (!e->file || sz == 0) { R_FREE (e->file); return false; }
e->filesize = (ut64) sz;
const ut8 *p = e->file;
if (!(p[0] == 0x7f && p[1] == 'E' && p[2] == 'L' && p[3] == 'F')) { R_FREE (e->file); return false; }
e->is64 = (p[4] == 2);
e->le = (p[5] == 1);
if (!e->le) { R_FREE (e->file); return false; }
if (e->is64) {
ut64 phoff = RD_LE64 (p + 0x20);
ut16 phentsize = RD_LE16 (p + 0x36);
ut16 phnum = RD_LE16 (p + 0x38);
ut64 phoff = r_read_le64 (p + 0x20);
ut16 phentsize = r_read_le16 (p + 0x36);
ut16 phnum = r_read_le16 (p + 0x38);
for (ut16 i = 0; i < phnum && e->nsegs < (int)(sizeof (e->segs)/sizeof (e->segs[0])); i++) {
ut64 off = phoff + (ut64) i * phentsize;
if (off + 56 > e->filesize) break;
const ut8 *ph = p + off;
ut32 p_type = RD_LE32 (ph + 0);
ut32 p_flags = RD_LE32 (ph + 4);
ut64 p_offset = RD_LE64 (ph + 8);
ut64 p_vaddr = RD_LE64 (ph + 16);
ut64 p_filesz = RD_LE64 (ph + 32);
ut64 p_memsz = RD_LE64 (ph + 40);
ut32 p_type = r_read_le32 (ph + 0);
ut32 p_flags = r_read_le32 (ph + 4);
ut64 p_offset = r_read_le64 (ph + 8);
ut64 p_vaddr = r_read_le64 (ph + 16);
ut64 p_filesz = r_read_le64 (ph + 32);
ut64 p_memsz = r_read_le64 (ph + 40);
if (p_type == 1 || p_type == 2) {
ElfSeg *s = &e->segs[e->nsegs++];
s->vaddr = p_vaddr; s->memsz = p_memsz; s->offset = p_offset; s->filesz = p_filesz; s->flags = p_flags; s->p_type = p_type;
}
}
} else {
ut32 phoff = RD_LE32 (p + 0x1C);
ut16 phentsize = RD_LE16 (p + 0x2A);
ut16 phnum = RD_LE16 (p + 0x2C);
ut32 phoff = r_read_le32 (p + 0x1C);
ut16 phentsize = r_read_le16 (p + 0x2A);
ut16 phnum = r_read_le16 (p + 0x2C);
for (ut16 i = 0; i < phnum && e->nsegs < (int)(sizeof (e->segs)/sizeof (e->segs[0])); i++) {
ut64 off = (ut64) phoff + (ut64) i * phentsize;
if (off + 32 > e->filesize) break;
const ut8 *ph = p + off;
ut32 p_type = RD_LE32 (ph + 0);
ut32 p_offset = RD_LE32 (ph + 4);
ut32 p_vaddr = RD_LE32 (ph + 8);
ut32 p_filesz = RD_LE32 (ph + 16);
ut32 p_memsz = RD_LE32 (ph + 20);
ut32 p_flags = RD_LE32 (ph + 24);
ut32 p_type = r_read_le32 (ph + 0);
ut32 p_offset = r_read_le32 (ph + 4);
ut32 p_vaddr = r_read_le32 (ph + 8);
ut32 p_filesz = r_read_le32 (ph + 16);
ut32 p_memsz = r_read_le32 (ph + 20);
ut32 p_flags = r_read_le32 (ph + 24);
if (p_type == 1 || p_type == 2) {
ElfSeg *s = &e->segs[e->nsegs++];
s->vaddr = p_vaddr; s->memsz = p_memsz; s->offset = p_offset; s->filesz = p_filesz; s->flags = p_flags; s->p_type = p_type;
@@ -139,8 +119,8 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
if (dyn_off && dyn_sz) {
const ut8 *d = e.file + dyn_off;
for (ut64 off = 0; off + (e.is64? 16: 8) <= dyn_sz; off += (e.is64? 16: 8)) {
ut64 tag = e.is64 ? RD_LE64 (d + off) : (ut64) RD_LE32 (d + off);
ut64 val = e.is64 ? RD_LE64 (d + off + 8) : (ut64) RD_LE32 (d + off + 4);
ut64 tag = e.is64 ? r_read_le64 (d + off) : (ut64) r_read_le32 (d + off);
ut64 val = e.is64 ? r_read_le64 (d + off + 8) : (ut64) r_read_le32 (d + off + 4);
if (tag == 0) break;
if (tag == 7) rela_off = val; else if (tag == 8) rela_sz = val; else if (tag == 9) rela_ent = val;
else if (tag == 17) rel_off = val; else if (tag == 18) rel_sz = val; else if (tag == 19) rel_ent = val;
@@ -150,9 +130,9 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
if (rela_off && rela_sz && rela_ent) {
for (ut64 i = 0; i + rela_ent <= rela_sz; i += rela_ent) {
const ut8 *rp = elf_vm_to_ptr (&e, rela_off + i); if (!rp) break;
ut64 r_offset = e.is64 ? RD_LE64 (rp + 0) : (ut64) RD_LE32 (rp + 0);
ut64 r_info = e.is64 ? RD_LE64 (rp + 8) : (ut64) RD_LE32 (rp + 4);
ut64 r_addend = e.is64 ? RD_LE64 (rp + 16) : (ut64) RD_LE32 (rp + 8);
ut64 r_offset = e.is64 ? r_read_le64 (rp + 0) : (ut64) r_read_le32 (rp + 0);
ut64 r_info = e.is64 ? r_read_le64 (rp + 8) : (ut64) r_read_le32 (rp + 4);
ut64 r_addend = e.is64 ? r_read_le64 (rp + 16) : (ut64) r_read_le32 (rp + 8);
ut64 type = e.is64 ? (r_info & 0xffffffffULL) : (r_info & 0xffULL);
bool is_relative = (type == 8) || (type == 23) || (type == 1027);
if (!is_relative) continue;
@@ -166,13 +146,13 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
if (rel_off && rel_sz && rel_ent) {
for (ut64 i = 0; i + rel_ent <= rel_sz; i += rel_ent) {
const ut8 *rp = elf_vm_to_ptr (&e, rel_off + i); if (!rp) break;
ut64 r_offset = e.is64 ? RD_LE64 (rp + 0) : (ut64) RD_LE32 (rp + 0);
ut64 r_info = e.is64 ? RD_LE64 (rp + 8) : (ut64) RD_LE32 (rp + 4);
ut64 r_offset = e.is64 ? r_read_le64 (rp + 0) : (ut64) r_read_le32 (rp + 0);
ut64 r_info = e.is64 ? r_read_le64 (rp + 8) : (ut64) r_read_le32 (rp + 4);
ut64 type = e.is64 ? (r_info & 0xffffffffULL) : (r_info & 0xffULL);
bool is_relative = (type == 8) || (type == 23) || (type == 1027);
if (!is_relative) continue;
ut8 *loc = (ut8 *) elf_vm_to_ptr (&e, r_offset); if (!loc) continue;
ut64 add = e.is64 ? RD_LE64 (loc) : (ut64) RD_LE32 (loc);
ut64 add = e.is64 ? r_read_le64 (loc) : (ut64) r_read_le32 (loc);
// REL: add base to current value
ut64 newv = base_vaddr != UT64_MAX ? (base_vaddr + add) : add;
if (e.is64) { for (int b = 0; b < 8; b++) loc[b] = (ut8)((newv >> (8*b)) & 0xff); }
@@ -183,17 +163,17 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
ut64 curr = 0;
for (ut64 i = 0; i + relr_ent <= relr_sz; i += relr_ent) {
const ut8 *rp = elf_vm_to_ptr (&e, relr_off + i); if (!rp) break;
ut64 R = RD_LE64 (rp);
ut64 R = r_read_le64 (rp);
if ((R & 1ULL) == 0) {
ut64 addr = R; ut8 *loc = (ut8 *) elf_vm_to_ptr (&e, addr);
if (loc) { ut64 add = RD_LE64 (loc); ut64 newv = base_vaddr != UT64_MAX ? (base_vaddr + add) : add; for (int b = 0; b < 8; b++) loc[b] = (ut8)((newv >> (8*b)) & 0xff); }
if (loc) { ut64 add = r_read_le64 (loc); ut64 newv = base_vaddr != UT64_MAX ? (base_vaddr + add) : add; for (int b = 0; b < 8; b++) loc[b] = (ut8)((newv >> (8*b)) & 0xff); }
curr = addr + 8;
} else {
ut64 bitmap = R >> 1;
for (int bit = 0; bit < 63; bit++) if (bitmap & (1ULL << bit)) {
ut64 addr = curr + (ut64)(bit + 1) * 8ULL;
ut8 *loc = (ut8 *) elf_vm_to_ptr (&e, addr); if (!loc) continue;
ut64 add = RD_LE64 (loc); ut64 newv = base_vaddr != UT64_MAX ? (base_vaddr + add) : add; for (int b = 0; b < 8; b++) loc[b] = (ut8)((newv >> (8*b)) & 0xff);
ut64 add = r_read_le64 (loc); ut64 newv = base_vaddr != UT64_MAX ? (base_vaddr + add) : add; for (int b = 0; b < 8; b++) loc[b] = (ut8)((newv >> (8*b)) & 0xff);
}
curr += 8ULL * 63ULL;
}
@@ -212,9 +192,9 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
const ut8 *buf = e.file + s->offset;
ut64 sz = s->filesz;
for (ut64 off = 0; off + (ut64)(8 + ptrsz) * 3 <= sz; off += 4) {
ut32 cnt1 = RD_LE32 (buf + off + 0);
ut64 p1 = (ptrsz == 8)? RD_LE64 (buf + off + 8): (ut64) RD_LE32 (buf + off + 4);
ut32 cnt2 = RD_LE32 (buf + off + (ut64)(8 + ptrsz));
ut32 cnt1 = r_read_le32 (buf + off + 0);
ut64 p1 = (ptrsz == 8)? r_read_le64 (buf + off + 8): (ut64) r_read_le32 (buf + off + 4);
ut32 cnt2 = r_read_le32 (buf + off + (ut64)(8 + ptrsz));
if (cnt1 < 32 || cnt2 < 16) continue;
// Sample method array
ut32 good = 0, seen = 0;
@@ -223,7 +203,7 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
const ut8 *pp = elf_vm_to_ptr (&e, p1 + (ut64)k * (ut64)ptrsz);
if (!pp && base_vaddr != UT64_MAX) { pp = elf_vm_to_ptr (&e, base_vaddr + p1 + (ut64)k * (ut64)ptrsz); }
if (!pp) break;
ut64 val = (ptrsz == 8) ? RD_LE64 (pp) : (ut64) RD_LE32 (pp);
ut64 val = (ptrsz == 8) ? r_read_le64 (pp) : (ut64) r_read_le32 (pp);
if (val) seen++;
if ((val >= text_lo && val < text_hi) || (val && base_vaddr != UT64_MAX && (val + base_vaddr) >= text_lo && (val + base_vaddr) < text_hi)) good++;
}
@@ -236,7 +216,7 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
const ut8 *pp = elf_vm_to_ptr (&e, p1 + (ut64)m * (ut64)ptrsz);
if (!pp && base_vaddr != UT64_MAX) { pp = elf_vm_to_ptr (&e, base_vaddr + p1 + (ut64)m * (ut64)ptrsz); }
if (!pp) break;
ut64 val = (ptrsz == 8) ? RD_LE64 (pp) : (ut64) RD_LE32 (pp);
ut64 val = (ptrsz == 8) ? r_read_le64 (pp) : (ut64) r_read_le32 (pp);
ut64 abs = (val >= text_lo && val < text_hi)? val: ((val && base_vaddr != UT64_MAX)? val + base_vaddr: val);
if (abs >= text_lo && abs < text_hi) { candidates[m] = abs; in_text++; }
}
@@ -252,19 +232,19 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
const ut8 *buf = e.file + s->offset;
ut64 sz = s->filesz;
for (ut64 off = 0; off + (ut64)(8 + ptrsz) <= sz; off += 4) {
ut32 cnt32 = RD_LE32 (buf + off);
ut32 cnt32 = r_read_le32 (buf + off);
if (cnt32 == 0) continue;
/* stricter thresholds to avoid wrong tables */
if (cnt32 < 64) continue;
if (expected && (cnt32 > expected * 2 || cnt32 < expected / 2)) continue;
ut64 arrptr = (ptrsz == 8) ? RD_LE64 (buf + off + 8) : (ut64) RD_LE32 (buf + off + 4);
ut64 arrptr = (ptrsz == 8) ? r_read_le64 (buf + off + 8) : (ut64) r_read_le32 (buf + off + 4);
ut32 good = 0, seen = 0;
ut32 sample = R_MIN ((ut32)128, cnt32);
for (ut32 k = 0; k < sample; k++) {
const ut8 *pp = elf_vm_to_ptr (&e, arrptr + (ut64)k * (ut64)ptrsz);
if (!pp && base_vaddr != UT64_MAX) { pp = elf_vm_to_ptr (&e, base_vaddr + arrptr + (ut64)k * (ut64)ptrsz); }
if (!pp) break;
ut64 val = (ptrsz == 8) ? RD_LE64 (pp) : (ut64) RD_LE32 (pp);
ut64 val = (ptrsz == 8) ? r_read_le64 (pp) : (ut64) r_read_le32 (pp);
if (val) seen++;
if ((val >= text_lo && val < text_hi) || (val && base_vaddr != UT64_MAX && (val + base_vaddr) >= text_lo && (val + base_vaddr) < text_hi)) good++;
}
@@ -277,7 +257,7 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
const ut8 *pp = elf_vm_to_ptr (&e, arrptr + (ut64)m * (ut64)ptrsz);
if (!pp && base_vaddr != UT64_MAX) { pp = elf_vm_to_ptr (&e, base_vaddr + arrptr + (ut64)m * (ut64)ptrsz); }
if (!pp) break;
ut64 val = (ptrsz == 8) ? RD_LE64 (pp) : (ut64) RD_LE32 (pp);
ut64 val = (ptrsz == 8) ? r_read_le64 (pp) : (ut64) r_read_le32 (pp);
ut64 abs = (val >= text_lo && val < text_hi)? val: ((val && base_vaddr != UT64_MAX)? val + base_vaddr: val);
if (abs >= text_lo && abs < text_hi) { candidates[m] = abs; in_text++; }
}
+50 -63
View File
@@ -1,18 +1,5 @@
#include "lib.h"
#include <r_util.h>
#include <r_util/r_buf.h>
#undef RD_LE32
static inline ut32 RD_LE32 (const ut8 *p) {
return ((ut32)p[0]) | ((ut32)p[1] << 8) | ((ut32)p[2] << 16) | ((ut32)p[3] << 24);
}
static inline ut16 RD_LE16 (const ut8 *p) {
return (ut16)((ut16)p[0] | ((ut16)p[1] << 8));
}
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
static bool g_debug = false;
@@ -39,12 +26,12 @@ R_API R2UnityMetadata *r2unity_parse_metadata (RBuffer *buf) {
R_FREE (meta);
return NULL;
}
uint32_t sanity = RD_LE32 (preamble);
uint32_t sanity = r_read_le32 (preamble);
if (sanity != IL2CPP_MAGIC) {
R_FREE (meta);
return NULL;
}
int32_t version = (int32_t) RD_LE32 (preamble + 4);
int32_t version = (int32_t) r_read_le32 (preamble + 4);
meta->version = version;
size_t header_size = 0;
if (version < 24 || version > 31) {
@@ -66,11 +53,11 @@ R_API R2UnityMetadata *r2unity_parse_metadata (RBuffer *buf) {
}
// Normalize header from on-disk little-endian to native byte order.
// Every field in the Il2Cpp header structs is a 32-bit word, so a single
// in-place RD_LE32 sweep handles all versions and is a no-op on LE hosts.
// in-place r_read_le32 sweep handles all versions and is a no-op on LE hosts.
uint32_t *hdr_words = (uint32_t *) &meta->header;
size_t nfields = header_size / sizeof (uint32_t);
for (size_t i = 0; i < nfields; i++) {
hdr_words[i] = RD_LE32 ((const ut8 *) &hdr_words[i]);
hdr_words[i] = r_read_le32 (&hdr_words[i]);
}
meta->buf = buf;
/* Normalize header fields depending on version to simplify later access */
@@ -181,32 +168,32 @@ R_API Il2CppTypeDefinition *r2unity_get_type_definitions (R2UnityMetadata *meta,
}
for (size_t i = 0; i < *count; i++) {
const ut8 *p = buf + i * entry;
types[i].nameIndex = RD_LE32 (p + 0);
types[i].namespaceIndex = RD_LE32 (p + 4);
types[i].byvalTypeIndex = (int32_t) RD_LE32 (p + 8);
types[i].declaringTypeIndex = (int32_t) RD_LE32 (p + 12);
types[i].parentIndex = (int32_t) RD_LE32 (p + 16);
types[i].elementTypeIndex = (int32_t) RD_LE32 (p + 20);
types[i].genericContainerIndex = (int32_t) RD_LE32 (p + 24);
types[i].flags = RD_LE32 (p + 28);
types[i].fieldStart = (int32_t) RD_LE32 (p + 32);
types[i].methodStart = (int32_t) RD_LE32 (p + 36);
types[i].eventStart = (int32_t) RD_LE32 (p + 40);
types[i].propertyStart = (int32_t) RD_LE32 (p + 44);
types[i].nestedTypesStart = (int32_t) RD_LE32 (p + 48);
types[i].interfacesStart = (int32_t) RD_LE32 (p + 52);
types[i].vtableStart = (int32_t) RD_LE32 (p + 56);
types[i].interfaceOffsetsStart = (int32_t) RD_LE32 (p + 60);
types[i].method_count = RD_LE16 (p + 64);
types[i].property_count = RD_LE16 (p + 66);
types[i].field_count = RD_LE16 (p + 68);
types[i].event_count = RD_LE16 (p + 70);
types[i].nested_type_count = RD_LE16 (p + 72);
types[i].vtable_count = RD_LE16 (p + 74);
types[i].interfaces_count = RD_LE16 (p + 76);
types[i].interface_offsets_count = RD_LE16 (p + 78);
types[i].bitfield = RD_LE32 (p + 80);
types[i].token = RD_LE32 (p + 84);
types[i].nameIndex = r_read_le32 (p + 0);
types[i].namespaceIndex = r_read_le32 (p + 4);
types[i].byvalTypeIndex = (int32_t) r_read_le32 (p + 8);
types[i].declaringTypeIndex = (int32_t) r_read_le32 (p + 12);
types[i].parentIndex = (int32_t) r_read_le32 (p + 16);
types[i].elementTypeIndex = (int32_t) r_read_le32 (p + 20);
types[i].genericContainerIndex = (int32_t) r_read_le32 (p + 24);
types[i].flags = r_read_le32 (p + 28);
types[i].fieldStart = (int32_t) r_read_le32 (p + 32);
types[i].methodStart = (int32_t) r_read_le32 (p + 36);
types[i].eventStart = (int32_t) r_read_le32 (p + 40);
types[i].propertyStart = (int32_t) r_read_le32 (p + 44);
types[i].nestedTypesStart = (int32_t) r_read_le32 (p + 48);
types[i].interfacesStart = (int32_t) r_read_le32 (p + 52);
types[i].vtableStart = (int32_t) r_read_le32 (p + 56);
types[i].interfaceOffsetsStart = (int32_t) r_read_le32 (p + 60);
types[i].method_count = r_read_le16 (p + 64);
types[i].property_count = r_read_le16 (p + 66);
types[i].field_count = r_read_le16 (p + 68);
types[i].event_count = r_read_le16 (p + 70);
types[i].nested_type_count = r_read_le16 (p + 72);
types[i].vtable_count = r_read_le16 (p + 74);
types[i].interfaces_count = r_read_le16 (p + 76);
types[i].interface_offsets_count = r_read_le16 (p + 78);
types[i].bitfield = r_read_le32 (p + 80);
types[i].token = r_read_le32 (p + 84);
}
R_FREE (buf);
return types;
@@ -239,16 +226,16 @@ R_API Il2CppMethodDefinition *r2unity_get_method_definitions (R2UnityMetadata *m
}
for (size_t i = 0; i < *count; i++) {
const ut8 *p = buf + i * entry;
methods[i].nameIndex = RD_LE32 (p + 0);
methods[i].declaringType = (int32_t) RD_LE32 (p + 4);
methods[i].returnType = (int32_t) RD_LE32 (p + 8);
methods[i].parameterStart = (int32_t) RD_LE32 (p + 12);
methods[i].genericContainerIndex = (int32_t) RD_LE32 (p + 16);
methods[i].token = RD_LE32 (p + 20);
methods[i].flags = RD_LE16 (p + 24);
methods[i].iflags = RD_LE16 (p + 26);
methods[i].slot = RD_LE16 (p + 28);
methods[i].parameterCount = RD_LE16 (p + 30);
methods[i].nameIndex = r_read_le32 (p + 0);
methods[i].declaringType = (int32_t) r_read_le32 (p + 4);
methods[i].returnType = (int32_t) r_read_le32 (p + 8);
methods[i].parameterStart = (int32_t) r_read_le32 (p + 12);
methods[i].genericContainerIndex = (int32_t) r_read_le32 (p + 16);
methods[i].token = r_read_le32 (p + 20);
methods[i].flags = r_read_le16 (p + 24);
methods[i].iflags = r_read_le16 (p + 26);
methods[i].slot = r_read_le16 (p + 28);
methods[i].parameterCount = r_read_le16 (p + 30);
}
R_FREE (buf);
return methods;
@@ -295,16 +282,16 @@ R_API Il2CppImageDefinition *r2unity_get_images (R2UnityMetadata *meta, size_t *
}
for (size_t i = 0; i < *count; i++) {
const ut8 *p = buf2 + i * entry;
imgs[i].nameIndex = RD_LE32 (p + 0);
imgs[i].assemblyIndex = (int32_t) RD_LE32 (p + 4);
imgs[i].typeStart = (int32_t) RD_LE32 (p + 8);
imgs[i].typeCount = RD_LE32 (p + 12);
imgs[i].exportedTypeStart = (int32_t) RD_LE32 (p + 16);
imgs[i].exportedTypeCount = RD_LE32 (p + 20);
imgs[i].entryPointIndex = (int32_t) RD_LE32 (p + 24);
imgs[i].token = RD_LE32 (p + 28);
imgs[i].customAttributeStart = (int32_t) RD_LE32 (p + 32);
imgs[i].customAttributeCount = RD_LE32 (p + 36);
imgs[i].nameIndex = r_read_le32 (p + 0);
imgs[i].assemblyIndex = (int32_t) r_read_le32 (p + 4);
imgs[i].typeStart = (int32_t) r_read_le32 (p + 8);
imgs[i].typeCount = r_read_le32 (p + 12);
imgs[i].exportedTypeStart = (int32_t) r_read_le32 (p + 16);
imgs[i].exportedTypeCount = r_read_le32 (p + 20);
imgs[i].entryPointIndex = (int32_t) r_read_le32 (p + 24);
imgs[i].token = r_read_le32 (p + 28);
imgs[i].customAttributeStart = (int32_t) r_read_le32 (p + 32);
imgs[i].customAttributeCount = r_read_le32 (p + 36);
}
R_FREE (buf2);
return imgs;
+25 -51
View File
@@ -1,20 +1,6 @@
// Fast Mach-O parser for r2unity
#include "lib.h"
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
static inline ut32 RD_LE32 (const ut8 *p) {
return ((ut32)p[0]) | ((ut32)p[1] << 8) | ((ut32)p[2] << 16) | ((ut32)p[3] << 24);
}
static inline ut32 RD_BE32 (const ut8 *p) {
return ((ut32)p[3]) | ((ut32)p[2] << 8) | ((ut32)p[1] << 16) | ((ut32)p[0] << 24);
}
static inline ut64 RD_LE64 (const ut8 *p) {
return ((ut64)p[0]) | ((ut64)p[1] << 8) | ((ut64)p[2] << 16) | ((ut64)p[3] << 24) |
((ut64)p[4] << 32) | ((ut64)p[5] << 40) | ((ut64)p[6] << 48) | ((ut64)p[7] << 56);
}
typedef struct {
char segname[16];
@@ -38,62 +24,50 @@ typedef struct {
static bool macho_load (const char *path, MachO *mo) {
memset (mo, 0, sizeof (*mo));
int fd = open (path, O_RDONLY);
if (fd < 0) return false;
struct stat st;
if (fstat (fd, &st) != 0 || st.st_size <= 0) {
close (fd);
return false;
}
mo->filesize = (ut64) st.st_size;
mo->file = R_NEWS (ut8, mo->filesize);
if (!mo->file) {
close (fd);
return false;
}
ssize_t rd = read (fd, mo->file, (size_t) mo->filesize);
close (fd);
if (rd < 0 || (ut64) rd != mo->filesize) {
size_t sz = 0;
mo->file = (ut8 *) r_file_slurp (path, &sz);
if (!mo->file || sz == 0) {
R_FREE (mo->file);
return false;
}
ut32 magic = RD_BE32 (mo->file);
mo->filesize = (ut64) sz;
ut32 magic = r_read_be32 (mo->file);
ut64 off = 0;
if (magic == 0xcafebabe) {
ut32 nfat = RD_BE32 (mo->file + 4);
ut32 nfat = r_read_be32 (mo->file + 4);
ut32 best = 0;
for (ut32 i = 0; i < nfat; i++) {
const ut8 *fa = mo->file + 8 + i * 20;
ut32 cputype = RD_BE32 (fa + 0);
ut32 cputype = r_read_be32 (fa + 0);
if (cputype == 0x0100000c) { best = i; break; }
}
const ut8 *fa = mo->file + 8 + best * 20;
off = RD_BE32 (fa + 8);
off = r_read_be32 (fa + 8);
}
mo->base = off;
const ut8 *p = mo->file + off;
ut32 mh_magic = RD_LE32 (p);
ut32 mh_magic = r_read_le32 (p);
if (mh_magic != 0xFEEDFACF) {
R_FREE (mo->file);
return false;
}
ut32 ncmds = RD_LE32 (p + 0x10);
ut32 ncmds = r_read_le32 (p + 0x10);
mo->ncmds = ncmds;
mo->cmd_off = off + 0x20;
ut64 co = mo->cmd_off;
for (ut32 i = 0; i < ncmds && (co + 8 <= mo->filesize); i++) {
ut32 cmd = RD_LE32 (mo->file + co);
ut32 cmdsize = RD_LE32 (mo->file + co + 4);
ut32 cmd = r_read_le32 (mo->file + co);
ut32 cmdsize = r_read_le32 (mo->file + co + 4);
if (cmd == 0x19 && cmdsize >= 72) {
if (mo->nsegs < (int)(sizeof (mo->segs)/sizeof (mo->segs[0]))) {
MachSeg *s = &mo->segs[mo->nsegs++];
const ut8 *sp = mo->file + co + 8;
memcpy (s->segname, sp, 16);
s->vmaddr = RD_LE64 (sp + 16);
s->vmsize = RD_LE64 (sp + 24);
s->fileoff = RD_LE64 (sp + 32);
s->filesize = RD_LE64 (sp + 40);
s->maxprot = RD_LE32 (sp + 48);
s->vmaddr = r_read_le64 (sp + 16);
s->vmsize = r_read_le64 (sp + 24);
s->fileoff = r_read_le64 (sp + 32);
s->filesize = r_read_le64 (sp + 40);
s->maxprot = r_read_le32 (sp + 48);
if (!mo->vm_base || s->vmaddr < mo->vm_base) {
mo->vm_base = s->vmaddr;
}
@@ -176,8 +150,8 @@ R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char
const ut8 *buf = mo.file + mo.base + s->fileoff;
ut64 sz = s->filesize;
for (ut64 off = 0; off + 16 <= sz; off += 4) {
ut32 cnt1 = RD_LE32 (buf + off);
ut64 p1 = RD_LE64 (buf + off + 8);
ut32 cnt1 = r_read_le32 (buf + off);
ut64 p1 = r_read_le64 (buf + off + 8);
if (cnt1 < 32) continue;
ut32 good = 0, seen = 0;
ut32 sample = R_MIN ((ut32)128, cnt1);
@@ -185,7 +159,7 @@ R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char
const ut8 *p = macho_vm_to_ptr (&mo, p1 + (ut64)k * 8);
if (!p && mo.vm_base) { p = macho_vm_to_ptr (&mo, mo.vm_base + p1 + (ut64)k * 8); }
if (!p) break;
ut64 val = RD_LE64 (p);
ut64 val = r_read_le64 (p);
if (val) seen++;
if (val < text_lo && mo.vm_base) val += mo.vm_base;
if (val >= text_lo && val < text_hi) good++;
@@ -197,7 +171,7 @@ R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char
const ut8 *p = macho_vm_to_ptr (&mo, p1 + (ut64)m * 8);
if (!p && mo.vm_base) { p = macho_vm_to_ptr (&mo, mo.vm_base + p1 + (ut64)m * 8); }
if (!p) break;
ut64 val = RD_LE64 (p);
ut64 val = r_read_le64 (p);
if (val < text_lo && mo.vm_base) val += mo.vm_base;
if (val >= text_lo && val < text_hi) candidates[m] = val;
}
@@ -213,18 +187,18 @@ R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char
const ut8 *buf = mo.file + mo.base + s->fileoff;
ut64 sz = s->filesize;
for (ut64 off = 0; off + 16 <= sz; off += 4) {
ut32 cnt32 = RD_LE32 (buf + off);
ut32 cnt32 = r_read_le32 (buf + off);
/* stricter thresholds to avoid wrong tables */
if (cnt32 < 64) continue;
if (expected && (cnt32 > expected * 2 || cnt32 < expected / 2)) continue;
ut64 arrptr = RD_LE64 (buf + off + 8);
ut64 arrptr = r_read_le64 (buf + off + 8);
ut32 good = 0, seen = 0;
ut32 sample = R_MIN ((ut32)128, cnt32);
for (ut32 k = 0; k < sample; k++) {
const ut8 *p = macho_vm_to_ptr (&mo, arrptr + (ut64)k * (ut64)ptrsz);
if (!p && mo.vm_base) { p = macho_vm_to_ptr (&mo, mo.vm_base + arrptr + (ut64)k * (ut64)ptrsz); }
if (!p) break;
ut64 val = RD_LE64 (p);
ut64 val = r_read_le64 (p);
// Do not treat 0 as RVA; only add base when non-zero
if (val && val < text_lo && mo.vm_base && (val + mo.vm_base) >= text_lo && (val + mo.vm_base) < text_hi) {
val += mo.vm_base;
@@ -239,7 +213,7 @@ R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char
const ut8 *p = macho_vm_to_ptr (&mo, arrptr + (ut64)m * (ut64)ptrsz);
if (!p && mo.vm_base) { p = macho_vm_to_ptr (&mo, mo.vm_base + arrptr + (ut64)m * (ut64)ptrsz); }
if (!p) break;
ut64 val = RD_LE64 (p);
ut64 val = r_read_le64 (p);
if (val && val < text_lo && mo.vm_base && (val + mo.vm_base) >= text_lo && (val + mo.vm_base) < text_hi) {
val += mo.vm_base;
}