mirror of
https://github.com/radareorg/r2unity.git
synced 2026-11-07 06:36:00 -10:00
Use RRead APIs instead of shipping our ones
This commit is contained in:
1 parent
2b39ebd659
commit
43b593bda2
3 files changed
+117
-176
No files matched your search
+42
-62
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user