mirror of
https://github.com/radareorg/r2unity.git
synced 2026-11-07 06:36:00 -10:00
Fix method offsets, map native code and silence class imports
This commit is contained in:
1 parent
aa3c6c6254
commit
212085e7fb
6 files changed
+76
-16
No files matched your search
@@ -46,6 +46,9 @@ all: $(EXEC)
|
||||
|
||||
r2 plugin: $(PLUGINS)
|
||||
|
||||
test: $(EXEC) $(PLUGINS)
|
||||
python3 test/test_import.py
|
||||
|
||||
install-plugin: $(PLUGINS)
|
||||
@[ -n "$(R2_USER_PLUGINS)" ] || (echo "r2 not found; cannot resolve R2_USER_PLUGINS"; exit 1)
|
||||
mkdir -p "$(R2_USER_PLUGINS)"
|
||||
@@ -96,4 +99,4 @@ clean:
|
||||
rm -f $(EXEC) $(OBJS) $(LEGACY_OBJS) $(PLUGINS) $(CONFIG_H)
|
||||
|
||||
|
||||
.PHONY: all clean plugin install-plugin uninstall-plugin fmt bindist
|
||||
.PHONY: all clean plugin install-plugin uninstall-plugin fmt bindist test
|
||||
@@ -94,6 +94,8 @@ After installing the plugins, open a Unity binary in r2 and use:
|
||||
```text
|
||||
r2unity? show help
|
||||
r2unity-D detect and cache companion file paths
|
||||
r2unity-L open/select and map the IL2CPP native library
|
||||
r2unity-c[*j] list classes, or emit an import script / JSON
|
||||
r2unity-i[j] show metadata summary
|
||||
r2unity-s apply managed method flags/comments
|
||||
r2unity-s* print the r2 commands instead of applying them
|
||||
@@ -104,6 +106,11 @@ r2unity-S emit managed-assembly SBOM text summary
|
||||
r2unity-Sj emit managed-assembly CycloneDX JSON
|
||||
```
|
||||
|
||||
Use `.r2unity-c*` to import classes and method flags. The script loads the
|
||||
native companion library automatically, so `s sym.unity.<class>.<method>`
|
||||
followed by `pd` shows the method's native code. Methods without a native
|
||||
implementation retain address zero and do not get a seekable flag.
|
||||
|
||||
Set `r2unity.metadata` and `r2unity.library` manually when auto-detection is not
|
||||
enough. The `bin_r2unity` plugin also lets radare2/rabin2 treat
|
||||
`global-metadata.dat` as a binary format, exposing sections, strings, symbols,
|
||||
|
||||
+8
-1
@@ -91,7 +91,7 @@ if build_plugins
|
||||
warning('r2 was not found; installing plugins under ' + r2_plugindir)
|
||||
endif
|
||||
|
||||
shared_library(
|
||||
core_plugin = shared_library(
|
||||
'core_r2unity',
|
||||
files('src/r2/core_r2unity.c') + lib_sources,
|
||||
include_directories: lib_inc,
|
||||
@@ -115,4 +115,11 @@ if build_plugins
|
||||
install_dir: r2_plugindir,
|
||||
)
|
||||
|
||||
python = find_program('python3', required: false)
|
||||
if python.found()
|
||||
test('r2unity-class-import', python,
|
||||
args: [files('test/test_import.py'), core_plugin],
|
||||
)
|
||||
endif
|
||||
|
||||
endif
|
||||
+13
-7
@@ -156,6 +156,7 @@ typedef struct {
|
||||
R2UnityMetadata *meta;
|
||||
Il2CppImageDefinition *images;
|
||||
Il2CppTypeDefinition *types;
|
||||
Il2CppMethodDefinition *methods;
|
||||
size_t image_count;
|
||||
size_t type_count;
|
||||
size_t method_count;
|
||||
@@ -166,13 +167,14 @@ static bool method_tables_init(R2UnityMethodTables *tables, R2UnityMetadata *met
|
||||
tables->meta = meta;
|
||||
tables->images = r2unity_get_images (meta, &tables->image_count);
|
||||
tables->types = r2unity_get_type_definitions (meta, &tables->type_count);
|
||||
tables->method_count = (size_t)r2unity_metadata_section_count (meta, R2U_SEC_METHODS);
|
||||
return tables->images && tables->image_count && tables->types && tables->type_count && tables->method_count;
|
||||
tables->methods = r2unity_get_method_definitions (meta, &tables->method_count);
|
||||
return tables->images && tables->image_count && tables->types && tables->type_count && tables->methods && tables->method_count;
|
||||
}
|
||||
|
||||
static void method_tables_fini(R2UnityMethodTables *tables) {
|
||||
R_FREE (tables->images);
|
||||
R_FREE (tables->types);
|
||||
R_FREE (tables->methods);
|
||||
}
|
||||
|
||||
static int image_index_by_name(R2UnityMethodTables *tables, const char *module_name) {
|
||||
@@ -215,23 +217,27 @@ static size_t copy_image_method_table(R2UnityNativeView *view, R2UnityMethodTabl
|
||||
if (image->typeStart < 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t local = 0;
|
||||
size_t copied = 0;
|
||||
size_t start = (size_t)image->typeStart;
|
||||
size_t end = R_MIN (tables->type_count, start + image->typeCount);
|
||||
for (size_t ti = start; ti < end && local < table_count; ti++) {
|
||||
for (size_t ti = start; ti < end; ti++) {
|
||||
const Il2CppTypeDefinition *td = &tables->types[ti];
|
||||
if (td->methodStart < 0) {
|
||||
local += td->method_count;
|
||||
continue;
|
||||
}
|
||||
for (size_t k = 0; k < td->method_count && local < table_count; k++, local++) {
|
||||
for (size_t k = 0; k < td->method_count; k++) {
|
||||
size_t mi = (size_t)td->methodStart + k;
|
||||
if (mi >= tables->method_count) {
|
||||
continue;
|
||||
}
|
||||
ut32 token = tables->methods[mi].token;
|
||||
ut32 rid = token & 0x00ffffff;
|
||||
if ((token >> 24) != 0x06 || !rid || rid > table_count) {
|
||||
continue;
|
||||
}
|
||||
ut64 raw = 0;
|
||||
if (!read_ptr_at (view, table_va + (ut64)local * view->ptr_size, &raw)) {
|
||||
// CodeGenModule method pointers are indexed by the MethodDef token RID.
|
||||
if (!read_ptr_at (view, table_va + (ut64)(rid - 1) * view->ptr_size, &raw)) {
|
||||
continue;
|
||||
}
|
||||
ut64 addr = code_va_from_raw (view, raw);
|
||||
|
||||
+2
-2
@@ -822,7 +822,7 @@ static void emit_class_r2(R2UnityMetadata *meta,
|
||||
}
|
||||
free (base);
|
||||
}
|
||||
printf ("ic+%s @ 0\n", r2klass);
|
||||
printf ("'@0x0'ic+ %s\n", r2klass);
|
||||
|
||||
int mstart = td->methodStart;
|
||||
for (int k = 0; methods && k < td->method_count && mstart >= 0 && (size_t)(mstart + k) < method_count; k++) {
|
||||
@@ -833,7 +833,7 @@ static void emit_class_r2(R2UnityMetadata *meta,
|
||||
}
|
||||
char *mname = method_name_or_fallback (meta, &methods[mi], mi);
|
||||
char *r2meth = r2_ic_name ("method", mname, mi);
|
||||
printf ("ic+%s.%s @ 0x%" PFMT64x "\n", r2klass, r2meth, addr);
|
||||
printf ("'@0x%" PFMT64x "'ic+ %s.%s\n", addr, r2klass, r2meth);
|
||||
free (r2meth);
|
||||
free (mname);
|
||||
}
|
||||
|
||||
+42
-5
@@ -15,6 +15,7 @@ static const char *g_help_msg[] = {
|
||||
"r2unity?", "", "show this help",
|
||||
"r2unity-c", "[*j]", "enumerate classes, inheritance, methods, and fields",
|
||||
"r2unity-D", "", "auto-detect companion files from current binary path",
|
||||
"r2unity-L", "", "open/select and map the IL2CPP native library",
|
||||
"r2unity-i", "[j]", "summary (metadata version, type/method counts)",
|
||||
"r2unity-s", "[*j]", "apply/list managed/native symbols as flags + comments",
|
||||
"r2unity-z", "[j]", "list managed string literals",
|
||||
@@ -287,6 +288,28 @@ static const char *resolve_library_path(RCore *core) {
|
||||
return R_STR_ISNOTEMPTY (v)? v: NULL;
|
||||
}
|
||||
|
||||
static int cmd_load_library(RCore *core) {
|
||||
const char *path = resolve_library_path (core);
|
||||
if (!path) {
|
||||
R_LOG_ERROR ("r2unity.library is not set. Run r2unity-D or set it manually");
|
||||
return 1;
|
||||
}
|
||||
RBinFile *bf = r_bin_file_find_by_name (core->bin, path);
|
||||
if (bf) {
|
||||
if (!r_core_bin_set_by_fd (core, bf->fd) || !r_io_use_fd (core->io, bf->fd)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (!current_binary_matches_path (core, path)) {
|
||||
RIODesc *desc = r_core_file_open (core, path, R_PERM_R, UT64_MAX);
|
||||
if (!desc || !r_core_bin_load (core, path, UT64_MAX)) {
|
||||
R_LOG_ERROR ("cannot load IL2CPP native library: %s", path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
r_core_block_read (core);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static R2UnityMetadata *open_metadata(RCore *core, RBuffer **out_buf) {
|
||||
const char *path = resolve_metadata_path (core);
|
||||
if (!path) {
|
||||
@@ -667,10 +690,10 @@ static void emit_class_r2(RCore *core,
|
||||
} else {
|
||||
r_cons_printf (core->cons, "# class %s\n", name? name: r2klass);
|
||||
}
|
||||
r_cons_printf (core->cons, "ic+%s @ 0\n", r2klass);
|
||||
r_cons_printf (core->cons, "'@0x0'ic+ %s\n", r2klass);
|
||||
if (base) {
|
||||
char *r2base = r2_ic_name ("type", base, 0, false);
|
||||
r_cons_printf (core->cons, "ic+%s:%s @ 0\n", r2klass, r2base);
|
||||
r_cons_printf (core->cons, "'@0x0'ic+ %s:%s\n", r2klass, r2base);
|
||||
free (r2base);
|
||||
}
|
||||
free (base);
|
||||
@@ -679,7 +702,7 @@ static void emit_class_r2(RCore *core,
|
||||
char *iname = type_name_from_index (meta, types, type_count, interfaces[td->interfacesStart + k], false);
|
||||
if (iname) {
|
||||
char *r2iface = r2_ic_name ("type", iname, 0, false);
|
||||
r_cons_printf (core->cons, "ic+%s:%s @ 0\n", r2klass, r2iface);
|
||||
r_cons_printf (core->cons, "'@0x0'ic+ %s:%s\n", r2klass, r2iface);
|
||||
free (r2iface);
|
||||
}
|
||||
free (iname);
|
||||
@@ -693,7 +716,10 @@ static void emit_class_r2(RCore *core,
|
||||
addr = addr > 0x1000? addr: 0;
|
||||
char *mname = method_name_or_fallback (meta, &methods[mi], mi);
|
||||
char *r2meth = r2_ic_name ("method", mname, mi, true);
|
||||
r_cons_printf (core->cons, "ic+%s.%s @ 0x%" PFMT64x "\n", r2klass, r2meth, addr);
|
||||
r_cons_printf (core->cons, "'@0x%" PFMT64x "'ic+ %s.%s\n", addr, r2klass, r2meth);
|
||||
if (addr) {
|
||||
r_cons_printf (core->cons, "'@0x%" PFMT64x "'f sym.unity.%s.%s 1\n", addr, r2klass, r2meth);
|
||||
}
|
||||
free (r2meth);
|
||||
free (mname);
|
||||
}
|
||||
@@ -704,7 +730,7 @@ static void emit_class_r2(RCore *core,
|
||||
char *fname = field_name_or_fallback (meta, &fields[fi], fi);
|
||||
char *r2field = r2_ic_name ("field", fname, fi, false);
|
||||
char *ftype = type_name_from_index (meta, types, type_count, fields[fi].typeIndex, true);
|
||||
r_cons_printf (core->cons, "ic+%s..%s %s @ 0\n",
|
||||
r_cons_printf (core->cons, "'@0x0'ic+ %s..%s %s\n",
|
||||
r2klass,
|
||||
r2field,
|
||||
ftype? ftype: "unknown");
|
||||
@@ -769,6 +795,9 @@ static int cmd_classes(RCore *core, char mode) {
|
||||
r_cons_println (core->cons, "# r2 script generated by r2unity-c");
|
||||
r_cons_printf (core->cons, "# Input file: %s\n", metadata_path && *metadata_path? metadata_path: "-");
|
||||
print_native_result (core, &native_result);
|
||||
if (has_ptrs) {
|
||||
r_cons_println (core->cons, "r2unity-L");
|
||||
}
|
||||
if (!has_ptrs) {
|
||||
r_cons_println (core->cons, "# Method addresses default to 0; run r2unity-D or set r2unity.library to recover native addresses.");
|
||||
}
|
||||
@@ -805,6 +834,9 @@ static int cmd_symbols(RCore *core, char mode) {
|
||||
R_LOG_ERROR ("r2unity.library is not set. Run r2unity-D or set it manually");
|
||||
return 1;
|
||||
}
|
||||
if (!mode && cmd_load_library (core)) {
|
||||
return 1;
|
||||
}
|
||||
RBuffer *buf = NULL;
|
||||
R2UnityMetadata *meta = open_metadata (core, &buf);
|
||||
if (!meta) {
|
||||
@@ -836,6 +868,9 @@ static int cmd_symbols(RCore *core, char mode) {
|
||||
pj_ka (pj, "methods");
|
||||
} else if (mode == '*') {
|
||||
print_native_result (core, &native_result);
|
||||
if (has_ptrs) {
|
||||
r_cons_println (core->cons, "r2unity-L");
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != 'j') {
|
||||
@@ -1274,6 +1309,8 @@ static bool r2unity_call(RCorePluginSession *cps, const char *input) {
|
||||
return cmd_classes (core, mode) == 0;
|
||||
case 'D':
|
||||
return cmd_detect (core, mode == 'j') == 0;
|
||||
case 'L':
|
||||
return cmd_load_library (core) == 0;
|
||||
case 'i':
|
||||
return cmd_info (core, mode == 'j') == 0;
|
||||
case 's':
|
||||
|
||||
Reference in new issue
Block a user