mirror of
https://github.com/radareorg/r2flutter.git
synced 2026-11-07 06:26:00 -10:00
Add r2flutter.str options to configure string parsing limits
This commit is contained in:
1 parent
49f174f3cd
commit
05c0616b37
7 files changed
+195
-74
No files matched your search
@@ -1749,3 +1749,16 @@ lines come from `dart_pool_strings.c` (string references), not
|
||||
address). The apply runs on a shallow DartCtx copy with its own read cache for
|
||||
the same reason as `r2flutter_setup_pp_gp`: the scan has already mutated
|
||||
app->dctx, and extraction needs the pristine state the standalone command sees.
|
||||
|
||||
## String dump config (`r2flutter.str.*`)
|
||||
|
||||
`r2flutter.str.limit`, `.minlen`, `.maxlen` and `.filter` replace the old
|
||||
hardcoded `DART_STRING_SCAN_LIMIT` (50000). The defaults are unlimited/empty:
|
||||
no test sample reaches 50k carved strings (mafia ~41k in 0.7s), and the carved
|
||||
regions are already capped by `DART_SNAPSHOT_SCAN_MAX`/`DART_DATA_IMAGE_SCAN_MAX`.
|
||||
minlen/maxlen/filter only filter what `-z`/`-zz` print, because the carved list
|
||||
also feeds enum recovery and string-ref population. `str.limit` caps printed
|
||||
matches and only stops the `-zz` carving early (`ctx->str_scan_limit`) when no
|
||||
filter is set; otherwise the scan would stop before reaching the matches.
|
||||
Careful: `r_regex_check` returns `r_regex_exec` as-is, i.e. **false on match**;
|
||||
compare `r_regex_exec (rx, s, 0, NULL, 0) == 0` explicitly.
|
||||
@@ -390,6 +390,11 @@ Config keys:
|
||||
|
||||
- `r2flutter.mapfile`: Flutter obfuscation map JSON path
|
||||
- `r2flutter.namepool`: enable heuristic name-pool fallback
|
||||
- `r2flutter.profile`: override Dart snapshot profile by 32-byte hash or Dart version
|
||||
- `r2flutter.str.limit`: max number of strings printed by `-z`/`-zz` (default `0`, unlimited); without filters it also stops the `-zz` carving early
|
||||
- `r2flutter.str.minlen`: skip printing strings shorter than N (default `0`)
|
||||
- `r2flutter.str.maxlen`: skip printing strings longer than N (default `0`, unlimited)
|
||||
- `r2flutter.str.filter`: only print strings matching this extended regex (default empty)
|
||||
|
||||
Plugin modifiers:
|
||||
|
||||
|
||||
@@ -81,6 +81,11 @@ typedef struct {
|
||||
int dump_fields;
|
||||
int dump_strings;
|
||||
bool dump_string_refs;
|
||||
ut64 str_limit; // max strings to print (0 = unlimited)
|
||||
ut64 str_scan_limit; // max strings to carve in the fuzzy scan (0 = unlimited)
|
||||
int str_minlen; // skip printing strings shorter than this
|
||||
int str_maxlen; // skip printing strings longer than this (0 = unlimited)
|
||||
const char *str_filter; // only print strings matching this regex
|
||||
const char *obf_map_path;
|
||||
HtPP *obf_by_obfuscated;
|
||||
bool obf_map_tried;
|
||||
|
||||
+110
-74
@@ -26,7 +26,17 @@ void dart_string_list_free(RList *list) {
|
||||
r_list_free (list);
|
||||
}
|
||||
|
||||
#define DART_STRING_SCAN_LIMIT 50000
|
||||
typedef struct {
|
||||
RList *list;
|
||||
HtUP *seen_addrs;
|
||||
ut64 ref_counter;
|
||||
ut64 limit; // 0 means unlimited
|
||||
} StringScan;
|
||||
|
||||
static bool string_scan_full(const StringScan *ss) {
|
||||
return ss->limit && (ut64)r_list_length (ss->list) >= ss->limit;
|
||||
}
|
||||
|
||||
DartStringCategory dart_string_classify_value(const char *s) {
|
||||
if (R_STR_ISEMPTY (s)) {
|
||||
return DART_STRING_CAT_UNKNOWN;
|
||||
@@ -57,7 +67,7 @@ static const char *string_category_name(DartStringCategory cat) {
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_utf16_strings(const ut8 *buf, ut64 base, ut64 size, RList *list, HtUP *seen_addrs, ut64 *ref_counter);
|
||||
static void scan_utf16_strings(const ut8 *buf, ut64 base, ut64 size, StringScan *ss);
|
||||
static bool should_scan_section(const RBinSection *sec);
|
||||
|
||||
static bool is_common_text_punct(ut8 ch) {
|
||||
@@ -146,31 +156,28 @@ static void packed_string_record_fini(PackedStringRecord *rec) {
|
||||
rec->value = NULL;
|
||||
}
|
||||
|
||||
static void append_string_info(RList *list, HtUP *seen_addrs, const char *value, ut32 len, ut32 flags, ut64 addr, DartStringCategory cat, ut64 *ref_counter) {
|
||||
if (!list || !value) {
|
||||
static void append_string_info(StringScan *ss, const char *value, ut32 len, ut32 flags, ut64 addr, DartStringCategory cat) {
|
||||
if (!value || string_scan_full (ss)) {
|
||||
return;
|
||||
}
|
||||
if (r_list_length (list) >= DART_STRING_SCAN_LIMIT) {
|
||||
return;
|
||||
}
|
||||
if (seen_addrs && addr && ht_up_find (seen_addrs, addr, NULL)) {
|
||||
if (addr && ht_up_find (ss->seen_addrs, addr, NULL)) {
|
||||
return;
|
||||
}
|
||||
DartStringInfo *si = R_NEW0 (DartStringInfo);
|
||||
si->ref_id = ref_counter? (*ref_counter)++: 0;
|
||||
si->ref_id = ss->ref_counter++;
|
||||
si->length = len;
|
||||
si->flags = flags | DART_STRING_CANONICAL;
|
||||
si->address = addr;
|
||||
si->category = cat;
|
||||
si->references = r_list_newf ((RListFree)dart_string_ref_free);
|
||||
si->value = strdup (value);
|
||||
r_list_append (list, si);
|
||||
if (seen_addrs && addr) {
|
||||
ht_up_insert (seen_addrs, addr, si);
|
||||
r_list_append (ss->list, si);
|
||||
if (addr) {
|
||||
ht_up_insert (ss->seen_addrs, addr, si);
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_ascii_strings(const ut8 *buf, ut64 base, ut64 size, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
static void scan_ascii_strings(const ut8 *buf, ut64 base, ut64 size, StringScan *ss) {
|
||||
if (!buf || !size) {
|
||||
return;
|
||||
}
|
||||
@@ -190,7 +197,7 @@ static void scan_ascii_strings(const ut8 *buf, ut64 base, ut64 size, RList *list
|
||||
memcpy (tmp, buf + start, length);
|
||||
tmp[length] = '\0';
|
||||
if (looks_like_text (tmp)) {
|
||||
append_string_info (list, seen_addrs, tmp, (ut32)length, 0, base + start, dart_string_classify_value (tmp), ref_counter);
|
||||
append_string_info (ss, tmp, (ut32)length, 0, base + start, dart_string_classify_value (tmp));
|
||||
}
|
||||
free (tmp);
|
||||
}
|
||||
@@ -334,12 +341,12 @@ static bool parse_packed_string_record_text(const ut8 *buf, ut64 size, ut64 pos,
|
||||
return out->value != NULL;
|
||||
}
|
||||
|
||||
static void scan_packed_string_runs(const ut8 *buf, ut64 base, ut64 size, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
if (!buf || !size || !list) {
|
||||
static void scan_packed_string_runs(const ut8 *buf, ut64 base, ut64 size, StringScan *ss) {
|
||||
if (!buf || !size) {
|
||||
return;
|
||||
}
|
||||
ut64 pos = 0;
|
||||
while (pos < size && r_list_length (list) < DART_STRING_SCAN_LIMIT) {
|
||||
while (pos < size && !string_scan_full (ss)) {
|
||||
PackedStringRecord probe = { 0 };
|
||||
if (!parse_packed_string_record_text (buf, size, pos, &probe)) {
|
||||
pos++;
|
||||
@@ -372,9 +379,9 @@ static void scan_packed_string_runs(const ut8 *buf, ut64 base, ut64 size, RList
|
||||
skips++;
|
||||
}
|
||||
if (n_records >= DART_PACKED_STRING_MIN_RUN) {
|
||||
for (int i = 0; i < n_records && r_list_length (list) < DART_STRING_SCAN_LIMIT; i++) {
|
||||
for (int i = 0; i < n_records && !string_scan_full (ss); i++) {
|
||||
PackedStringRecord *rec = &records[i];
|
||||
append_string_info (list, seen_addrs, rec->value, rec->length, rec->flags, base + rec->payload_off, dart_string_classify_value (rec->value), ref_counter);
|
||||
append_string_info (ss, rec->value, rec->length, rec->flags, base + rec->payload_off, dart_string_classify_value (rec->value));
|
||||
}
|
||||
pos = run_end;
|
||||
} else {
|
||||
@@ -386,8 +393,8 @@ static void scan_packed_string_runs(const ut8 *buf, ut64 base, ut64 size, RList
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_packed_strings_from_snapshot(DartCtx *ctx, ut64 snapshot_base, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
if (!ctx || !snapshot_base || !list) {
|
||||
static void scan_packed_strings_from_snapshot(DartCtx *ctx, ut64 snapshot_base, StringScan *ss) {
|
||||
if (!ctx || !snapshot_base) {
|
||||
return;
|
||||
}
|
||||
ut8 hdrbuf[12];
|
||||
@@ -417,23 +424,23 @@ static void scan_packed_strings_from_snapshot(DartCtx *ctx, ut64 snapshot_base,
|
||||
if (ctx->verbose > 1) {
|
||||
fprintf (stderr, "[r2flutter] packed string scan snapshot=0x%" PFMT64x " cluster_start=0x%" PFMT64x " total=0x%" PFMT64x "\n", snapshot_base, snapshot_base + hdr.cluster_start, hdr.total_len);
|
||||
}
|
||||
scan_packed_string_runs (buf + hdr.cluster_start, snapshot_base + hdr.cluster_start, hdr.total_len - hdr.cluster_start, list, seen_addrs, ref_counter);
|
||||
scan_packed_string_runs (buf + hdr.cluster_start, snapshot_base + hdr.cluster_start, hdr.total_len - hdr.cluster_start, ss);
|
||||
free (buf);
|
||||
}
|
||||
|
||||
#define DART_SNAPSHOT_SCAN_MAX (64ULL << 20)
|
||||
#define DART_DATA_IMAGE_SCAN_MAX (8ULL << 20)
|
||||
|
||||
static void scan_string_buffer(const ut8 *buf, ut64 base, ut64 size, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
if (!buf || !size || !list) {
|
||||
static void scan_string_buffer(const ut8 *buf, ut64 base, ut64 size, StringScan *ss) {
|
||||
if (!buf || !size) {
|
||||
return;
|
||||
}
|
||||
scan_ascii_strings (buf, base, size, list, seen_addrs, ref_counter);
|
||||
scan_utf16_strings (buf, base, size, list, seen_addrs, ref_counter);
|
||||
scan_ascii_strings (buf, base, size, ss);
|
||||
scan_utf16_strings (buf, base, size, ss);
|
||||
}
|
||||
|
||||
static void scan_snapshot_region(DartCtx *ctx, ut64 start, ut64 size, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
if (!ctx || !ctx->core || !ctx->core->bin || !start || !size || !list || size > DART_SNAPSHOT_SCAN_MAX) {
|
||||
static void scan_snapshot_region(DartCtx *ctx, ut64 start, ut64 size, StringScan *ss) {
|
||||
if (!ctx || !ctx->core || !ctx->core->bin || !start || !size || size > DART_SNAPSHOT_SCAN_MAX) {
|
||||
return;
|
||||
}
|
||||
ut64 end = start + size;
|
||||
@@ -468,16 +475,16 @@ static void scan_snapshot_region(DartCtx *ctx, ut64 start, ut64 size, RList *lis
|
||||
free (buf);
|
||||
continue;
|
||||
}
|
||||
scan_string_buffer (buf, chunk_start, chunk_size, list, seen_addrs, ref_counter);
|
||||
scan_string_buffer (buf, chunk_start, chunk_size, ss);
|
||||
free (buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_strings_from_snapshot_window(DartCtx *ctx, ut64 snapshot_base, ut64 upper_bound, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
if (!ctx || !snapshot_base || !list) {
|
||||
static void scan_strings_from_snapshot_window(DartCtx *ctx, ut64 snapshot_base, ut64 upper_bound, StringScan *ss) {
|
||||
if (!ctx || !snapshot_base) {
|
||||
return;
|
||||
}
|
||||
ut64 before_count = r_list_length (list);
|
||||
ut64 before_count = r_list_length (ss->list);
|
||||
DartSnapshotHeader sh;
|
||||
if (!dart_snapshot_header_read (ctx, snapshot_base, &sh)) {
|
||||
goto fallback;
|
||||
@@ -486,10 +493,10 @@ static void scan_strings_from_snapshot_window(DartCtx *ctx, ut64 snapshot_base,
|
||||
goto fallback;
|
||||
}
|
||||
if (ctx->compressed_word_size == 4) {
|
||||
scan_packed_strings_from_snapshot (ctx, snapshot_base, list, seen_addrs, ref_counter);
|
||||
scan_packed_strings_from_snapshot (ctx, snapshot_base, ss);
|
||||
return;
|
||||
}
|
||||
scan_snapshot_region (ctx, snapshot_base + sh.cluster_start, sh.total_len - sh.cluster_start, list, seen_addrs, ref_counter);
|
||||
scan_snapshot_region (ctx, snapshot_base + sh.cluster_start, sh.total_len - sh.cluster_start, ss);
|
||||
ut64 align = ctx->layout && ctx->layout->max_alignment? (ut64)ctx->layout->max_alignment: 16;
|
||||
if (align == 0) {
|
||||
align = 16;
|
||||
@@ -497,18 +504,18 @@ static void scan_strings_from_snapshot_window(DartCtx *ctx, ut64 snapshot_base,
|
||||
ut64 data_start = snapshot_base + ((sh.total_len + (align - 1)) & ~ (align - 1));
|
||||
ut64 data_end = upper_bound;
|
||||
if (data_end > data_start && (data_end - data_start) <= DART_DATA_IMAGE_SCAN_MAX) {
|
||||
scan_snapshot_region (ctx, data_start, data_end - data_start, list, seen_addrs, ref_counter);
|
||||
scan_snapshot_region (ctx, data_start, data_end - data_start, ss);
|
||||
}
|
||||
if ((ut64)r_list_length (list) > before_count) {
|
||||
if ((ut64)r_list_length (ss->list) > before_count) {
|
||||
return;
|
||||
}
|
||||
fallback:
|
||||
if (upper_bound > snapshot_base + 0x100 && (upper_bound - (snapshot_base + 0x100)) <= DART_DATA_IMAGE_SCAN_MAX) {
|
||||
scan_snapshot_region (ctx, snapshot_base + 0x100, upper_bound - (snapshot_base + 0x100), list, seen_addrs, ref_counter);
|
||||
scan_snapshot_region (ctx, snapshot_base + 0x100, upper_bound - (snapshot_base + 0x100), ss);
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_utf16_strings(const ut8 *buf, ut64 base, ut64 size, RList *list, HtUP *seen_addrs, ut64 *ref_counter) {
|
||||
static void scan_utf16_strings(const ut8 *buf, ut64 base, ut64 size, StringScan *ss) {
|
||||
if (!buf || size < 8) {
|
||||
return;
|
||||
}
|
||||
@@ -536,7 +543,7 @@ static void scan_utf16_strings(const ut8 *buf, ut64 base, ut64 size, RList *list
|
||||
if (utf8 && units >= 4 && utf16le_has_ascii_profile (buf, start, start + (units * 2))) {
|
||||
ut32 ulen = (ut32)strlen (utf8);
|
||||
if (ulen >= 4 && ulen <= 512 && looks_like_text (utf8)) {
|
||||
append_string_info (list, seen_addrs, utf8, ulen, DART_STRING_TWO_BYTE, base + start, dart_string_classify_value (utf8), ref_counter);
|
||||
append_string_info (ss, utf8, ulen, DART_STRING_TWO_BYTE, base + start, dart_string_classify_value (utf8));
|
||||
}
|
||||
}
|
||||
r_strbuf_fini (&sb);
|
||||
@@ -583,16 +590,15 @@ RList *dart_pool_extract_strings(DartCtx *ctx) {
|
||||
return NULL;
|
||||
}
|
||||
RList *string_list = r_list_newf ((RListFree)dart_string_info_free);
|
||||
HtUP *seen_addrs = ht_up_new0 ();
|
||||
if (!seen_addrs) {
|
||||
return string_list;
|
||||
}
|
||||
RVecRBinSection *sections = r_bin_get_sections_vec (ctx->core->bin);
|
||||
if (!sections) {
|
||||
ht_up_free (seen_addrs);
|
||||
return string_list;
|
||||
}
|
||||
ut64 ref_counter = 0;
|
||||
StringScan ss = {
|
||||
.list = string_list,
|
||||
.seen_addrs = ht_up_new0 (),
|
||||
.limit = ctx->str_scan_limit
|
||||
};
|
||||
if (find_snapshots (ctx) == 0 && ctx->vm_data) {
|
||||
DartVerLayout layout_tmp;
|
||||
DartVerLayout *layout_owned = dart_ctx_init_layout (ctx, &layout_tmp);
|
||||
@@ -608,14 +614,14 @@ RList *dart_pool_extract_strings(DartCtx *ctx) {
|
||||
} else if (ctx->iso_instr > ctx->iso_data) {
|
||||
iso_upper = ctx->iso_instr;
|
||||
}
|
||||
scan_strings_from_snapshot_window (ctx, ctx->vm_data, vm_upper, string_list, seen_addrs, &ref_counter);
|
||||
scan_strings_from_snapshot_window (ctx, ctx->iso_data, iso_upper, string_list, seen_addrs, &ref_counter);
|
||||
scan_strings_from_snapshot_window (ctx, ctx->vm_data, vm_upper, &ss);
|
||||
scan_strings_from_snapshot_window (ctx, ctx->iso_data, iso_upper, &ss);
|
||||
if (r_list_length (string_list) == 0) {
|
||||
if (vm_upper > ctx->vm_data + 0x100) {
|
||||
scan_snapshot_region (ctx, ctx->vm_data + 0x100, vm_upper - (ctx->vm_data + 0x100), string_list, seen_addrs, &ref_counter);
|
||||
scan_snapshot_region (ctx, ctx->vm_data + 0x100, vm_upper - (ctx->vm_data + 0x100), &ss);
|
||||
}
|
||||
if (iso_upper > ctx->iso_data + 0x100) {
|
||||
scan_snapshot_region (ctx, ctx->iso_data + 0x100, iso_upper - (ctx->iso_data + 0x100), string_list, seen_addrs, &ref_counter);
|
||||
scan_snapshot_region (ctx, ctx->iso_data + 0x100, iso_upper - (ctx->iso_data + 0x100), &ss);
|
||||
}
|
||||
}
|
||||
dart_ctx_fini_layout (ctx, layout_owned);
|
||||
@@ -637,9 +643,9 @@ RList *dart_pool_extract_strings(DartCtx *ctx) {
|
||||
free (buf);
|
||||
continue;
|
||||
}
|
||||
scan_string_buffer (buf, sec->vaddr, size, string_list, seen_addrs, &ref_counter);
|
||||
scan_string_buffer (buf, sec->vaddr, size, &ss);
|
||||
free (buf);
|
||||
if (r_list_length (string_list) >= DART_STRING_SCAN_LIMIT) {
|
||||
if (string_scan_full (&ss)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -648,12 +654,12 @@ RList *dart_pool_extract_strings(DartCtx *ctx) {
|
||||
if (size > 0 && size <= DART_SNAPSHOT_SCAN_MAX) {
|
||||
ut8 *buf = (ut8 *)malloc ((size_t)size);
|
||||
if (buf && read_mem (ctx, 0, buf, (int)size)) {
|
||||
scan_string_buffer (buf, 0, size, string_list, seen_addrs, &ref_counter);
|
||||
scan_string_buffer (buf, 0, size, &ss);
|
||||
}
|
||||
free (buf);
|
||||
}
|
||||
}
|
||||
ht_up_free (seen_addrs);
|
||||
ht_up_free (ss.seen_addrs);
|
||||
r_list_sort (string_list, (RListComparator)string_info_addr_cmp);
|
||||
return string_list;
|
||||
}
|
||||
@@ -832,36 +838,62 @@ static void dump_string_text(RStrBuf *sb, const DartStringInfo *si, int fmt, boo
|
||||
}
|
||||
}
|
||||
|
||||
static bool string_matches(const DartCtx *ctx, const RRegex *rx, const DartStringInfo *si) {
|
||||
if (!si || !si->value) {
|
||||
return false;
|
||||
}
|
||||
if (ctx->str_minlen > 0 && si->length < (ut32)ctx->str_minlen) {
|
||||
return false;
|
||||
}
|
||||
if (ctx->str_maxlen > 0 && si->length > (ut32)ctx->str_maxlen) {
|
||||
return false;
|
||||
}
|
||||
return !rx || r_regex_exec (rx, si->value, 0, NULL, 0) == 0;
|
||||
}
|
||||
|
||||
static char *dump_strings_list(DartCtx *ctx, RList *strings, int fmt) {
|
||||
const bool refs = ctx && ctx->dump_string_refs;
|
||||
RRegex *rx = NULL;
|
||||
if (R_STR_ISNOTEMPTY (ctx->str_filter)) {
|
||||
rx = r_regex_new (ctx->str_filter, "e");
|
||||
if (!rx) {
|
||||
R_LOG_ERROR ("Invalid string filter regex: %s", ctx->str_filter);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
const bool refs = ctx->dump_string_refs;
|
||||
const bool quiet = ctx->quiet;
|
||||
PJ *pj = NULL;
|
||||
RStrBuf *sb = NULL;
|
||||
if (fmt == 'j') {
|
||||
if (!strings || r_list_length (strings) == 0) {
|
||||
return strdup ("[]");
|
||||
}
|
||||
PJ *pj = pj_new ();
|
||||
pj = pj_new ();
|
||||
pj_a (pj);
|
||||
RListIter *it;
|
||||
DartStringInfo *si;
|
||||
r_list_foreach (strings, it, si) {
|
||||
if (si) {
|
||||
dump_string_json (pj, si, refs);
|
||||
}
|
||||
}
|
||||
pj_end (pj);
|
||||
return pj_drain (pj);
|
||||
} else {
|
||||
sb = r_strbuf_new (fmt == 'r' && !quiet? "# Dart Strings\n": "");
|
||||
}
|
||||
if (!strings) {
|
||||
return strdup ("# No strings found\n");
|
||||
}
|
||||
const bool quiet = ctx && ctx->quiet;
|
||||
RStrBuf *sb = r_strbuf_new (fmt == 'r' && !quiet? "# Dart Strings\n": "");
|
||||
ut64 count = 0;
|
||||
RListIter *it;
|
||||
DartStringInfo *si;
|
||||
r_list_foreach (strings, it, si) {
|
||||
dump_string_text (sb, si, fmt, quiet, refs);
|
||||
if (ctx->str_limit && count >= ctx->str_limit) {
|
||||
break;
|
||||
}
|
||||
if (!string_matches (ctx, rx, si)) {
|
||||
continue;
|
||||
}
|
||||
if (pj) {
|
||||
dump_string_json (pj, si, refs);
|
||||
} else {
|
||||
dump_string_text (sb, si, fmt, quiet, refs);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
r_regex_free (rx);
|
||||
if (pj) {
|
||||
pj_end (pj);
|
||||
return pj_drain (pj);
|
||||
}
|
||||
if (fmt == 'r' && !quiet) {
|
||||
r_strbuf_appendf (sb, "# Total: %d strings\n", r_list_length (strings));
|
||||
r_strbuf_appendf (sb, "# Total: %" PFMT64u " strings\n", count);
|
||||
}
|
||||
return r_strbuf_drain (sb);
|
||||
}
|
||||
@@ -874,8 +906,12 @@ char *dart_pool_dump_strings(DartCtx *ctx, int fmt) {
|
||||
}
|
||||
|
||||
char *dart_pool_dump_strings_fuzzy(DartCtx *ctx, int fmt) {
|
||||
// stop carving early only when every scanned string is going to be printed
|
||||
const bool filtered = ctx->str_minlen > 0 || ctx->str_maxlen > 0 || R_STR_ISNOTEMPTY (ctx->str_filter);
|
||||
ctx->str_scan_limit = filtered? 0: ctx->str_limit;
|
||||
DartRecoveryModel model = { 0 };
|
||||
dart_recovery_model_load (ctx, &model, DART_RECOVERY_STRINGS | DART_RECOVERY_CLASSES | DART_RECOVERY_STRING_REFS);
|
||||
ctx->str_scan_limit = 0;
|
||||
char *out = dump_strings_list (ctx, model.strings, fmt);
|
||||
dart_recovery_model_fini (&model);
|
||||
return out;
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#define R2FLUTTER_CFG_MAPFILE "r2flutter.mapfile"
|
||||
#define R2FLUTTER_CFG_NAMEPOOL "r2flutter.namepool"
|
||||
#define R2FLUTTER_CFG_PROFILE "r2flutter.profile"
|
||||
#define R2FLUTTER_CFG_STR_LIMIT "r2flutter.str.limit"
|
||||
#define R2FLUTTER_CFG_STR_MINLEN "r2flutter.str.minlen"
|
||||
#define R2FLUTTER_CFG_STR_MAXLEN "r2flutter.str.maxlen"
|
||||
#define R2FLUTTER_CFG_STR_FILTER "r2flutter.str.filter"
|
||||
|
||||
typedef struct {
|
||||
char action;
|
||||
@@ -36,6 +40,14 @@ static bool r2flutter_core_init(RCorePluginSession *cps) {
|
||||
r_config_node_desc (node, "Enable heuristic name-pool fallback resolution");
|
||||
node = r_config_set (cfg, R2FLUTTER_CFG_PROFILE, "");
|
||||
r_config_node_desc (node, "Override Dart snapshot profile by 32-byte hash or Dart version");
|
||||
node = r_config_set_i (cfg, R2FLUTTER_CFG_STR_LIMIT, 0);
|
||||
r_config_node_desc (node, "Maximum number of strings to print (0 = unlimited)");
|
||||
node = r_config_set_i (cfg, R2FLUTTER_CFG_STR_MINLEN, 0);
|
||||
r_config_node_desc (node, "Skip printing strings shorter than this length");
|
||||
node = r_config_set_i (cfg, R2FLUTTER_CFG_STR_MAXLEN, 0);
|
||||
r_config_node_desc (node, "Skip printing strings longer than this length (0 = unlimited)");
|
||||
node = r_config_set (cfg, R2FLUTTER_CFG_STR_FILTER, "");
|
||||
r_config_node_desc (node, "Only print strings matching this extended regex");
|
||||
r_config_lock (cfg, true);
|
||||
return true;
|
||||
}
|
||||
@@ -49,6 +61,10 @@ static bool r2flutter_core_fini(RCorePluginSession *cps) {
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_MAPFILE);
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_NAMEPOOL);
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_PROFILE);
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_STR_LIMIT);
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_STR_MINLEN);
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_STR_MAXLEN);
|
||||
r_config_rm (cfg, R2FLUTTER_CFG_STR_FILTER);
|
||||
r_config_lock (cfg, true);
|
||||
#endif
|
||||
return true;
|
||||
@@ -57,6 +73,10 @@ static bool r2flutter_core_fini(RCorePluginSession *cps) {
|
||||
static void r2flutter_apply_config(RCore *core, DartCtx *dctx) {
|
||||
dctx->obf_map_path = r_config_get (core->config, R2FLUTTER_CFG_MAPFILE);
|
||||
dctx->use_name_pool = r_config_get_b (core->config, R2FLUTTER_CFG_NAMEPOOL);
|
||||
dctx->str_limit = r_config_get_i (core->config, R2FLUTTER_CFG_STR_LIMIT);
|
||||
dctx->str_minlen = (int)r_config_get_i (core->config, R2FLUTTER_CFG_STR_MINLEN);
|
||||
dctx->str_maxlen = (int)r_config_get_i (core->config, R2FLUTTER_CFG_STR_MAXLEN);
|
||||
dctx->str_filter = r_config_get (core->config, R2FLUTTER_CFG_STR_FILTER);
|
||||
const char *profile = r_config_get (core->config, R2FLUTTER_CFG_PROFILE);
|
||||
if (R_STR_ISNOTEMPTY (profile) && !dart_ctx_set_profile_override (dctx, profile)) {
|
||||
R_LOG_WARN ("Ignoring unsupported Dart snapshot profile override: %s", profile);
|
||||
|
||||
@@ -169,6 +169,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
case 'l':
|
||||
dctx.dump_fns_limit = atoi (opt.arg);
|
||||
dctx.str_limit = r_num_get (NULL, opt.arg);
|
||||
break;
|
||||
case 'n':
|
||||
dctx.use_name_pool = true;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
NAME=r2-strings-config-mafia
|
||||
FILE=bins/android/mafia/libapp.so
|
||||
CMDS=<<EOF
|
||||
L ../src/r2/core_flutter.dylib
|
||||
L ../src/r2/core_flutter.so
|
||||
e r2flutter.str.limit=3
|
||||
r2flutter -q -zz
|
||||
?e --
|
||||
e r2flutter.str.filter=^https?://
|
||||
r2flutter -q -zz
|
||||
?e --
|
||||
e r2flutter.str.filter=
|
||||
e r2flutter.str.minlen=41
|
||||
e r2flutter.str.maxlen=42
|
||||
r2flutter -zz
|
||||
?e --
|
||||
e r2flutter.str.minlen=0
|
||||
e r2flutter.str.maxlen=0
|
||||
e r2flutter.str.limit=2
|
||||
e r2flutter.str.filter=^ab
|
||||
r2flutter -j -zz
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
<optimized out>
|
||||
Handle
|
||||
MonomorphicSmiableCall
|
||||
|
||||
--
|
||||
http://www.w3.org/XML/1998/namespace
|
||||
http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd
|
||||
https://www.youtube.com/watch?v=
|
||||
|
||||
--
|
||||
0x0004a5e8 42 :lib "_createBuiltInForegroundPainters@401245603"
|
||||
0x0004b7d4 41 :lib "package:qr_flutter/src/qr_image_view.dart"
|
||||
0x0004bab3 42 :lib "expected-closing-tag-but-got-right-bracket"
|
||||
|
||||
--
|
||||
[{"ref":12,"len":8,"value":"abstract","category":"lib","two_byte":false,"canonical":true,"addr":2307},{"ref":209,"len":8,"value":"absolute","category":"lib","two_byte":false,"canonical":true,"addr":5339}]
|
||||
EOF
|
||||
RUN
|
||||
Reference in new issue
Block a user