mirror of
https://github.com/radareorg/r2flutter.git
synced 2026-11-07 22:56:23 -10:00
Give duplicate Dart method names unique r2 flags and function names
r2 flag names are unique, so flagging a second function with a repeated Dart name (e.g. Native._anon_closure) moved the flag away from the first one, and current r2's af then named it after the Mach-O sym.func.* flag. Suffix repeats with their address, use the same names for afs, and rename analyzed functions after the af pass. Also skip var recovery, call-following and jump tables in the signature af pass (AuthPass -AAA 47s -> 29s) and raise R2R_TIMEOUT to 60s.
This commit is contained in:
1 parent
cc338995cf
commit
0ee5e01498
5 files changed
+98
-9
No files matched your search
@@ -9,7 +9,7 @@ LDFLAGS += $(R2_LDFLAGS)
|
||||
LDLIBS += $(R2_LIBS)
|
||||
DEPFLAGS = -MMD -MP
|
||||
R2R_JOBS ?= 1
|
||||
R2R_TIMEOUT ?= 30
|
||||
R2R_TIMEOUT ?= 60
|
||||
R2_LIBR_PLUGINS=$(shell r2 -H R2_LIBR_PLUGINS 2> /dev/null)
|
||||
R2_LIBEXT=$(shell r2 -H R2_LIBEXT 2> /dev/null)
|
||||
-include config.mk
|
||||
|
||||
@@ -2052,3 +2052,18 @@ Regressions also mark the Android table entries as lacking Code metadata and
|
||||
place matching PP loads in the last function and outside the image to check
|
||||
coverage and bounds. This expands instruction coverage; operand decoding
|
||||
continues to use the existing standalone scanner.
|
||||
|
||||
## Duplicate Dart method names need unique r2 flags and function names
|
||||
|
||||
Several functions can share a Dart name (e.g. many `Native._anon_closure`).
|
||||
r2 flag and function names are unique, so `r_flag_set` on a repeated name
|
||||
moves the flag to the later function. Older r2 left a stale per-address entry
|
||||
behind, which let `af` still pick the moved `method.*` name; current r2 does
|
||||
not, and `af` also prefers symbol-space flags such as Mach-O `sym.func.*`.
|
||||
|
||||
The first function keeps `method.<name>` and repeats get a `.0x<addr>` suffix,
|
||||
computed once in app order and shared by the flags, the `afs` prototypes and
|
||||
`dart_dumper_name_functions`, which renames analyzed functions after the `af`
|
||||
pass. The signature `af` storm also disables `anal.vars`, `anal.calls` and
|
||||
`anal.jmp.tbl` like `flutter_ensure_functions`; var recovery was about half
|
||||
of its cost (AuthPass `-AAA` 47s -> 29s).
|
||||
@@ -11,6 +11,7 @@ char *dart_dumper_dump_r2(DartApp *app);
|
||||
char *dart_dumper_dump_funcs(DartApp *app, int fmt);
|
||||
void dart_dumper_apply_to_core(DartApp *app, bool apply_signatures);
|
||||
void dart_dumper_apply_signatures(DartApp *app);
|
||||
void dart_dumper_name_functions(DartApp *app);
|
||||
// Disable anal.trycatch while r2flutter runs many `af` commands, when no try.*
|
||||
// flag exists for it to find. Returns the previous value to pass to the restore.
|
||||
bool dart_core_trycatch_suspend(RCore *core);
|
||||
|
||||
+80
-8
@@ -124,8 +124,61 @@ static char *make_method_flagname(const char *name) {
|
||||
return flagname;
|
||||
}
|
||||
|
||||
static void dump_func_r2(RStrBuf *sb, const DartFunction *fn, bool quiet) {
|
||||
char *flagname = make_method_flagname (fn->name);
|
||||
// Flag and function names are unique in r2: setting an existing flag name
|
||||
// moves it, so a later function sharing a Dart name (e.g. several
|
||||
// Native._anon_closure) would steal it from the first one. Suffix repeated
|
||||
// names with the entry address.
|
||||
static char *make_unique_method_flagname(HtPP *seen, const char *name, ut64 addr) {
|
||||
char *flagname = make_method_flagname (name);
|
||||
bool found = false;
|
||||
ut64 owner = (ut64) (size_t)ht_pp_find (seen, flagname, &found);
|
||||
if (found && owner != addr) {
|
||||
char *unique = r_str_newf ("%s.0x%" PFMT64x, flagname, addr);
|
||||
free (flagname);
|
||||
return unique;
|
||||
}
|
||||
ht_pp_insert (seen, flagname, (void *) (size_t)addr);
|
||||
return flagname;
|
||||
}
|
||||
|
||||
static void method_flagname_free(HtUPKv *kv) {
|
||||
free (kv->value);
|
||||
}
|
||||
|
||||
// Map each function address to its unique method.* name, in app order.
|
||||
static HtUP *method_flagnames(DartApp *app) {
|
||||
HtUP *names = ht_up_new (NULL, method_flagname_free, NULL);
|
||||
HtPP *seen = ht_pp_new0 ();
|
||||
DartFunction *fn;
|
||||
R_VEC_FOREACH (app->functions, fn) {
|
||||
if (fn->name && !ht_up_find (names, fn->addr, NULL)) {
|
||||
ht_up_insert (names, fn->addr, make_unique_method_flagname (seen, fn->name, fn->addr));
|
||||
}
|
||||
}
|
||||
ht_pp_free (seen);
|
||||
return names;
|
||||
}
|
||||
|
||||
// Give each analyzed function its Dart name: r2's `af` prefers flags in the
|
||||
// symbols space (e.g. Mach-O sym.func.*) over the method.* flags set here.
|
||||
void dart_dumper_name_functions(DartApp *app) {
|
||||
if (!app || !app->core || !app->functions) {
|
||||
return;
|
||||
}
|
||||
HtUP *names = method_flagnames (app);
|
||||
DartFunction *fn;
|
||||
R_VEC_FOREACH (app->functions, fn) {
|
||||
RAnalFunction *fcn = r_anal_get_function_at (app->core->anal, fn->addr);
|
||||
const char *name = fcn? ht_up_find (names, fn->addr, NULL): NULL;
|
||||
if (name && strcmp (fcn->name, name)) {
|
||||
r_anal_function_rename (fcn, name);
|
||||
}
|
||||
}
|
||||
ht_up_free (names);
|
||||
}
|
||||
|
||||
static void dump_func_r2(RStrBuf *sb, HtPP *seen, const DartFunction *fn, bool quiet) {
|
||||
char *flagname = make_unique_method_flagname (seen, fn->name, fn->addr);
|
||||
r_strbuf_appendf (sb, "f %s = 0x%" PFMT64x "\n", flagname, (uint64_t)fn->addr);
|
||||
if (!quiet) {
|
||||
r_strbuf_appendf (sb, "'@0x%" PFMT64x "'CC %s\n", (uint64_t)fn->addr, fn->name);
|
||||
@@ -145,13 +198,15 @@ char *dart_dumper_dump_r2(DartApp *app) {
|
||||
r_strbuf_appendf (sb, "f app.heap_base = 0x%" PFMT64x "\n", (uint64_t)app->heap_base);
|
||||
|
||||
if (app->functions) {
|
||||
HtPP *seen = ht_pp_new0 ();
|
||||
DartFunction *fn;
|
||||
R_VEC_FOREACH (app->functions, fn) {
|
||||
if (!fn->name) {
|
||||
continue;
|
||||
}
|
||||
dump_func_r2 (sb, fn, quiet);
|
||||
dump_func_r2 (sb, seen, fn, quiet);
|
||||
}
|
||||
ht_pp_free (seen);
|
||||
}
|
||||
|
||||
r_strbuf_append (sb, "dr x27=`e anal.gp`\n");
|
||||
@@ -219,6 +274,7 @@ char *dart_dumper_dump_funcs(DartApp *app, int fmt) {
|
||||
}
|
||||
|
||||
RStrBuf *sb = r_strbuf_new ("");
|
||||
HtPP *seen = ht_pp_new0 ();
|
||||
R_VEC_FOREACH (app->functions, fn) {
|
||||
if (!fn->name) {
|
||||
continue;
|
||||
@@ -227,12 +283,13 @@ char *dart_dumper_dump_funcs(DartApp *app, int fmt) {
|
||||
break;
|
||||
}
|
||||
if (fmt == 'r') {
|
||||
dump_func_r2 (sb, fn, app->dctx.quiet);
|
||||
dump_func_r2 (sb, seen, fn, app->dctx.quiet);
|
||||
} else {
|
||||
dump_func_text (sb, fn);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ht_pp_free (seen);
|
||||
return drain_trimmed_strbuf (sb);
|
||||
}
|
||||
|
||||
@@ -419,17 +476,27 @@ void dart_dumper_apply_signatures(DartApp *app) {
|
||||
}
|
||||
}
|
||||
qsort (order, n, sizeof (DartFunction *), dart_fn_addr_desc);
|
||||
HtUP *names = method_flagnames (app);
|
||||
// Keep the analysis local to each function start; the surrounding pass owns
|
||||
// broader discovery. String ESIL emulation is very slow and irrelevant to
|
||||
// prototypes, so disable it for the duration of this pass.
|
||||
// Variable recovery, call-following and jump tables are not needed for the
|
||||
// prototypes either, and var recovery alone is about half of this `af` cost.
|
||||
int prev_hasnext = r_config_get_i (core->config, "anal.hasnext");
|
||||
int prev_emustr = r_config_get_i (core->config, "emu.str");
|
||||
bool prev_calls = r_config_get_b (core->config, "anal.calls");
|
||||
bool prev_vars = r_config_get_b (core->config, "anal.vars");
|
||||
bool prev_jmptbl = r_config_get_b (core->config, "anal.jmp.tbl");
|
||||
r_config_set_i (core->config, "anal.hasnext", 0);
|
||||
r_config_set_i (core->config, "emu.str", 0);
|
||||
r_config_set_b (core->config, "anal.calls", false);
|
||||
r_config_set_b (core->config, "anal.vars", false);
|
||||
r_config_set_b (core->config, "anal.jmp.tbl", false);
|
||||
const bool prev_trycatch = dart_core_trycatch_suspend (core);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
fn = order[i];
|
||||
char *name = strdup (fn->name? fn->name: "fcn");
|
||||
const char *flagname = ht_up_find (names, fn->addr, NULL);
|
||||
char *name = strdup (flagname? flagname: "fcn");
|
||||
r_name_filter (name, 0);
|
||||
if (R_STR_ISEMPTY (name)) {
|
||||
free (name);
|
||||
@@ -452,7 +519,11 @@ void dart_dumper_apply_signatures(DartApp *app) {
|
||||
}
|
||||
r_config_set_i (core->config, "anal.hasnext", prev_hasnext);
|
||||
r_config_set_i (core->config, "emu.str", prev_emustr);
|
||||
r_config_set_b (core->config, "anal.calls", prev_calls);
|
||||
r_config_set_b (core->config, "anal.vars", prev_vars);
|
||||
r_config_set_b (core->config, "anal.jmp.tbl", prev_jmptbl);
|
||||
dart_core_trycatch_restore (core, prev_trycatch);
|
||||
ht_up_free (names);
|
||||
free (order);
|
||||
}
|
||||
|
||||
@@ -468,16 +539,17 @@ void dart_dumper_apply_to_core(DartApp *app, bool apply_signatures) {
|
||||
}
|
||||
|
||||
if (app->functions) {
|
||||
HtUP *names = method_flagnames (app);
|
||||
DartFunction *fn;
|
||||
R_VEC_FOREACH (app->functions, fn) {
|
||||
if (!fn->name) {
|
||||
const char *flagname = ht_up_find (names, fn->addr, NULL);
|
||||
if (!fn->name || !flagname) {
|
||||
continue;
|
||||
}
|
||||
char *flagname = make_method_flagname (fn->name);
|
||||
r_flag_set (core->flags, flagname, fn->addr, fn->size);
|
||||
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, fn->addr, fn->name);
|
||||
free (flagname);
|
||||
}
|
||||
ht_up_free (names);
|
||||
}
|
||||
|
||||
r_core_cmd0 (core, "e emu.str=true");
|
||||
|
||||
@@ -1572,6 +1572,7 @@ bool r2flutter_analysis_run(RCore *core, DartCtx *dctx, bool quiet) {
|
||||
|
||||
RVecFlutterEntry *entries = flutter_collect_entries (core, app, &model);
|
||||
flutter_ensure_functions (core, entries);
|
||||
dart_dumper_name_functions (app);
|
||||
flutter_scan_functions (core, &model, &pp_strings, &pp_refs, entries, &stats);
|
||||
|
||||
int graph_xrefs = r2flutter_apply_pool_xrefs (core, dctx);
|
||||
|
||||
Reference in new issue
Block a user