From 0e1506b77bb7598e957fc219a37645a4b0a8bed2 Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 18 Sep 2025 18:20:02 +0200 Subject: [PATCH] Add visibility attributes and remove unused code --- Makefile | 4 +- src/lib/elf.c | 42 ++++++ src/lib/lib.c | 394 +----------------------------------------------- src/lib/lib.h | 2 +- src/lib/macho.c | 38 +++++ src/main.c | 83 ++++++++-- 6 files changed, 154 insertions(+), 409 deletions(-) diff --git a/Makefile b/Makefile index 3184846..8e08897 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/lib/elf.c b/src/lib/elf.c index 337a833..68bb2e0 100644 --- a/src/lib/elf.c +++ b/src/lib/elf.c @@ -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); diff --git a/src/lib/lib.c b/src/lib/lib.c index eb23cd0..7142310 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -1,8 +1,6 @@ #include "lib.h" #include #include -#include -#include #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; } diff --git a/src/lib/lib.h b/src/lib/lib.h index 248892b..64b4c8d 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -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); diff --git a/src/lib/macho.c b/src/lib/macho.c index 25eedef..10566a0 100644 --- a/src/lib/macho.c +++ b/src/lib/macho.c @@ -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); diff --git a/src/main.c b/src/main.c index bc5ccb8..84c534b 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,57 @@ #include #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] \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);