Add visibility attributes and remove unused code

This commit is contained in:
pancake committed 2025-09-18 18:20:02 +02:00
1 parent bc0478ba31
commit 0e1506b77b
6 files changed
+154 -409

No files matched your search

+2 -2
View File
@@ -2,8 +2,8 @@
# Compiler and flags
CC = gcc
CFLAGS = -Wall -Wextra -g -I./third_party/radare2/libr/include $(shell pkg-config --cflags r_core r_util 2>/dev/null || echo "")
LDFLAGS = $(shell pkg-config --libs r_core r_util 2>/dev/null || echo "")
CFLAGS = -Wall -Wextra -g -I./third_party/radare2/libr/include $(shell pkg-config --cflags r_util 2>/dev/null || echo "")
LDFLAGS = $(shell pkg-config --libs r_util 2>/dev/null || echo "")
# Project name
EXEC = r2unity
+42
View File
@@ -205,6 +205,48 @@ R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *
* use method_count computed earlier (methodsSize / sizeof(Il2CppMethodDefinition))
*/
ut32 expected = (ut32) R_MAX ((ut64)64, (ut64) ((ut64) meta->methodsSize / sizeof (Il2CppMethodDefinition)));
// Try to locate CodeRegistration-like layout first: [count, ptr] for multiple arrays
for (int i = 0; i < e.nsegs && !found; i++) {
const ElfSeg *s = &e.segs[i];
bool is_data = (s->flags & 0x1) && !(s->flags & 0x4);
if (!is_data || s->filesz < (ut64)(16 + (ut64)ptrsz * 2)) continue;
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));
ut64 p2 = (ptrsz == 8)? RD_LE64 (buf + off + (ut64)(8 + ptrsz) + 8): (ut64) RD_LE32 (buf + off + (ut64)(8 + ptrsz) + 4);
if (cnt1 < 32 || cnt2 < 16) continue;
// Sample method array
ut32 good = 0, seen = 0;
ut32 sample = R_MIN ((ut32)128, cnt1);
for (ut32 k = 0; k < sample; k++) {
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);
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++;
}
if (seen >= 8 && good >= 8) {
if (r2unity_is_debug ()) fprintf (stderr, "[r2unity/elf] codeReg p1=0x%"PFMT64x" cnt1=%u\n", p1, cnt1);
memset (candidates, 0, method_count * sizeof (ut64));
size_t tocopy = R_MIN ((size_t) cnt1, method_count);
size_t in_text = 0;
for (size_t m = 0; m < tocopy; m++) {
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 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++; }
}
if (in_text >= 8) { found = true; }
break;
}
}
}
for (int i = 0; i < e.nsegs && !found; i++) {
const ElfSeg *s = &e.segs[i];
bool is_data = (s->flags & 0x1) && !(s->flags & 0x4);
+2 -392
View File
@@ -1,8 +1,6 @@
#include "lib.h"
#include <r_util.h>
#include <r_util/r_buf.h>
#include <r_core.h>
#include <r_util/r_json.h>
#undef RD_LE32
#undef RD_LE64
static inline ut32 RD_LE32 (const ut8 *p) {
@@ -312,395 +310,7 @@ R_API Il2CppImageDefinition *r2unity_get_images (R2UnityMetadata *meta, size_t *
return imgs;
}
R_API bool r2unity_find_method_pointers (R2UnityMetadata *meta, const char *exe_path, ut64 **out_ptrs) {
if (!meta || !exe_path || !out_ptrs) {
return false;
}
*out_ptrs = NULL;
/* Try specialized fast finders first based on magic, then fall back to r2 scanning */
{
unsigned char magic[4] = {0};
FILE *fp = fopen (exe_path, "rb");
if (fp) {
(void)fread (magic, 1, 4, fp);
fclose (fp);
}
ut32 m = (ut32)magic[0] | ((ut32)magic[1] << 8) | ((ut32)magic[2] << 16) | ((ut32)magic[3] << 24);
if (magic[0] == 0x7f && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') {
if (r2unity_find_method_pointers_elf (meta, exe_path, out_ptrs)) {
return true;
}
} else if (m == 0xfeedfacf || m == 0xcffaedfe || m == 0xcafebabe || m == 0xbebafeca) {
if (r2unity_find_method_pointers_macho (meta, exe_path, out_ptrs)) {
return true;
}
}
}
RCore *core = r_core_new ();
if (!core) {
return false;
}
// apply relocs/binds/fixups
r_core_cmd0 (core, "e bin.cache=true");
r_core_cmd0 (core, "e bin.relocs.apply=true");
r_core_cmd0 (core, "e io.va=true");
if (!r_core_file_open (core, exe_path, 0, 0)) {
r_core_free (core);
return false;
}
if (!r_core_bin_load (core, NULL, 0)) {
r_core_free (core);
return false;
}
// detect pointer size
int ptrsz = 8;
char *ij = r_core_cmd_str (core, "ij");
if (ij) {
RJson *pj = r_json_parse (ij);
if (pj) {
const RJson *pbin = r_json_get (pj, "bin");
if (pbin) {
st64 bits = r_json_get_num (pbin, "bits");
ptrsz = (bits == 32)? 4: 8;
}
r_json_free (pj);
}
free (ij);
}
// compute text range and data ranges from io maps json
ut64 text_lo = UT64_MAX;
ut64 text_hi = 0;
char *omj = r_core_cmd_str (core, "omj");
RJson *jom = omj? r_json_parse (omj): NULL;
#define MAX_RANGES 128
typedef struct { ut64 from, to; } Range;
Range data_ranges[MAX_RANGES];
int data_n = 0;
if (jom && jom->type == R_JSON_ARRAY) {
for (size_t i = 0; i < jom->children.count; i++) {
const RJson *item = r_json_item (jom, i);
if (!item) continue;
const char *perm = r_json_get_str (item, "perm");
ut64 from = (ut64) r_json_get_num (item, "from");
ut64 to = (ut64) r_json_get_num (item, "to");
if (!perm) continue;
if (strchr (perm, 'x')) {
if (from < text_lo) text_lo = from;
if (to > text_hi) text_hi = to;
} else if (strchr (perm, 'r')) {
if (data_n < MAX_RANGES) {
data_ranges[data_n].from = from;
data_ranges[data_n].to = to;
data_n++;
}
}
}
}
if (jom) r_json_free (jom);
free (omj);
if (text_lo == UT64_MAX || text_hi <= text_lo) {
if (g_debug) fprintf (stderr, "[r2unity] No executable text range found.\n");
r_core_free (core);
return false;
}
size_t method_count = (ut64) meta->methodsSize / sizeof (Il2CppMethodDefinition);
if (!method_count) {
r_core_free (core);
return false;
}
// Try fast sampled window scan first instead of full sliding O(N^2)
ut64 *candidates = R_NEWS (ut64, method_count);
if (!candidates) {
r_core_free (core);
return false;
}
bool found = false;
for (int r = 0; r < data_n && !found; r++) {
ut64 start = data_ranges[r].from;
ut64 end = data_ranges[r].to;
ut64 rsize = end - start;
if (rsize < (ut64)ptrsz * 256) {
continue;
}
ut8 *rbuf = R_NEWS (ut8, rsize);
if (!rbuf) break;
r_io_vread_at (core->io, start, rbuf, rsize);
const ut64 sampleN = R_MIN ((ut64)512, (ut64)method_count);
const ut64 step = (ut64)ptrsz * 4; // stride to reduce checks
for (ut64 off = 0; off + sampleN * (ut64)ptrsz <= rsize; off += step) {
ut32 good = 0, zero = 0;
for (ut64 i = 0; i < sampleN; i++) {
ut64 val = (ptrsz == 8)
? RD_LE64 (rbuf + off + i * 8)
: (ut64) RD_LE32 (rbuf + off + i * 4);
if (!val) { zero++; continue; }
if (val >= text_lo && val < text_hi) { good++; }
}
if (good > 0 && good + zero >= (ut32)(sampleN * 9 / 10)) {
// Likely candidate; fetch full array from IO once
ut64 addr = start + off;
ut64 bytes = (ut64)method_count * (ut64)ptrsz;
ut8 *tmp = R_NEWS (ut8, bytes);
if (!tmp) { continue; }
st64 nr = r_io_vread_at (core->io, addr, tmp, bytes);
if (nr > 0) {
size_t total = (size_t)((ut64)nr / (ut64)ptrsz);
if (total > method_count) total = method_count;
ut32 g2 = 0, z2 = 0;
for (size_t i = 0; i < total; i++) {
ut64 val = (ptrsz == 8)
? RD_LE64 (tmp + (ut64)i * 8)
: (ut64) RD_LE32 (tmp + (ut64)i * 4);
candidates[i] = val;
if (!val) { z2++; continue; }
if (val >= text_lo && val < text_hi) { g2++; }
}
for (size_t i = total; i < method_count; i++) candidates[i] = 0;
if (total > 0 && g2 > 0 && g2 + z2 >= (ut32)(total * 9 / 10)) {
found = true;
R_FREE (tmp);
break;
}
}
R_FREE (tmp);
}
}
R_FREE (rbuf);
}
if (!found) {
// Try to identify CodeRegistration-like pattern: [count (u32), padding (u32), pointer (ptrsz)]
ut64 gmp_ptr = 0;
size_t gmp_cnt = 0;
for (int r = 0; r < data_n && !found; r++) {
ut64 start = data_ranges[r].from;
ut64 end = data_ranges[r].to;
ut64 rsize = end - start;
ut8 *rbuf = R_NEWS (ut8, rsize);
if (!rbuf) break;
r_io_vread_at (core->io, start, rbuf, rsize);
for (ut64 off = 0; off + (ut64)(ptrsz + 8) <= rsize; off += 4) {
ut32 cnt32 = RD_LE32 (rbuf + off);
if (cnt32 < 32) continue;
ut64 arrptr = (ptrsz == 8)
? RD_LE64 (rbuf + off + 8)
: (ut64) RD_LE32 (rbuf + off + 4);
// Check arrptr lies in a readable range
bool in_r = false;
for (int rr = 0; rr < data_n; rr++) {
if (arrptr >= data_ranges[rr].from && arrptr < data_ranges[rr].to) {
in_r = true;
break;
}
}
if (!in_r) continue;
// Sample first up to 256 entries with one bulk read
ut32 good = 0, seen = 0;
ut32 sample = R_MIN ((ut32)256, cnt32);
ut64 sbytes = (ut64)sample * (ut64)ptrsz;
ut8 *sbuf = R_NEWS (ut8, sbytes);
if (!sbuf) continue;
st64 sread = r_io_vread_at (core->io, arrptr, sbuf, sbytes);
if (sread <= 0) { R_FREE (sbuf); continue; }
ut32 sitems = (ut32)((ut64)sread / (ut64)ptrsz);
if (sitems > sample) sitems = sample;
for (ut32 i = 0; i < sitems; i++) {
ut64 val = (ptrsz == 8)
? RD_LE64 (sbuf + (ut64)i * 8)
: (ut64) RD_LE32 (sbuf + (ut64)i * 4);
if (val) seen++;
if (val >= text_lo && val < text_hi) good++;
}
R_FREE (sbuf);
if (sitems >= 32 && good >= 8 && seen >= 8) {
if (g_debug) fprintf (stderr, "[r2unity] gmp-like arrptr=0x%"PFMT64x" cnt=%u sample=%u good=%u seen=%u\n", arrptr, cnt32, sitems, good, seen);
gmp_ptr = arrptr;
gmp_cnt = cnt32;
found = true;
break;
}
}
R_FREE (rbuf);
}
if (found && gmp_ptr) {
// Read array at gmp_ptr
size_t maxc = method_count;
memset (candidates, 0, method_count * sizeof (ut64));
ut64 bytes = (ut64) R_MIN (maxc, gmp_cnt) * (ut64) ptrsz;
ut8 *tmp = R_NEWS (ut8, bytes);
if (tmp) {
st64 nr = r_io_vread_at (core->io, gmp_ptr, tmp, bytes);
size_t total = (nr > 0)? (size_t)((ut64)nr / (ut64)ptrsz): 0;
if (total > R_MIN (maxc, gmp_cnt)) total = R_MIN (maxc, gmp_cnt);
for (size_t i = 0; i < total; i++) {
candidates[i] = (ptrsz == 8)
? RD_LE64 (tmp + (ut64)i * 8)
: (ut64) RD_LE32 (tmp + (ut64)i * 4);
}
R_FREE (tmp);
}
}
}
if (!found) {
// Fallback: find the longest run of pointers into text (or zero) – use as prefix
ut64 best_start = 0;
size_t best_len = 0;
size_t max_probe = R_MIN ((size_t)65536, (size_t)method_count);
for (int r = 0; r < data_n; r++) {
ut64 start = data_ranges[r].from;
ut64 end = data_ranges[r].to;
ut64 rsize = end - start;
ut8 *rbuf = R_NEWS (ut8, rsize);
if (!rbuf) break;
r_io_vread_at (core->io, start, rbuf, rsize);
for (ut64 off = 0; off + (ut64)(ptrsz * 16) <= rsize; off += ptrsz) {
size_t run = 0;
for (; run < max_probe; run++) {
ut64 val = (ptrsz == 8)
? RD_LE64 (rbuf + off + (ut64)run * 8)
: (ut64) RD_LE32 (rbuf + off + (ut64)run * 4);
if (!val) {
// allow zeros in the run
continue;
}
if (!(val >= text_lo && val < text_hi)) {
break;
}
}
if (run > best_len) {
best_len = run;
best_start = start + off;
}
}
R_FREE (rbuf);
}
if (best_len > 0) {
if (g_debug) fprintf (stderr, "[r2unity] fallback run best_start=0x%"PFMT64x" best_len=%u\n", best_start, (unsigned)best_len);
// Read best_len pointers in one shot into prefix of candidates, rest zeros
memset (candidates, 0, method_count * sizeof (ut64));
ut64 bytes = (ut64)best_len * (ut64)ptrsz;
ut8 *tmp = R_NEWS (ut8, bytes);
if (tmp) {
st64 nr = r_io_vread_at (core->io, best_start, tmp, bytes);
if (nr > 0) {
size_t total = (size_t)((ut64)nr / (ut64)ptrsz);
if (total > best_len) total = best_len;
for (size_t i = 0; i < total; i++) {
candidates[i] = (ptrsz == 8)
? RD_LE64 (tmp + (ut64)i * 8)
: (ut64) RD_LE32 (tmp + (ut64)i * 4);
}
}
R_FREE (tmp);
}
found = true;
}
}
if (!found) {
R_FREE (candidates);
r_core_free (core);
return false;
}
// Sanitize: zero out any pointer not pointing into text
for (size_t i = 0; i < method_count; i++) {
ut64 v = candidates[i];
if (!v) continue;
if (!(v >= text_lo && v < text_hi)) {
candidates[i] = 0;
}
}
*out_ptrs = candidates;
r_core_free (core);
return true;
}
R_API bool r2unity_read_method_pointers_at (R2UnityMetadata *meta, const char *exe_path, ut64 addr, size_t count, ut64 **out_ptrs) {
if (!meta || !exe_path || !out_ptrs || !addr) {
return false;
}
*out_ptrs = NULL;
RCore *core = r_core_new ();
if (!core) {
return false;
}
r_core_cmd0 (core, "e bin.cache=true");
r_core_cmd0 (core, "e bin.relocs.apply=true");
if (!r_core_file_open (core, exe_path, 0, 0)) {
r_core_free (core);
return false;
}
if (!r_core_bin_load (core, NULL, 0)) {
r_core_free (core);
return false;
}
int ptrsz = 8;
char *ij = r_core_cmd_str (core, "ij");
if (ij) {
RJson *pj = r_json_parse (ij);
if (pj) {
const RJson *pbin = r_json_get (pj, "bin");
if (pbin) {
st64 bits = r_json_get_num (pbin, "bits");
ptrsz = (bits == 32)? 4: 8;
}
r_json_free (pj);
}
free (ij);
}
size_t method_count = (ut64) meta->methodsSize / sizeof (Il2CppMethodDefinition);
if (!method_count) {
r_core_free (core);
return false;
}
if (!count || count > method_count) {
count = method_count;
}
ut64 *ptrs = R_NEWS (ut64, method_count);
if (!ptrs) {
r_core_free (core);
return false;
}
memset (ptrs, 0, method_count * sizeof (ut64));
ut64 bytes = (ut64) count * (ut64) ptrsz;
ut8 *tmp = R_NEWS (ut8, bytes);
if (tmp) {
st64 nr = r_io_vread_at (core->io, addr, tmp, bytes);
size_t total = (nr > 0)? (size_t)((ut64)nr / (ut64)ptrsz): 0;
if (total > count) total = count;
for (size_t i = 0; i < total; i++) {
ptrs[i] = (ptrsz == 8)
? RD_LE64 (tmp + (ut64)i * 8)
: (ut64) RD_LE32 (tmp + (ut64)i * 4);
}
R_FREE (tmp);
}
// Sanitize out-of-text pointers
ut64 text_lo = UT64_MAX, text_hi = 0;
char *omj = r_core_cmd_str (core, "omj");
RJson *jom = omj? r_json_parse (omj): NULL;
if (jom && jom->type == R_JSON_ARRAY) {
for (size_t i = 0; i < jom->children.count; i++) {
const RJson *item = r_json_item (jom, i);
if (!item) continue;
const char *perm = r_json_get_str (item, "perm");
ut64 from = (ut64) r_json_get_num (item, "from");
ut64 to = (ut64) r_json_get_num (item, "to");
if (!perm) continue;
if (strchr (perm, 'x')) {
if (from < text_lo) text_lo = from;
if (to > text_hi) text_hi = to;
}
}
}
if (jom) r_json_free (jom);
free (omj);
if (text_lo != UT64_MAX && text_hi > text_lo) {
for (size_t i = 0; i < count; i++) {
ut64 v = ptrs[i];
if (!v) continue;
if (!(v >= text_lo && v < text_hi)) ptrs[i] = 0;
}
}
*out_ptrs = ptrs;
r_core_free (core);
return true;
(void) meta; (void) exe_path; (void) addr; (void) count; (void) out_ptrs;
return false;
}
+1 -1
View File
@@ -296,7 +296,7 @@ R_API const char *r2unity_get_string (R2UnityMetadata *meta, uint32_t index);
R_API Il2CppTypeDefinition *r2unity_get_type_definitions (R2UnityMetadata *meta, size_t *count);
R_API Il2CppMethodDefinition *r2unity_get_method_definitions (R2UnityMetadata *meta, size_t *count);
R_API Il2CppImageDefinition *r2unity_get_images (R2UnityMetadata *meta, size_t *count);
R_API bool r2unity_find_method_pointers (R2UnityMetadata *meta, const char *exe_path, ut64 **out_ptrs);
/* Simplified API: use format-specific finders, or manual read stub. */
R_API bool r2unity_read_method_pointers_at (R2UnityMetadata *meta, const char *exe_path, ut64 addr, size_t count, ut64 **out_ptrs);
R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char *macho_path, ut64 **out_ptrs);
R_API bool r2unity_find_method_pointers_elf (R2UnityMetadata *meta, const char *elf_path, ut64 **out_ptrs);
+38
View File
@@ -168,6 +168,44 @@ R_API bool r2unity_find_method_pointers_macho (R2UnityMetadata *meta, const char
bool found = false;
int ptrsz = 8;
ut32 expected = (ut32) R_MAX ((ut64)64, (ut64) ((ut64) meta->methodsSize / sizeof (Il2CppMethodDefinition)));
// Try CodeRegistration-like pairs first
for (int i = 0; i < mo.nsegs && !found; i++) {
MachSeg *s = &mo.segs[i];
bool is_data = (s->maxprot & 0x1) && !(s->maxprot & 0x4);
if (!is_data || s->filesize < (16 + 8)) continue;
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);
if (cnt1 < 32) continue;
ut32 good = 0, seen = 0;
ut32 sample = R_MIN ((ut32)128, cnt1);
for (ut32 k = 0; k < sample; k++) {
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);
if (val) seen++;
if (val < text_lo && mo.vm_base) val += mo.vm_base;
if (val >= text_lo && val < text_hi) good++;
}
if (seen >= 8 && good >= 8) {
if (r2unity_is_debug ()) fprintf (stderr, "[r2unity/macho] codeReg p1=0x%"PFMT64x" cnt1=%u\n", p1, cnt1);
memset (candidates, 0, method_count * sizeof (ut64));
for (size_t m = 0; m < method_count && m < cnt1; m++) {
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);
if (val < text_lo && mo.vm_base) val += mo.vm_base;
if (val >= text_lo && val < text_hi) candidates[m] = val;
}
found = true;
break;
}
}
}
for (int i = 0; i < mo.nsegs && !found; i++) {
MachSeg *s = &mo.segs[i];
bool is_data = (s->maxprot & 0x1) && !(s->maxprot & 0x4);
+69 -14
View File
@@ -3,6 +3,57 @@
#include <string.h>
#include "lib/lib.h"
static void build_method_attrs_string (char *o, size_t osz, unsigned int flags) {
/* System.Reflection.MethodAttributes subset */
const unsigned int MemberAccessMask = 0x0007;
const unsigned int MdPrivate = 0x0001;
const unsigned int MdFamANDAssem = 0x0002; /* private protected */
const unsigned int MdAssembly = 0x0003; /* internal */
const unsigned int MdFamily = 0x0004; /* protected */
const unsigned int MdFamORAssem = 0x0005; /* protected internal */
const unsigned int MdPublic = 0x0006;
const unsigned int MdStatic = 0x0010;
const unsigned int MdFinal = 0x0020;
const unsigned int MdVirtual = 0x0040;
const unsigned int MdAbstract = 0x0400;
const char *vis = "";
switch (flags & MemberAccessMask) {
case MdPublic: vis = "public"; break;
case MdFamily: vis = "protected"; break;
case MdAssembly: vis = "internal"; break;
case MdFamORAssem: vis = "protected internal"; break;
case MdFamANDAssem: vis = "private protected"; break;
case MdPrivate: vis = "private"; break;
default: vis = ""; break;
}
char tmp[128]; tmp[0] = 0;
if (*vis) {
strncat (tmp, vis, sizeof (tmp) - 1);
}
if (flags & MdStatic) {
if (*tmp) strncat (tmp, " ", sizeof (tmp) - 1);
strncat (tmp, "static", sizeof (tmp) - 1);
}
if (flags & MdAbstract) {
if (*tmp) strncat (tmp, " ", sizeof (tmp) - 1);
strncat (tmp, "abstract", sizeof (tmp) - 1);
}
if (flags & MdVirtual) {
if (*tmp) strncat (tmp, " ", sizeof (tmp) - 1);
strncat (tmp, "virtual", sizeof (tmp) - 1);
}
if (flags & MdFinal) {
if (*tmp) strncat (tmp, " ", sizeof (tmp) - 1);
strncat (tmp, "final", sizeof (tmp) - 1);
}
if (!*tmp) {
strncpy (o, "", osz);
} else {
strncpy (o, tmp, osz);
o[osz? osz - 1: 0] = 0;
}
}
static void print_usage (const char *prog_name) {
fprintf (stderr, "Usage: %s [--json-one-line] [--quiet] [-l N] [--fast] [--gmp-addr 0xADDR] [--gmp-count N] [-v|--debug] <executable> <path/to/global-metadata.dat>\n", prog_name);
}
@@ -91,22 +142,13 @@ int main (int argc, char *argv[]) {
ut32 m = (ut32)magic[0] | ((ut32)magic[1] << 8) | ((ut32)magic[2] << 16) | ((ut32)magic[3] << 24);
if (magic[0] == 0x7f && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') {
has_ptrs = r2unity_find_method_pointers_elf (meta, exe_path, &method_ptrs);
if (!has_ptrs) {
/* Fallback to r2-based */
has_ptrs = r2unity_find_method_pointers (meta, exe_path, &method_ptrs);
}
} else if (m == 0xfeedfacf || m == 0xcffaedfe || m == 0xcafebabe || m == 0xbebafeca) {
has_ptrs = r2unity_find_method_pointers_macho (meta, exe_path, &method_ptrs);
if (!has_ptrs) {
/* Fallback to r2-based */
has_ptrs = r2unity_find_method_pointers (meta, exe_path, &method_ptrs);
}
} else {
/* Fallback to r2-based */
has_ptrs = r2unity_find_method_pointers (meta, exe_path, &method_ptrs);
has_ptrs = false;
}
} else {
has_ptrs = r2unity_find_method_pointers (meta, exe_path, &method_ptrs);
has_ptrs = false;
}
// Recompute has_ptrs by checking any non-zero entry
if (method_ptrs) {
@@ -192,15 +234,28 @@ int main (int argc, char *argv[]) {
char *im = (char *) r2unity_get_string (meta, images[ii].nameIndex);
if (im && *im) {
printf ("'@0x%"PFMT64x"'f sym.unity.%s.%s\n", addr, im, fullname);
printf ("'@0x%"PFMT64x"'CCu Method: [%s] %s\n", addr, im, fullname);
char attrs[128]; attrs[0] = 0; build_method_attrs_string (attrs, sizeof (attrs), m->flags);
if (*attrs) {
printf ("'@0x%"PFMT64x"'CCu Method: [%s] %s %s\n", addr, im, attrs, fullname);
} else {
printf ("'@0x%"PFMT64x"'CCu Method: [%s] %s\n", addr, im, fullname);
}
free (im);
} else {
printf ("'@0x%"PFMT64x"'f sym.unity.%s\n", addr, fullname);
printf ("'@0x%"PFMT64x"'CCu Method: %s\n", addr, fullname);
char attrs2[128]; attrs2[0] = 0; build_method_attrs_string (attrs2, sizeof (attrs2), m->flags);
if (*attrs2) {
printf ("'@0x%"PFMT64x"'CCu Method: %s %s\n", addr, attrs2, fullname);
} else {
printf ("'@0x%"PFMT64x"'CCu Method: %s\n", addr, fullname);
}
}
} else {
printf ("'@0x%"PFMT64x"'f sym.unity.%s\n", addr, fullname);
printf ("'@0x%"PFMT64x"'CCu Method: %s\n", addr, fullname);
char attrs3[128]; attrs3[0] = 0; build_method_attrs_string (attrs3, sizeof (attrs3), m->flags);
if (*attrs3) {
printf ("'@0x%"PFMT64x"'CCu Method: %s\n", addr, attrs3);
}
}
} else {
printf ("# %s\n", fullname);