diff --git a/src/lib/lib.c b/src/lib/lib.c index c0647bc..ec8b97a 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -576,6 +576,75 @@ R_API char *r2unity_get_string(R2UnityMetadata *meta, uint32_t index) { return str; } +R_API char *r2unity_type_fullname(R2UnityMetadata *meta, const Il2CppTypeDefinition *td, size_t type_idx, int flags) { + R_RETURN_VAL_IF_FAIL (meta, NULL); + if (!td) { + return NULL; + } + char *ns = r2unity_get_string (meta, td->namespaceIndex); + char *tn = r2unity_get_string (meta, td->nameIndex); + char *out = NULL; + if (ns && *ns && tn && *tn) { + out = r_str_newf ("%s.%s", ns, tn); + } else if (tn && *tn) { + out = strdup (tn); + } else if (flags & R2U_NAME_FALLBACK_TYPE) { + out = r_str_newf ("type.%zu", type_idx); + } + free (ns); + free (tn); + return out; +} + +R_API char *r2unity_method_fullname(R2UnityMetadata *meta, const Il2CppMethodDefinition *m, const Il2CppTypeDefinition *td, size_t type_idx, int flags) { + R_RETURN_VAL_IF_FAIL (meta && m, NULL); + char *mn = r2unity_get_string (meta, m->nameIndex); + if (!mn) { + return NULL; + } + char *out = NULL; + if (flags & R2U_NAME_FALLBACK_TYPE) { + const bool with_params = flags & R2U_NAME_WITH_PARAMS; + char *owner = r2unity_type_fullname (meta, td, type_idx, flags); + if (owner && *owner) { + out = with_params + ? r_str_newf ("%s.%s(%u)", owner, mn, (unsigned)m->parameterCount) + : r_str_newf ("%s.%s", owner, mn); + } else { + out = with_params + ? r_str_newf ("%s(%u)", mn, (unsigned)m->parameterCount) + : strdup (mn); + } + free (owner); + free (mn); + return out; + } + + char *ns = td? r2unity_get_string (meta, td->namespaceIndex): NULL; + char *tn = td? r2unity_get_string (meta, td->nameIndex): NULL; + if (flags & R2U_NAME_WITH_PARAMS) { + if (ns && *ns) { + out = r_str_newf ("%s.%s.%s(%u)", ns, tn? tn: "", mn, (unsigned)m->parameterCount); + } else if (tn && *tn) { + out = r_str_newf ("%s.%s(%u)", tn, mn, (unsigned)m->parameterCount); + } else { + out = r_str_newf ("%s(%u)", mn, (unsigned)m->parameterCount); + } + } else { + if (ns && *ns && tn && *tn) { + out = r_str_newf ("%s.%s.%s", ns, tn, mn); + } else if (tn && *tn) { + out = r_str_newf ("%s.%s", tn, mn); + } else { + out = strdup (mn); + } + } + free (ns); + free (tn); + free (mn); + return out; +} + R_API Il2CppStringLiteral *r2unity_get_string_literals(R2UnityMetadata *meta, size_t *count) { R_RETURN_VAL_IF_FAIL (meta && count, NULL); *count = 0; @@ -900,9 +969,7 @@ static int cmp_tokidx(const void *a, const void *b) { return (ta < tb)? -1: (ta > tb); } -/* Build a typeIndex -> imageIndex map once per enumeration pass. Returns NULL - * if no images are known or the type table is empty. */ -static int *build_type2img(const Il2CppImageDefinition *images, size_t image_count, size_t type_count) { +R_API int *r2unity_build_type_image_map(const Il2CppImageDefinition *images, size_t image_count, size_t type_count) { if (!images || !type_count) { return NULL; } @@ -926,39 +993,14 @@ static int *build_type2img(const Il2CppImageDefinition *images, size_t image_cou return type2img; } -/* Resolve the owning image (DLL) of a given method via its declaring type. */ -static int image_index_for_method(const int *type2img, size_t type_count, const Il2CppMethodDefinition *m) { +R_API int r2unity_image_index_for_method(const int *type2img, size_t type_count, const Il2CppMethodDefinition *m) { + R_RETURN_VAL_IF_FAIL (m, -1); if (!type2img || m->declaringType < 0 || (size_t)m->declaringType >= type_count) { return -1; } return type2img[m->declaringType]; } -static char *build_qualified_name(R2UnityMetadata *meta, - const Il2CppTypeDefinition *td, - uint32_t method_name_idx) { - char *ns = td? r2unity_get_string (meta, td->namespaceIndex): NULL; - char *tn = td? r2unity_get_string (meta, td->nameIndex): NULL; - char *mn = r2unity_get_string (meta, method_name_idx); - if (!mn) { - free (ns); - free (tn); - return NULL; - } - char *out; - if (ns && *ns && tn && *tn) { - out = r_str_newf ("%s.%s.%s", ns, tn, mn); - } else if (tn && *tn) { - out = r_str_newf ("%s.%s", tn, mn); - } else { - out = strdup (mn); - } - free (ns); - free (tn); - free (mn); - return out; -} - /* Shared context for P/Invoke and reverse P/Invoke enumeration. */ typedef struct { R2UnityMetadata *meta; @@ -980,7 +1022,7 @@ static bool interop_ctx_init(InteropCtx *c, R2UnityMetadata *meta) { } c->types = r2unity_get_type_definitions (meta, &c->type_count); c->images = r2unity_get_images (meta, &c->image_count); - c->type2img = build_type2img (c->images, c->image_count, c->type_count); + c->type2img = r2unity_build_type_image_map (c->images, c->image_count, c->type_count); return true; } @@ -1006,9 +1048,9 @@ static void interop_fill(R2UnityInterop *it, const InteropCtx *c, int32_t method if (c->types && m->declaringType >= 0 && (size_t)m->declaringType < c->type_count) { td = &c->types[m->declaringType]; } - it->name = build_qualified_name (c->meta, td, m->nameIndex); + it->name = r2unity_method_fullname (c->meta, m, td, (size_t)m->declaringType, 0); - int img_idx = image_index_for_method (c->type2img, c->type_count, m); + int img_idx = r2unity_image_index_for_method (c->type2img, c->type_count, m); it->image_index = img_idx; if (img_idx >= 0 && c->images && (size_t)img_idx < c->image_count) { it->image_name = r2unity_get_string (c->meta, c->images[img_idx].nameIndex); @@ -1220,7 +1262,7 @@ static bool tokindex_build(TokIndex *t, const InteropCtx *c) { return false; } for (size_t j = 0; j < c->method_count; j++) { - int ii = image_index_for_method (c->type2img, c->type_count, &c->methods[j]); + int ii = r2unity_image_index_for_method (c->type2img, c->type_count, &c->methods[j]); if (ii < 0 || (size_t)ii >= c->image_count || !c->methods[j].token) { continue; } @@ -1233,7 +1275,7 @@ static bool tokindex_build(TokIndex *t, const InteropCtx *c) { t->count[ii] = 0; } for (size_t j = 0; j < c->method_count; j++) { - int ii = image_index_for_method (c->type2img, c->type_count, &c->methods[j]); + int ii = r2unity_image_index_for_method (c->type2img, c->type_count, &c->methods[j]); if (ii < 0 || (size_t)ii >= c->image_count || !c->methods[j].token) { continue; } diff --git a/src/lib/lib.h b/src/lib/lib.h index 3edf364..d059b24 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -183,15 +183,24 @@ typedef struct { uint8_t confidence; /* 0..100 */ } R2UnityInterop; +typedef enum { + R2U_NAME_WITH_PARAMS = 1, + R2U_NAME_FALLBACK_TYPE = 2 +} R2UnityNameFlags; + R_API R2UnityMetadata *r2unity_parse_metadata(RBuffer *buf); R_API void r2unity_free_metadata(R2UnityMetadata *meta); /* Caller owns the returned string and must free() it. NULL on missing/empty. */ R_API char *r2unity_get_string(R2UnityMetadata *meta, uint32_t index); +R_API char *r2unity_type_fullname(R2UnityMetadata *meta, const Il2CppTypeDefinition *td, size_t type_idx, int flags); +R_API char *r2unity_method_fullname(R2UnityMetadata *meta, const Il2CppMethodDefinition *m, const Il2CppTypeDefinition *td, size_t type_idx, int flags); R_API Il2CppStringLiteral *r2unity_get_string_literals(R2UnityMetadata *meta, size_t *count); R_API bool r2unity_read_string_literal(R2UnityMetadata *meta, const Il2CppStringLiteral *lit, ut8 **out_bytes, size_t *out_len); 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 int *r2unity_build_type_image_map(const Il2CppImageDefinition *images, size_t image_count, size_t type_count); +R_API int r2unity_image_index_for_method(const int *type2img, size_t type_count, const Il2CppMethodDefinition *m); R_API Il2CppAssemblyDefinition *r2unity_get_assemblies(R2UnityMetadata *meta, size_t *count); R_API int32_t *r2unity_get_referenced_assemblies(R2UnityMetadata *meta, size_t *count); R_API R2UnityInterop *r2unity_enumerate_pinvokes(R2UnityMetadata *meta, size_t *count); diff --git a/src/main.c b/src/main.c index 6723f02..be868cb 100644 --- a/src/main.c +++ b/src/main.c @@ -602,33 +602,21 @@ static bool find_method_pointers_fast(R2UnityMetadata *meta, const char *path, u static bool emit_r2_method(R2UnityMetadata *meta, const Il2CppMethodDefinition *m, const Il2CppTypeDefinition *td, + size_t type_idx, const Il2CppImageDefinition *img, bool have_img_map, ut64 addr) { if (addr <= 0x1000) { return false; } - char *mn = r2unity_get_string (meta, m->nameIndex); - if (!mn) { + char *fullname = r2unity_method_fullname (meta, m, td, type_idx, R2U_NAME_WITH_PARAMS); + if (!fullname) { return false; } - char *ns = td? r2unity_get_string (meta, td->namespaceIndex): NULL; - char *tn = td? r2unity_get_string (meta, td->nameIndex): NULL; - char fullname[1024]; - unsigned pc = (unsigned)m->parameterCount; - if (ns && *ns) { - snprintf (fullname, sizeof (fullname), "%s.%s.%s(%u)", ns, tn? tn: "", mn, pc); - } else if (tn && *tn) { - snprintf (fullname, sizeof (fullname), "%s.%s(%u)", tn, mn, pc); - } else { - snprintf (fullname, sizeof (fullname), "%s(%u)", mn, pc); - } - free (ns); - free (tn); - free (mn); /* No image map context: fall back to a plain comment. */ if (!have_img_map || !td) { printf ("# %s\n", fullname); + free (fullname); return true; } r_name_filter (fullname, -1); @@ -657,6 +645,7 @@ static bool emit_r2_method(R2UnityMetadata *meta, } free (im); free (attrs); + free (fullname); return true; } @@ -826,25 +815,9 @@ int main(int argc, char *argv[]) { printf ("# Input file: %s\n\n", metadata_path); } - /* Build a typeIndex -> imageIndex map so method output can be prefixed with - * the owning DLL name. Keep method_ptrs 1:1 with method_definitions — gaps - *(zeros) are expected for abstract/generic/external methods. */ size_t img_count = 0; Il2CppImageDefinition *images = r2unity_get_images (meta, &img_count); - int *type2img = NULL; - if (images && type_count > 0) { - type2img = R_NEWS (int, type_count); - for (size_t ti = 0; ti < type_count; ti++) { - type2img[ti] = -1; - } - for (size_t ii = 0; ii < img_count; ii++) { - int start = images[ii].typeStart; - int count = (int)images[ii].typeCount; - for (int k = 0; k < count && start >= 0 && (size_t) (start + k) < type_count; k++) { - type2img[start + k] = (int)ii; - } - } - } + int *type2img = r2unity_build_type_image_map (images, img_count, type_count); long printed = 0; if (methods && types) { @@ -854,18 +827,18 @@ int main(int argc, char *argv[]) { } Il2CppMethodDefinition *m = &methods[j]; const Il2CppTypeDefinition *td = NULL; + size_t type_idx = 0; if (m->declaringType >= 0 && (size_t)m->declaringType < type_count) { + type_idx = (size_t)m->declaringType; td = &types[m->declaringType]; } ut64 addr = (has_ptrs && method_ptrs)? method_ptrs[j]: 0; const Il2CppImageDefinition *img = NULL; - if (type2img && td) { - int ii = type2img[m->declaringType]; - if (ii >= 0 && (size_t)ii < img_count) { - img = &images[ii]; - } + int ii = r2unity_image_index_for_method (type2img, type_count, m); + if (ii >= 0 && (size_t)ii < img_count) { + img = &images[ii]; } - if (emit_r2_method (meta, m, td, img, type2img != NULL, addr)) { + if (emit_r2_method (meta, m, td, type_idx, img, type2img != NULL, addr)) { printed++; } } diff --git a/src/r2/bin_r2unity.c b/src/r2/bin_r2unity.c index d402345..09ba68c 100644 --- a/src/r2/bin_r2unity.c +++ b/src/r2/bin_r2unity.c @@ -343,42 +343,6 @@ static RBinAttribute type_attr(uint32_t flags) { return attr; } -static char *type_fullname(R2UnityBinObj *obj, const Il2CppTypeDefinition *td, size_t idx) { - char *ns = td? get_string (obj, td->namespaceIndex): NULL; - char *tn = td? get_string (obj, td->nameIndex): NULL; - char *out; - if (ns && *ns && tn && *tn) { - out = r_str_newf ("%s.%s", ns, tn); - } else if (tn && *tn) { - out = strdup (tn); - } else { - out = r_str_newf ("type.%zu", idx); - } - free (ns); - free (tn); - return out; -} - -static char *method_fullname(R2UnityBinObj *obj, - const Il2CppMethodDefinition *m, - const Il2CppTypeDefinition *types, - size_t type_count) { - char *mn = get_string (obj, m->nameIndex); - if (!mn) { - return NULL; - } - char *owner = NULL; - if (m->declaringType >= 0 && (size_t)m->declaringType < type_count) { - owner = type_fullname (obj, &types[m->declaringType], (size_t)m->declaringType); - } - char *out = owner && *owner - ? r_str_newf ("%s.%s(%u)", owner, mn, (unsigned)m->parameterCount) - : r_str_newf ("%s(%u)", mn, (unsigned)m->parameterCount); - free (owner); - free (mn); - return out; -} - static RBinSymbol *new_symbol(const char *name, ut64 paddr, ut64 size, const char *type, RBinAttribute attr, const char *classname, int ordinal) { RBinSymbol *sym = r_bin_symbol_new (name, paddr, paddr); if (!sym) { @@ -491,7 +455,7 @@ static bool symbols_fill(RBinFile *bf, R2UnitySymbolSink *ret) { Il2CppMetadataSection type_sec; r2unity_metadata_section (meta, R2U_SEC_TYPE_DEFINITIONS, &type_sec); for (size_t i = 0; types && i < type_count; i++) { - char *name = type_fullname (obj, &types[i], i); + char *name = r2unity_type_fullname (meta, &types[i], i, R2U_NAME_FALLBACK_TYPE); RBinSymbol *sym = new_symbol (name, type_sec.offset + i * type_entry, type_entry, R_BIN_TYPE_OBJECT_STR, type_attr (types[i].flags), NULL, ordinal++); append_symbol (ret, sym); free (name); @@ -503,14 +467,20 @@ static bool symbols_fill(RBinFile *bf, R2UnitySymbolSink *ret) { Il2CppMetadataSection method_sec; r2unity_metadata_section (meta, R2U_SEC_METHODS, &method_sec); for (size_t i = 0; methods && i < method_count; i++) { - char *name = method_fullname (obj, &methods[i], types, type_count); + const Il2CppTypeDefinition *td = NULL; + size_t type_idx = 0; + if (methods[i].declaringType >= 0 && (size_t)methods[i].declaringType < type_count) { + type_idx = (size_t)methods[i].declaringType; + td = &types[type_idx]; + } + char *name = r2unity_method_fullname (meta, &methods[i], td, type_idx, R2U_NAME_WITH_PARAMS | R2U_NAME_FALLBACK_TYPE); if (!name) { continue; } char *mn = get_string (obj, methods[i].nameIndex); char *classname = NULL; - if (methods[i].declaringType >= 0 && (size_t)methods[i].declaringType < type_count) { - classname = type_fullname (obj, &types[methods[i].declaringType], (size_t)methods[i].declaringType); + if (td) { + classname = r2unity_type_fullname (meta, td, type_idx, R2U_NAME_FALLBACK_TYPE); } RBinSymbol *sym = new_symbol (name, method_sec.offset + i * method_entry, method_entry, R_BIN_TYPE_METH_STR, method_attr (methods[i].flags, mn), classname, ordinal++); append_symbol (ret, sym); @@ -578,7 +548,13 @@ static RList *classes(RBinFile *bf) { int count = types[i].method_count; for (int k = 0; methods && k < count && start >= 0 && (size_t)(start + k) < method_count; k++) { size_t mi = (size_t)(start + k); - char *mname = method_fullname (obj, &methods[mi], types, type_count); + const Il2CppTypeDefinition *td = &types[i]; + size_t type_idx = i; + if (methods[mi].declaringType >= 0 && (size_t)methods[mi].declaringType < type_count) { + type_idx = (size_t)methods[mi].declaringType; + td = &types[type_idx]; + } + char *mname = r2unity_method_fullname (meta, &methods[mi], td, type_idx, R2U_NAME_WITH_PARAMS | R2U_NAME_FALLBACK_TYPE); char *raw = get_string (obj, methods[mi].nameIndex); RBinSymbol *sym = new_symbol (mname? mname: raw, method_sec.offset + mi * method_entry, method_entry, R_BIN_TYPE_METH_STR, method_attr (methods[mi].flags, raw), NULL, (int)mi); append_class_method (klass, sym); diff --git a/src/r2/core_r2unity.c b/src/r2/core_r2unity.c index 1b03b84..703c676 100644 --- a/src/r2/core_r2unity.c +++ b/src/r2/core_r2unity.c @@ -284,31 +284,6 @@ static bool find_method_pointers(R2UnityMetadata *meta, const char *path, ut64 * return false; } -/* Build the fully-qualified method name "Ns.Class.Method(argc)". Caller owns. */ -static char *build_method_fullname(R2UnityMetadata *meta, - const Il2CppMethodDefinition *m, - const Il2CppTypeDefinition *td) { - char *mn = r2unity_get_string (meta, m->nameIndex); - if (!mn) { - return NULL; - } - char *ns = td? r2unity_get_string (meta, td->namespaceIndex): NULL; - char *tn = td? r2unity_get_string (meta, td->nameIndex): NULL; - unsigned pc = (unsigned)m->parameterCount; - char *out = NULL; - if (ns && *ns) { - out = r_str_newf ("%s.%s.%s(%u)", ns, tn? tn: "", mn, pc); - } else if (tn && *tn) { - out = r_str_newf ("%s.%s(%u)", tn, mn, pc); - } else { - out = r_str_newf ("%s(%u)", mn, pc); - } - free (ns); - free (tn); - free (mn); - return out; -} - /* ---------- r2unity-s (methods) ---------- */ static int cmd_symbols(RCore *core, char mode) { /* mode: 0 = apply to r2 session, '*' = print r2 commands, 'j' = JSON */ @@ -340,20 +315,7 @@ static int cmd_symbols(RCore *core, char mode) { } } - int *type2img = NULL; - if (images && type_count > 0) { - type2img = R_NEWS (int, type_count); - for (size_t ti = 0; ti < type_count; ti++) { - type2img[ti] = -1; - } - for (size_t ii = 0; ii < img_count; ii++) { - int start = images[ii].typeStart; - int count = (int)images[ii].typeCount; - for (int k = 0; k < count && start >= 0 && (size_t) (start + k) < type_count; k++) { - type2img[start + k] = (int)ii; - } - } - } + int *type2img = r2unity_build_type_image_map (images, img_count, type_count); PJ *pj = NULL; if (mode == 'j') { @@ -369,18 +331,18 @@ static int cmd_symbols(RCore *core, char mode) { for (size_t j = 0; j < method_count; j++) { Il2CppMethodDefinition *m = &methods[j]; const Il2CppTypeDefinition *td = NULL; + size_t type_idx = 0; if (m->declaringType >= 0 && (size_t)m->declaringType < type_count) { + type_idx = (size_t)m->declaringType; td = &types[m->declaringType]; } ut64 addr = (has_ptrs && method_ptrs)? method_ptrs[j]: 0; const Il2CppImageDefinition *img = NULL; - if (type2img && td) { - int ii = type2img[m->declaringType]; - if (ii >= 0 && (size_t)ii < img_count) { - img = &images[ii]; - } + int ii = r2unity_image_index_for_method (type2img, type_count, m); + if (ii >= 0 && (size_t)ii < img_count) { + img = &images[ii]; } - char *fullname = build_method_fullname (meta, m, td); + char *fullname = r2unity_method_fullname (meta, m, td, type_idx, R2U_NAME_WITH_PARAMS); if (!fullname) { continue; }