From 2a0b3e938454f3fa80e0330b72e2b26585393550 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 10 Dec 2024 14:50:35 -0500 Subject: [PATCH 001/157] Sorry mister, we don't do search no longer. --- librz/core/cmd/cmd_search.c | 905 +----------------------------------- 1 file changed, 1 insertion(+), 904 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index bb5e501f19a..71aad4941aa 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -1770,907 +1770,4 @@ static void __core_cmd_search_asm_byteswap(RzCore *core, int nth) { } } -RZ_IPI int rz_cmd_search(void *data, const char *input) { - bool dosearch = false; - int ret = true; - RzCore *core = (RzCore *)data; - struct search_parameters param = { - .core = core, - .cmd_hit = rz_config_get(core->config, "cmd.hit"), - .outmode = 0, - .inverse = false, - .aes_search = false, - .privkey_search = false, - .regex_search = false, - }; - if (!param.cmd_hit) { - param.cmd_hit = ""; - } - RzSearch *search = core->search; - int ignorecase = false; - int param_offset = 2; - char *inp; - if (!core || !core->io) { - RZ_LOG_ERROR("core: Can't search if we don't have an open file.\n"); - return false; - } - if (core->in_search) { - RZ_LOG_ERROR("core: Can't search from within a search.\n"); - return false; - } - if (input[0] == '/') { - if (core->lastsearch) { - input = core->lastsearch; - } else { - RZ_LOG_ERROR("core: No previous search done\n"); - return false; - } - } else { - free(core->lastsearch); - core->lastsearch = rz_str_dup(input); - } - - core->in_search = true; - rz_flag_space_push(core->flags, "search"); - const ut64 search_from = rz_config_get_i(core->config, "search.from"), - search_to = rz_config_get_i(core->config, "search.to"); - if (search_from > search_to && search_to) { - RZ_LOG_ERROR("core: search.from > search.to is not supported\n"); - ret = false; - goto beach; - } - // {.addr = UT64_MAX, .size = 0} means search range is unspecified - RzInterval search_itv = { search_from, search_to - search_from }; - bool empty_search_itv = search_from == search_to && search_from != UT64_MAX; - if (empty_search_itv) { - RZ_LOG_ERROR("core: `from` address is equal `to`\n"); - ret = false; - goto beach; - } - // TODO full address cannot be represented, shrink 1 byte to [0, UT64_MAX) - if (search_from == UT64_MAX && search_to == UT64_MAX) { - search_itv.addr = 0; - search_itv.size = UT64_MAX; - } - - c = 0; - - searchshow = rz_config_get_i(core->config, "search.show"); - param.mode = rz_config_get(core->config, "search.in"); - param.boundaries = rz_core_get_boundaries_select(core, "search.from", "search.to", "search.in"); - - /* - this introduces a bug until we implement backwards search - for all search types - if (__to < __from) { - eprintf ("Invalid search range. Check 'e search.{from|to}'\n"); - return false; - } - since the backward search will be implemented soon I'm not gonna stick - checks for every case in switch // jjdredd - remove when everything is done - */ - - core->search->align = rz_config_get_i(core->config, "search.align"); - searchflags = rz_config_get_i(core->config, "search.flags"); - core->search->maxhits = rz_config_get_i(core->config, "search.maxhits"); - searchprefix = rz_config_get(core->config, "search.prefix"); - core->search->overlap = rz_config_get_i(core->config, "search.overlap"); - core->search->bckwrds = false; - - /* Quick & dirty check for json output */ - if (input[0] && (input[1] == 'j') && (input[0] != ' ')) { - param.outmode = RZ_MODE_JSON; - param_offset++; - } - param.pj = pj_new(); - -reread: - switch (*input) { - case '!': - input++; - param.inverse = true; - goto reread; - case 'b': // "/b" backward search - if (*(++input) == '?') { - RZ_LOG_ERROR("core: Usage: /b [value] backward search, see '/?'\n"); - goto beach; - } - search->bckwrds = true; - if (core->offset) { - RzInterval itv = { 0, core->offset }; - if (!rz_itv_overlap(search_itv, itv)) { - ret = false; - goto beach; - } else { - search_itv = rz_itv_intersect(search_itv, itv); - } - } - goto reread; - case 'o': { // "/o" print the offset of the Previous opcode - ut64 addr, n = input[param_offset - 1] ? rz_num_math(core->num, input + param_offset) : 1; - n = RZ_ABS((st64)n); - if (((st64)n) < 1) { - n = 1; - } - if (!rz_core_prevop_addr(core, core->offset, n, &addr)) { - addr = UT64_MAX; - (void)rz_core_asm_bwdis_len(core, NULL, &addr, n); - } - if (param.outmode == RZ_MODE_JSON) { - rz_cons_printf("[%" PFMT64u "]", addr); - } else { - rz_cons_printf("0x%08" PFMT64x "\n", addr); - } - break; - } - case 'O': { // "/O" alternative to "/o" - ut64 addr, n = input[param_offset - 1] ? rz_num_math(core->num, input + param_offset) : 1; - if (!n) { - n = 1; - } - addr = rz_core_prevop_addr_force(core, core->offset, n); - if (param.outmode == RZ_MODE_JSON) { - rz_cons_printf("[%" PFMT64u "]", addr); - } else { - rz_cons_printf("0x%08" PFMT64x "\n", addr); - } - break; - } - case 'r': // "/r" - { - ut64 n = (input[1] == ' ' || (input[1] && input[2] == ' ')) - ? rz_num_math(core->num, input + 2) - : UT64_MAX; - if (n == 0LL) { - RZ_LOG_ERROR("core: Cannot find null references.\n"); - break; - } - switch (input[1]) { - case 'c': // "/rc" - { - RzListIter *iter; - RzIOMap *map; - rz_list_foreach (param.boundaries, iter, map) { - eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); - rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 'c'); - } - } break; - case 'a': // "/ra" - { - RzListIter *iter; - RzIOMap *map; - rz_list_foreach (param.boundaries, iter, map) { - eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); - rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 0); - } - } break; - case 'r': // "/rr" - read refs - { - RzListIter *iter; - RzIOMap *map; - rz_list_foreach (param.boundaries, iter, map) { - eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); - rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 'r'); - } - } break; - case 'w': // "/rw" - write refs - { - RzListIter *iter; - RzIOMap *map; - rz_list_foreach (param.boundaries, iter, map) { - eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); - rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 'w'); - } - } break; - case ' ': // "/r $$" - case 0: // "/r" - { - RzListIter *iter; - RzIOMap *map; - rz_list_foreach (param.boundaries, iter, map) { - ut64 from = map->itv.addr; - ut64 to = rz_itv_end(map->itv); - if (input[param_offset - 1] == ' ') { - rz_core_analysis_search(core, from, to, - rz_num_math(core->num, input + 2), 0); - do_ref_search(core, rz_num_math(core->num, input + 2), from, to, ¶m); - } else { - rz_core_analysis_search(core, from, to, core->offset, 0); - do_ref_search(core, core->offset, from, to, ¶m); - } - if (rz_cons_is_breaked()) { - break; - } - } - } break; - case '?': - rz_core_cmd_help(core, help_msg_slash_r); - break; - } - } break; - case 'a': // "/a" - if (input[1] == '?') { - rz_core_cmd_help(core, help_msg_slash_a); - } else if (input[1] == 'd') { // "ad" - dosearch = 0; - do_asm_search(core, ¶m, input + 2, 0, search_itv); - } else if (input[1] == 'e') { // "ae" - dosearch = 0; - do_asm_search(core, ¶m, input + 2, 'e', search_itv); - } else if (input[1] == 'c') { // "/ac" - dosearch = 0; - do_asm_search(core, ¶m, input + 2, 'c', search_itv); - } else if (input[1] == 'o') { // "/ao" - dosearch = 0; - do_asm_search(core, ¶m, input + 2, 'o', search_itv); - } else if (input[1] == 'a') { // "/aa" - dosearch = 0; - do_asm_search(core, ¶m, input + 2, 'a', search_itv); - } else if (input[1] == 'i') { // "/ai" - do_asm_search(core, ¶m, input + 2, 'i', search_itv); - } else if (input[1] == '1') { // "a1" - __core_cmd_search_asm_byteswap(core, (int)rz_num_math(core->num, input + 2)); - } else if (input[1] == 'I') { // "/aI" - infinite - __core_cmd_search_asm_infinite(core, rz_str_trim_head_ro(input + 1)); - } else if (input[1] == ' ') { - if (input[param_offset - 1]) { - char *kwd = rz_core_asm_search(core, input + param_offset); - if (!kwd) { - ret = false; - goto beach; - } - dosearch = true; - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - rz_search_kw_add(core->search, - rz_search_keyword_new_hexmask(kwd, NULL)); - free(kwd); - } - } else if (input[1] == 's') { - if (input[2] == 'l') { // "asl" - rz_core_cmd0(core, "asl"); - } else { // "as" - do_syscall_search(core, ¶m); - } - dosearch = false; - } else { - dosearch = do_analysis_search(core, ¶m, input + 1); - } - break; - case 'c': { // "/c" - dosearch = true; - switch (input[1]) { - case 'c': // "/cc" - { - ret = false; - char *space = strchr(input, ' '); - const char *arg = space ? rz_str_trim_head_ro(space + 1) : NULL; - if (!arg || input[2] == '?') { - RZ_LOG_ERROR("core: Usage: /cc[aAdlpb] [hashname] [hexpairhashvalue]\n"); - RZ_LOG_ERROR("core: /cca - lowercase alphabet chars only\n"); - RZ_LOG_ERROR("core: /ccA - uppercase alphabet chars only\n"); - RZ_LOG_ERROR("core: /ccl - letters (lower + upper alphabet chars)\n"); - RZ_LOG_ERROR("core: /ccd - digits (only numbers)\n"); - RZ_LOG_ERROR("core: /ccp - printable (alpha + digit)\n"); - RZ_LOG_ERROR("core: /ccb - binary (any number is valid)\n"); - goto beach; - } - char *s = rz_str_dup(arg); - char *sp = strchr(s, ' '); - int mode = input[2]; - if (sp) { - *sp = 0; - sp++; - char *hashName = s; - ut8 *hashValue = (ut8 *)rz_str_dup(sp); - if (hashValue) { - if (!rz_str_startswith((const char *)hashValue, "0x")) { - // TODO: support bigger hashes - int hashLength = 4; - ut32 n = (ut32)rz_num_get(NULL, (const char *)hashValue); - memcpy(hashValue, (const ut8 *)&n, sizeof(ut32)); - search_collisions(core, hashName, hashValue, hashLength, mode); - } else { - int hashLength = rz_hex_str2bin(sp, hashValue); - if (hashLength > 0) { - search_collisions(core, hashName, hashValue, hashLength, mode); - } else { - RZ_LOG_ERROR("core: Invalid expected hash hexpairs.\n"); - } - } - free(hashValue); - } else { - RZ_LOG_ERROR("core: Cannot allocate memory.\n"); - } - ret = true; - } else { - RZ_LOG_ERROR("core: Usage: /cc [hashname] [hexpairhashvalue]\n"); - RZ_LOG_ERROR("core: Usage: /CC to search ascii collisions\n"); - } - free(s); - goto beach; - } break; - case 'd': // "cd" - { - // Certificate with version number - RzSearchKeyword *kw_1 = rz_search_keyword_new_hex("30820000308100A0030201", "ffff0000fffc00ffffffff", NULL); - RzSearchKeyword *kw_2 = rz_search_keyword_new_hex("3082000030820000A0030201", "ffff0000fffc0000ffffffff", NULL); - // Certificate with serial number - RzSearchKeyword *kw_3 = rz_search_keyword_new_hex("308200003082000002", "ffff0000fffc0000ff", NULL); - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - if (kw_1 && kw_2 && kw_3) { - rz_search_kw_add(core->search, kw_1); - rz_search_kw_add(core->search, kw_2); - rz_search_kw_add(core->search, kw_3); - rz_search_begin(core->search); - } else { - RZ_LOG_ERROR("core: null pointer on search keyword\n"); - dosearch = false; - } - } break; - case 'a': // "ca" - { - RzSearchKeyword *kw; - kw = rz_search_keyword_new_hexmask("00", NULL); - // AES search is done over 40 bytes - kw->keyword_length = AES_SEARCH_LENGTH; - rz_search_reset(core->search, RZ_SEARCH_AES); - rz_search_kw_add(search, kw); - rz_search_begin(core->search); - param.aes_search = true; - break; - } - case 'r': // "cr" - { - RzSearchKeyword *kw; - kw = rz_search_keyword_new_hexmask("00", NULL); - // Private key search is at least 11 bytes - kw->keyword_length = PRIVATE_KEY_SEARCH_LENGTH; - rz_search_reset(core->search, RZ_SEARCH_PRIV_KEY); - rz_search_kw_add(search, kw); - rz_search_begin(core->search); - param.privkey_search = true; - break; - } - default: { - dosearch = false; - rz_core_cmd_help(core, help_msg_slash_c); - } - } - } break; - case 'm': // "/m" - dosearch = false; - if (input[1] == '?') { // "/m?" - rz_core_cmd_help(core, help_msg_slash_m); - } else if (input[1] == 'b') { // "/mb" - bool bin_verbose = rz_config_get_i(core->config, "bin.verbose"); - rz_config_set_i(core->config, "bin.verbose", false); - // TODO : iter maps? - cmd_search_bin(core, search_itv); - rz_config_set_i(core->config, "bin.verbose", bin_verbose); - } else if (input[1] == ' ' || input[1] == '\0' || param.outmode == RZ_MODE_JSON) { - int ret; - const char *file = input[param_offset - 1] ? input + param_offset : NULL; - ut64 addr = search_itv.addr; - RzListIter *iter; - RzIOMap *map; - if (param.outmode == RZ_MODE_JSON) { - pj_a(param.pj); - } - rz_core_magic_reset(core); - int maxHits = rz_config_get_i(core->config, "search.maxhits"); - int hits = 0; - rz_list_foreach (param.boundaries, iter, map) { - if (param.outmode != RZ_MODE_JSON) { - eprintf("-- %llx %llx\n", map->itv.addr, rz_itv_end(map->itv)); - } - rz_cons_break_push(NULL, NULL); - for (addr = map->itv.addr; addr < rz_itv_end(map->itv); addr++) { - if (rz_cons_is_breaked()) { - break; - } - ret = rz_core_magic_at(core, file, addr, 99, false, param.outmode == RZ_MODE_JSON ? param.pj : NULL, &hits); - if (ret == -1) { - // something went terribly wrong. - break; - } - if (maxHits && hits >= maxHits) { - break; - } - addr += ret - 1; - } - rz_cons_clear_line(1); - rz_cons_break_pop(); - } - if (param.outmode == RZ_MODE_JSON) { - pj_end(param.pj); - } - } else { - RZ_LOG_ERROR("core: Usage: /m [file]\n"); - } - rz_cons_clear_line(1); - break; - case 'p': // "/p" - { - if (input[param_offset - 1]) { - int ps = atoi(input + param_offset); - if (ps > 1) { - RzListIter *iter; - RzIOMap *map; - rz_list_foreach (param.boundaries, iter, map) { - eprintf("-- %llx %llx\n", map->itv.addr, rz_itv_end(map->itv)); - rz_cons_break_push(NULL, NULL); - rz_search_pattern_size(core->search, ps); - rz_search_pattern(core->search, map->itv.addr, rz_itv_end(map->itv)); - rz_cons_break_pop(); - } - break; - } - } - RZ_LOG_ERROR("core: Invalid pattern size (must be > 0)\n"); - } break; - case 'P': // "/P" - search_similar_pattern(core, atoi(input + 1), ¶m); - break; - case 'V': // "/V" - { - if (input[2] == 'j') { - param.outmode = RZ_MODE_JSON; - param_offset++; - } else if (strchr(input + 1, '*')) { - param.outmode = RZ_MODE_RIZINCMD; - } - int err = 1, vsize = atoi(input + 1); - const char *num_str = input + param_offset + 1; - if (vsize && input[2] && num_str) { - if (param.outmode == RZ_MODE_JSON) { - pj_a(param.pj); - } - char *w = strchr(num_str, ' '); - if (w) { - *w++ = 0; - ut64 vmin = rz_num_math(core->num, num_str); - ut64 vmax = rz_num_math(core->num, w); - if (vsize > 0) { - RzIOMap *map; - RzListIter *iter; - rz_list_foreach (param.boundaries, iter, map) { - err = 0; - int hits = rz_core_search_value_in_range(core, map->itv, - vmin, vmax, vsize, - _CbInRangeSearchV, ¶m); - if (param.outmode != RZ_MODE_JSON) { - eprintf("hits: %d\n", hits); - } - } - } - } - if (param.outmode == RZ_MODE_JSON) { - pj_end(param.pj); - } - } - if (err) { - RZ_LOG_ERROR("core: Usage: /V[1|2|4|8] [minval] [maxval]\n"); - } - } - dosearch = false; - break; - case 'v': // "/v" - if (input[1]) { - if (input[1] == '?') { - rz_cons_print("Usage: /v[1|2|4|8] [value]\n"); - break; - } - if (input[2] == 'j') { - param.outmode = RZ_MODE_JSON; - param_offset++; - } - } - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - char *v_str = (char *)rz_str_trim_head_ro(input + param_offset); - RzList *nums = rz_num_str_split_list(v_str); - int len = rz_list_length(nums); - int bsize = 0; - ut8 *v_buf = NULL; - switch (input[1]) { - case '8': - if (input[param_offset]) { - bsize = sizeof(ut64) * len; - v_buf = v_writebuf(core, nums, len, '8', bsize); - } else { - RZ_LOG_ERROR("core: Usage: /v8 value\n"); - } - break; - case '1': - if (input[param_offset]) { - bsize = sizeof(ut8) * len; - v_buf = v_writebuf(core, nums, len, '1', bsize); - } else { - RZ_LOG_ERROR("core: Usage: /v1 value\n"); - } - break; - case '2': - if (input[param_offset]) { - bsize = sizeof(ut16) * len; - v_buf = v_writebuf(core, nums, len, '2', bsize); - } else { - RZ_LOG_ERROR("core: Usage: /v2 value\n"); - } - break; - default: // default size - case '4': - if (input[param_offset - 1]) { - if (input[param_offset]) { - bsize = sizeof(ut32) * len; - v_buf = v_writebuf(core, nums, len, '4', bsize); - } - } else { - RZ_LOG_ERROR("core: Usage: /v4 value\n"); - } - break; - } - if (v_buf) { - rz_search_kw_add(core->search, - rz_search_keyword_new((const ut8 *)v_buf, bsize, NULL, 0, NULL)); - free(v_buf); - } - rz_search_begin(core->search); - dosearch = true; - break; - case 'w': // "/w" search wide string, includes ignorecase search functionality (/wi cmd)! - if (input[2]) { - if (input[1] == 'j' || input[2] == 'j') { - param.outmode = RZ_MODE_JSON; - } - if (input[1] == 'i' || input[2] == 'i') { - ignorecase = true; - } - } else { - param.outmode = RZ_MODE_RIZINCMD; - } - - size_t shift = 1 + ignorecase; - if (param.outmode == RZ_MODE_JSON) { - shift++; - } - size_t strstart; - const char *p2; - char *p; - strstart = shift + 1; - len = strlen(input + strstart); - inp = calloc((len + 1), 2); - for (p2 = input + strstart, p = inp; *p2; p += 2, p2++) { - if (ignorecase) { - p[0] = tolower((const ut8)*p2); - } else { - p[0] = *p2; - } - p[1] = 0; - } - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - RzSearchKeyword *skw; - skw = rz_search_keyword_new((const ut8 *)inp, len * 2, NULL, 0, NULL); - free(inp); - if (skw) { - skw->icase = ignorecase; - rz_search_kw_add(core->search, skw); - rz_search_begin(core->search); - dosearch = true; - } else { - RZ_LOG_ERROR("core: Invalid keyword\n"); - break; - } - break; - case 'i': // "/i" - if (input[param_offset - 1] != ' ') { - RZ_LOG_ERROR("core: Missing ' ' after /i\n"); - ret = false; - goto beach; - } - ignorecase = true; - // fallthrough - case 'j': // "/j" - if (input[0] == 'j' && input[1] == ' ') { - param.outmode = RZ_MODE_JSON; - } - // fallthrough - case ' ': // "/ " search string - inp = rz_str_dup(input + 1 + ignorecase + (param.outmode == RZ_MODE_JSON ? 1 : 0)); - len = rz_str_unescape(inp); - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - { - RzSearchKeyword *skw; - skw = rz_search_keyword_new((const ut8 *)inp, len, NULL, 0, NULL); - free(inp); - if (skw) { - skw->icase = ignorecase; - skw->type = RZ_SEARCH_KEYWORD_TYPE_STRING; - rz_search_kw_add(core->search, skw); - } else { - RZ_LOG_ERROR("core: Invalid keyword\n"); - break; - } - } - rz_search_begin(core->search); - dosearch = true; - break; - case 'e': // "/e" match regexp - if (input[1] == '?') { - RZ_LOG_ERROR("core: Usage: /e /foo/i or /e/foo/i\n"); - } else if (input[1]) { - RzSearchKeyword *kw; - kw = rz_search_keyword_new_regexp(input + 1, NULL); - if (!kw) { - RZ_LOG_ERROR("core: Invalid regexp specified\n"); - break; - } - rz_search_reset(core->search, RZ_SEARCH_REGEXP); - // TODO distance is unused - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - rz_search_kw_add(core->search, kw); - rz_search_begin(core->search); - dosearch = true; - param.regex_search = true; - } else { - RZ_LOG_ERROR("core: Missing regex\n"); - } - break; - case 'E': // "/E" - if (core->bin && core->bin->is_debugger) { - rz_debug_map_sync(core->dbg); - } - do_esil_search(core, ¶m, input); - goto beach; - case 'd': // "/d" search delta key - if (input[1]) { - rz_search_reset(core->search, RZ_SEARCH_DELTAKEY); - rz_search_kw_add(core->search, - rz_search_keyword_new_hexmask(input + param_offset, NULL)); - rz_search_begin(core->search); - dosearch = true; - } else { - RZ_LOG_ERROR("core: Missing delta\n"); - } - break; - case 'h': // "/h" - { - char *p, *arg = rz_str_trim_dup(input + 1); - p = strchr(arg, ' '); - if (p) { - *p++ = 0; - if (*arg == '?') { - RZ_LOG_ERROR("core: Usage: /h md5 [hash] [datalen]\n"); - } else { - ut32 min = UT32_MAX; - ut32 max = UT32_MAX; - char *pmax, *pmin = strchr(p, ' '); - if (pmin) { - *pmin++ = 0; - pmax = strchr(pmin, ' '); - if (pmax) { - *pmax++ = 0; - max = rz_num_math(core->num, pmax); - } - min = rz_num_math(core->num, pmin); - } - search_hash(core, arg, p, min, max, ¶m); - } - } else { - RZ_LOG_ERROR("core: Missing hash. See ph?\n"); - } - free(arg); - } break; - case 'f': // "/f" forward search - if (core->offset) { - RzInterval itv = { core->offset, -core->offset }; - if (!rz_itv_overlap(search_itv, itv)) { - ret = false; - goto beach; - } else { - search_itv = rz_itv_intersect(search_itv, itv); - } - } - break; - case 'g': // "/g" graph search - if (input[1] == '?') { - rz_cons_printf("Usage: /g[g] [fromaddr] @ [toaddr]\n"); - rz_cons_printf("(find all graph paths A to B (/gg follow jumps, see search.count and analysis.depth)"); - } else { - ut64 addr = UT64_MAX; - if (input[1]) { - addr = rz_num_math(core->num, input + 2); - } else { - RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); - if (fcn) { - addr = fcn->addr; - } else { - addr = core->offset; - } - } - const int depth = rz_config_get_i(core->config, "analysis.depth"); - // Va;ifate input length - if (input[1] != '\0') { - rz_core_analysis_paths(core, addr, core->offset, input[1] == 'g', depth, (input[1] == 'j' || input[2] == 'j')); - } - } - break; - case 'F': // "/F" search file /F [file] ([offset] ([sz])) - if (input[param_offset - 1] == ' ') { - int n_args; - char **args = rz_str_argv(input + param_offset, &n_args); - ut8 *buf = NULL; - ut64 offset = 0; - size_t size; - buf = (ut8 *)rz_file_slurp(args[0], &size); - if (!buf) { - RZ_LOG_ERROR("core: Cannot open '%s'\n", args[0]); - rz_str_argv_free(args); - break; - } - if (n_args > 1) { - offset = rz_num_math(core->num, args[1]); - if (size <= offset) { - RZ_LOG_ERROR("core: size <= offset\n"); - rz_str_argv_free(args); - free(buf); - break; - } - } - if (n_args > 2) { - len = rz_num_math(core->num, args[2]); - if (len > size - offset) { - RZ_LOG_ERROR("core: len too large\n"); - rz_str_argv_free(args); - free(buf); - break; - } - } else { - len = size - offset; - } - RzSearchKeyword *kw; - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - kw = rz_search_keyword_new(buf + offset, len, NULL, 0, NULL); - if (kw) { - rz_search_kw_add(core->search, kw); - // eprintf ("Searching %d byte(s)...\n", kw->keyword_length); - rz_search_begin(core->search); - dosearch = true; - } else { - RZ_LOG_ERROR("core: no keyword\n"); - } - - rz_str_argv_free(args); - free(buf); - } else { - RZ_LOG_ERROR("core: Usage: /F[j] [file] ([offset] ([sz]))\n"); - } - break; - case 'x': // "/x" search hex - if (!input[1]) { - RZ_LOG_ERROR("core: missing hexpairs:binmask\n"); - break; - } - if (input[1] == '?') { - rz_core_cmd_help(core, help_msg_slash_x); - } else { - RzSearchKeyword *kw; - char *s, *p = rz_str_dup(input + param_offset); - rz_search_reset(core->search, RZ_SEARCH_KEYWORD); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - s = strchr(p, ':'); - if (s) { - *s++ = 0; - kw = rz_search_keyword_new_hex(p, s, NULL); - } else { - kw = rz_search_keyword_new_hexmask(p, NULL); - } - if (kw) { - rz_search_kw_add(core->search, kw); - // eprintf ("Searching %d byte(s)...\n", kw->keyword_length); - rz_search_begin(core->search); - dosearch = true; - } else { - RZ_LOG_ERROR("core: no keyword\n"); - } - free(p); - } - break; - case 's': // "/s" - do_section_search(core, ¶m, input + 1); - break; - case '+': // "/+" - if (input[1] == ' ') { - // TODO: support /+j - char *buf = malloc(strlen(input) * 2); - char *str = rz_str_dup(input + 2); - int ochunksize; - int i, len, chunksize = rz_config_get_i(core->config, "search.chunk"); - if (chunksize < 1) { - chunksize = core->rasm->bits / 8; - } - len = rz_str_unescape(str); - ochunksize = chunksize = RZ_MIN(len, chunksize); - RZ_LOG_ERROR("core: Using chunksize: %d\n", chunksize); - core->in_search = false; - for (i = 0; i < len; i += chunksize) { - chunksize = ochunksize; - again: - rz_hex_bin2str((ut8 *)str + i, RZ_MIN(chunksize, len - i), buf); - RZ_LOG_ERROR("core: /x %s\n", buf); - rz_core_cmdf(core, "/x %s", buf); - if (core->num->value == 0) { - chunksize--; - if (chunksize < 1) { - RZ_LOG_ERROR("core: Oops\n"); - free(buf); - free(str); - goto beach; - } - RZ_LOG_ERROR("core: Repeat with chunk size %d\n", chunksize); - goto again; - } - } - free(str); - free(buf); - } else { - RZ_LOG_ERROR("core: Usage: /+ [string]\n"); - } - break; - case 'z': // "/z" search strings of min-max range - { - char *p; - ut32 min, max; - if (!input[1]) { - RZ_LOG_ERROR("core: Usage: /z min max\n"); - break; - } - if ((p = strchr(input + 2, ' '))) { - *p = 0; - max = rz_num_math(core->num, p + 1); - } else { - RZ_LOG_ERROR("core: Usage: /z min max\n"); - break; - } - min = rz_num_math(core->num, input + 2); - if (!rz_search_set_string_limits(core->search, min, max)) { - RZ_LOG_ERROR("core: min must be lower than max\n"); - break; - } - rz_search_reset(core->search, RZ_SEARCH_STRING); - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - { - RzSearchKeyword *kw = rz_search_keyword_new_hexmask("00", NULL); - kw->type = RZ_SEARCH_KEYWORD_TYPE_STRING; - rz_search_kw_add(search, kw); - } - rz_search_begin(search); - dosearch = true; - } break; - case '?': // "/?" - rz_core_cmd_help(core, help_msg_slash); - break; - default: - RZ_LOG_ERROR("core: See /? for help.\n"); - break; - } - rz_config_set_i(core->config, "search.kwidx", search->n_kws); - if (dosearch) { - do_string_search(core, search_itv, ¶m); - } -beach: - core->num->value = search->nhits; - core->in_search = false; - rz_flag_space_pop(core->flags); - if (param.outmode == RZ_MODE_JSON) { - rz_cons_println(pj_string(param.pj)); - } - pj_free(param.pj); - rz_list_free(param.boundaries); - rz_search_kw_reset(search); - return ret; -} +RZ_IPI int rz_cmd_search(void *data, const char *input) { return RZ_CMD_STATUS_ERROR; } From 2893fde2197345e34039e122992753a4164cb292 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 10 Dec 2024 15:00:36 -0500 Subject: [PATCH 002/157] Add RzShell handlers for all search commands. --- librz/core/cmd/cmd_search.c | 91 ++++++ librz/core/cmd_descs/cmd_descs.c | 411 ++++++++++++++++++++++++++- librz/core/cmd_descs/cmd_descs.h | 40 ++- librz/core/cmd_descs/cmd_descs.yaml | 6 +- librz/core/cmd_descs/cmd_search.yaml | 320 ++++++++++++++++++++- librz/core/cmd_descs/cmd_seek.yaml | 4 - 6 files changed, 846 insertions(+), 26 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 71aad4941aa..fc5d7f74177 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only #include +#include #include #include #include @@ -1771,3 +1772,93 @@ static void __core_cmd_search_asm_byteswap(RzCore *core, int nth) { } RZ_IPI int rz_cmd_search(void *data, const char *input) { return RZ_CMD_STATUS_ERROR; } + +// "/a" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/ca" +RZ_IPI RzCmdStatus rz_cmd_search_aes_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/cp" +RZ_IPI RzCmdStatus rz_cmd_search_private_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/e" +RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/ei" +RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/g" +RZ_IPI RzCmdStatus rz_cmd_search_graph_path_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/gg" +RZ_IPI RzCmdStatus rz_cmd_search_graph_path_follow_jumps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/h" +RZ_IPI RzCmdStatus rz_cmd_search_hash_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/m" +RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/E" +RZ_IPI RzCmdStatus rz_cmd_search_entropy_section_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/r" +RZ_IPI RzCmdStatus rz_cmd_search_reference_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/v1" +RZ_IPI RzCmdStatus rz_cmd_search_value_8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/v2" +RZ_IPI RzCmdStatus rz_cmd_search_value_16_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/v4" +RZ_IPI RzCmdStatus rz_cmd_search_value_32_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/v8" +RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/x" +RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/z" +RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} + +// "/zi" +RZ_IPI RzCmdStatus rz_cmd_search_string_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return RZ_CMD_STATUS_NONEXISTINGCMD; +} diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index b19f68f8105..c5e8ea60a20 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -14,6 +14,9 @@ static const RzCmdDescDetail alias_details[2]; static const RzCmdDescDetail oparen__details[2]; static const RzCmdDescDetail pointer_details[2]; static const RzCmdDescDetail interpret_macro_multiple_details[2]; +static const RzCmdDescDetail cmd_search_hash_block_details[2]; +static const RzCmdDescDetail slash_v_details[2]; +static const RzCmdDescDetail cmd_search_hex_details[2]; static const RzCmdDescDetail base64_encode_details[2]; static const RzCmdDescDetail base64_decode_details[2]; static const RzCmdDescDetail print_boundaries_prot_details[2]; @@ -105,10 +108,25 @@ static const RzCmdDescArg interpret_output_args[2]; static const RzCmdDescArg interpret_pipe_args[2]; static const RzCmdDescArg interpret_macro_args[4]; static const RzCmdDescArg interpret_macro_multiple_args[4]; +static const RzCmdDescArg cmd_search_assemble_args[2]; +static const RzCmdDescArg cmd_search_regex_raw_sensitive_args[2]; +static const RzCmdDescArg cmd_search_regex_raw_insensitive_args[2]; +static const RzCmdDescArg cmd_search_graph_path_args[3]; +static const RzCmdDescArg cmd_search_graph_path_follow_jumps_args[3]; +static const RzCmdDescArg cmd_search_hash_block_args[3]; +static const RzCmdDescArg cmd_search_entropy_section_args[2]; +static const RzCmdDescArg cmd_search_reference_args[2]; static const RzCmdDescArg cmd_info_gadget_args[2]; static const RzCmdDescArg cmd_search_gadget_args[2]; static const RzCmdDescArg cmd_query_gadget_args[2]; static const RzCmdDescArg cmd_detail_gadget_args[2]; +static const RzCmdDescArg cmd_search_value_8_args[2]; +static const RzCmdDescArg cmd_search_value_16_args[2]; +static const RzCmdDescArg cmd_search_value_32_args[2]; +static const RzCmdDescArg cmd_search_value_64_args[2]; +static const RzCmdDescArg cmd_search_hex_args[2]; +static const RzCmdDescArg cmd_search_string_sensitive_args[3]; +static const RzCmdDescArg cmd_search_string_insensitive_args[3]; static const RzCmdDescArg remote_args[3]; static const RzCmdDescArg remote_send_args[3]; static const RzCmdDescArg remote_add_args[2]; @@ -1378,11 +1396,180 @@ static const RzCmdDescHelp interpret_macro_multiple_help = { .args = interpret_macro_multiple_args, }; -static const RzCmdDescHelp cmd_search_help = { +static const RzCmdDescHelp slash__help = { .summary = "Search for bytes, regexps, patterns, ..", }; +static const RzCmdDescArg cmd_search_assemble_args[] = { + { + .name = "opcodes", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_help = { + .summary = "Assemble the opcodes and search its bytes", + .args = cmd_search_assemble_args, +}; + +static const RzCmdDescHelp slash_c_help = { + .summary = "Cryptographic material search", +}; +static const RzCmdDescArg cmd_search_aes_key_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_aes_key_help = { + .summary = "Search for AES keys", + .args = cmd_search_aes_key_args, +}; + +static const RzCmdDescArg cmd_search_private_key_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_private_key_help = { + .summary = "Search for private RSA/ECC/EdDSA keys", + .args = cmd_search_private_key_args, +}; + +static const RzCmdDescHelp slash_e_help = { + .summary = "Raw regular expression search.", +}; +static const RzCmdDescArg cmd_search_regex_raw_sensitive_args[] = { + { + .name = "regex", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_regex_raw_sensitive_help = { + .summary = "Raw regular expression search (case-sensitive).", + .args = cmd_search_regex_raw_sensitive_args, +}; + +static const RzCmdDescArg cmd_search_regex_raw_insensitive_args[] = { + { + .name = "regex", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_regex_raw_insensitive_help = { + .summary = "Raw regular expression search (case-insensitive).", + .args = cmd_search_regex_raw_insensitive_args, +}; + +static const RzCmdDescHelp slash_g_help = { + .summary = "Search for all graph paths A to B (/gg follow jumps, see search.count and analysis.depth).", +}; +static const RzCmdDescArg cmd_search_graph_path_args[] = { + { + .name = "from", + .type = RZ_CMD_ARG_TYPE_RZNUM, + + }, + { + .name = "to", + .type = RZ_CMD_ARG_TYPE_RZNUM, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_graph_path_help = { + .summary = "Search for all graph paths A to B (does not follow jumps).", + .args = cmd_search_graph_path_args, +}; + +static const RzCmdDescArg cmd_search_graph_path_follow_jumps_args[] = { + { + .name = "from", + .type = RZ_CMD_ARG_TYPE_RZNUM, + + }, + { + .name = "to", + .type = RZ_CMD_ARG_TYPE_RZNUM, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_graph_path_follow_jumps_help = { + .summary = "Search for all graph paths A to B (follow jumps, see `search.count` and `analysis.depth`).", + .args = cmd_search_graph_path_follow_jumps_args, +}; + +static const RzCmdDescDetailEntry cmd_search_hash_block_Usage_space_example_detail_entries[] = { + { .text = "MD5 hash search within blocks of 512 bytes.", .arg_str = NULL, .comment = "/h md5 0bc8f8c426b74ffaedac8330a7464014 @! 512" }, + { 0 }, +}; +static const RzCmdDescDetail cmd_search_hash_block_details[] = { + { .name = "Usage example", .entries = cmd_search_hash_block_Usage_space_example_detail_entries }, + { 0 }, +}; +static const RzCmdDescArg cmd_search_hash_block_args[] = { + { + .name = "algo", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "hash", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_hash_block_help = { + .summary = "Search for blocks that have the same hash (see also command `ph`).", + .details = cmd_search_hash_block_details, + .args = cmd_search_hash_block_args, +}; + +static const RzCmdDescArg cmd_search_magic_const_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_magic_const_help = { + .summary = "Magic constants search.", + .args = cmd_search_magic_const_args, +}; + +static const RzCmdDescArg cmd_search_entropy_section_args[] = { + { + .name = "threshold", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_entropy_section_help = { + .summary = "Entropy search on sections by grouping in blocks.", + .args = cmd_search_entropy_section_args, +}; + +static const RzCmdDescArg cmd_search_reference_args[] = { + { + .name = "address", + .type = RZ_CMD_ARG_TYPE_RZNUM, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_reference_help = { + .summary = "Reference search.", + .args = cmd_search_reference_args, +}; + static const RzCmdDescHelp slash_R_help = { - .summary = "List ROP Gadgets", + .summary = "Search, List, Query for ROP Gadgets", }; static const RzCmdDescArg cmd_info_gadget_args[] = { { @@ -1445,6 +1632,140 @@ static const RzCmdDescHelp cmd_detail_gadget_help = { .args = cmd_detail_gadget_args, }; +static const RzCmdDescDetailEntry slash_v_Usage_space_example_detail_entries[] = { + { .text = "512 value search of its 32-bit representation", .arg_str = NULL, .comment = "/v4 512" }, + { 0 }, +}; +static const RzCmdDescDetail slash_v_details[] = { + { .name = "Usage example", .entries = slash_v_Usage_space_example_detail_entries }, + { 0 }, +}; +static const RzCmdDescHelp slash_v_help = { + .summary = "Value search.", + .details = slash_v_details, +}; +static const RzCmdDescArg cmd_search_value_8_args[] = { + { + .name = "value8", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_8_help = { + .summary = "8-bit value search.", + .args = cmd_search_value_8_args, +}; + +static const RzCmdDescArg cmd_search_value_16_args[] = { + { + .name = "value16", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_16_help = { + .summary = "16-bit size value search.", + .args = cmd_search_value_16_args, +}; + +static const RzCmdDescArg cmd_search_value_32_args[] = { + { + .name = "value32", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_32_help = { + .summary = "32-bit size value search.", + .args = cmd_search_value_32_args, +}; + +static const RzCmdDescArg cmd_search_value_64_args[] = { + { + .name = "value64", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_64_help = { + .summary = "64-bit size value search.", + .args = cmd_search_value_64_args, +}; + +static const RzCmdDescDetailEntry cmd_search_hex_Usage_space_example_detail_entries[] = { + { .text = "Hexadecimal search of the exact bytes", .arg_str = NULL, .comment = "/x ffcc33" }, + { .text = "Hexadecimal search of the bytes with ignored nibbles", .arg_str = NULL, .comment = "/x ff..33" }, + { .text = "Hexadecimal search of the bytes with bytes mask", .arg_str = NULL, .comment = "/x ff43:ffd0" }, + { 0 }, +}; +static const RzCmdDescDetail cmd_search_hex_details[] = { + { .name = "Usage example", .entries = cmd_search_hex_Usage_space_example_detail_entries }, + { 0 }, +}; +static const RzCmdDescArg cmd_search_hex_args[] = { + { + .name = "bytes", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_hex_help = { + .summary = "Raw hexadecimal search.", + .details = cmd_search_hex_details, + .args = cmd_search_hex_args, +}; + +static const RzCmdDescHelp slash_z_help = { + .summary = "String search.", +}; +static const char *cmd_search_string_sensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; +static const RzCmdDescArg cmd_search_string_sensitive_args[] = { + { + .name = "string", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "encoding", + .type = RZ_CMD_ARG_TYPE_CHOICES, + .optional = true, + .choices.choices = cmd_search_string_sensitive_encoding_choices, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_string_sensitive_help = { + .summary = "String search (case-sensitive).", + .args = cmd_search_string_sensitive_args, +}; + +static const char *cmd_search_string_insensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; +static const RzCmdDescArg cmd_search_string_insensitive_args[] = { + { + .name = "string", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "encoding", + .type = RZ_CMD_ARG_TYPE_CHOICES, + .optional = true, + .choices.choices = cmd_search_string_insensitive_encoding_choices, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_string_insensitive_help = { + .summary = "String search (case-insensitive).", + .args = cmd_search_string_insensitive_args, +}; + static const RzCmdDescHelp R_help = { .summary = "Connect with other instances of rizin", }; @@ -16869,10 +17190,6 @@ static const RzCmdDescHelp seek_undo_reset_help = { .args = seek_undo_reset_args, }; -static const RzCmdDescHelp seek_search_help = { - .summary = "Seek to the first hit of a search", -}; - static const RzCmdDescArg seek_asz_args[] = { { .name = "align", @@ -19817,9 +20134,53 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *interpret_macro_multiple_cd = rz_cmd_desc_argv_new(core->rcmd, dot__cd, "..(", rz_interpret_macro_multiple_handler, &interpret_macro_multiple_help); rz_warn_if_fail(interpret_macro_multiple_cd); - RzCmdDesc *cmd_search_cd = rz_cmd_desc_oldinput_new(core->rcmd, root_cd, "/", rz_cmd_search, &cmd_search_help); - rz_warn_if_fail(cmd_search_cd); - RzCmdDesc *slash_R_cd = rz_cmd_desc_group_state_new(core->rcmd, cmd_search_cd, "/R", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_info_gadget_handler, &cmd_info_gadget_help, &slash_R_help); + RzCmdDesc *slash__cd = rz_cmd_desc_group_new(core->rcmd, root_cd, "/", NULL, NULL, &slash__help); + rz_warn_if_fail(slash__cd); + RzCmdDesc *cmd_search_assemble_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/a", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_assemble_handler, &cmd_search_assemble_help); + rz_warn_if_fail(cmd_search_assemble_cd); + rz_cmd_desc_set_default_mode(cmd_search_assemble_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *slash_c_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/c", NULL, NULL, &slash_c_help); + rz_warn_if_fail(slash_c_cd); + RzCmdDesc *cmd_search_aes_key_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_c_cd, "/ca", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_aes_key_handler, &cmd_search_aes_key_help); + rz_warn_if_fail(cmd_search_aes_key_cd); + rz_cmd_desc_set_default_mode(cmd_search_aes_key_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_private_key_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_c_cd, "/cp", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_private_key_handler, &cmd_search_private_key_help); + rz_warn_if_fail(cmd_search_private_key_cd); + rz_cmd_desc_set_default_mode(cmd_search_private_key_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *slash_e_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/e", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_regex_raw_sensitive_handler, &cmd_search_regex_raw_sensitive_help, &slash_e_help); + rz_warn_if_fail(slash_e_cd); + rz_cmd_desc_set_default_mode(slash_e_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_regex_raw_insensitive_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_e_cd, "/ei", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_regex_raw_insensitive_handler, &cmd_search_regex_raw_insensitive_help); + rz_warn_if_fail(cmd_search_regex_raw_insensitive_cd); + rz_cmd_desc_set_default_mode(cmd_search_regex_raw_insensitive_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *slash_g_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/g", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_graph_path_handler, &cmd_search_graph_path_help, &slash_g_help); + rz_warn_if_fail(slash_g_cd); + rz_cmd_desc_set_default_mode(slash_g_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_graph_path_follow_jumps_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_g_cd, "/gg", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_graph_path_follow_jumps_handler, &cmd_search_graph_path_follow_jumps_help); + rz_warn_if_fail(cmd_search_graph_path_follow_jumps_cd); + rz_cmd_desc_set_default_mode(cmd_search_graph_path_follow_jumps_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_hash_block_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/h", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_hash_block_handler, &cmd_search_hash_block_help); + rz_warn_if_fail(cmd_search_hash_block_cd); + rz_cmd_desc_set_default_mode(cmd_search_hash_block_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_magic_const_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/m", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_magic_const_handler, &cmd_search_magic_const_help); + rz_warn_if_fail(cmd_search_magic_const_cd); + rz_cmd_desc_set_default_mode(cmd_search_magic_const_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_entropy_section_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/E", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_entropy_section_handler, &cmd_search_entropy_section_help); + rz_warn_if_fail(cmd_search_entropy_section_cd); + rz_cmd_desc_set_default_mode(cmd_search_entropy_section_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_reference_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/r", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_reference_handler, &cmd_search_reference_help); + rz_warn_if_fail(cmd_search_reference_cd); + rz_cmd_desc_set_default_mode(cmd_search_reference_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *slash_R_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/R", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_info_gadget_handler, &cmd_info_gadget_help, &slash_R_help); rz_warn_if_fail(slash_R_cd); rz_cmd_desc_set_default_mode(slash_R_cd, RZ_OUTPUT_MODE_STANDARD); RzCmdDesc *cmd_search_gadget_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/R/", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_gadget_handler, &cmd_search_gadget_help); @@ -19834,6 +20195,35 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_detail_gadget_cd); rz_cmd_desc_set_default_mode(cmd_detail_gadget_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *slash_v_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/v", NULL, NULL, &slash_v_help); + rz_warn_if_fail(slash_v_cd); + RzCmdDesc *cmd_search_value_8_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_v_cd, "/v1", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_8_handler, &cmd_search_value_8_help); + rz_warn_if_fail(cmd_search_value_8_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_8_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_value_16_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_v_cd, "/v2", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_16_handler, &cmd_search_value_16_help); + rz_warn_if_fail(cmd_search_value_16_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_16_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_value_32_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_v_cd, "/v4", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_32_handler, &cmd_search_value_32_help); + rz_warn_if_fail(cmd_search_value_32_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_32_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_value_64_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_v_cd, "/v8", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_64_handler, &cmd_search_value_64_help); + rz_warn_if_fail(cmd_search_value_64_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_64_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_hex_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/x", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_hex_handler, &cmd_search_hex_help); + rz_warn_if_fail(cmd_search_hex_cd); + rz_cmd_desc_set_default_mode(cmd_search_hex_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *slash_z_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/z", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_string_sensitive_handler, &cmd_search_string_sensitive_help, &slash_z_help); + rz_warn_if_fail(slash_z_cd); + rz_cmd_desc_set_default_mode(slash_z_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_string_insensitive_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_z_cd, "/zi", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_string_insensitive_handler, &cmd_search_string_insensitive_help); + rz_warn_if_fail(cmd_search_string_insensitive_cd); + rz_cmd_desc_set_default_mode(cmd_search_string_insensitive_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *R_cd = rz_cmd_desc_group_new(core->rcmd, root_cd, "R", rz_remote_handler, &remote_help, &R_help); rz_warn_if_fail(R_cd); RzCmdDesc *remote_send_cd = rz_cmd_desc_argv_new(core->rcmd, R_cd, "R<", rz_remote_send_handler, &remote_send_help); @@ -23089,9 +23479,6 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *seek_undo_reset_cd = rz_cmd_desc_argv_new(core->rcmd, sh_cd, "sh-", rz_seek_undo_reset_handler, &seek_undo_reset_help); rz_warn_if_fail(seek_undo_reset_cd); - RzCmdDesc *seek_search_cd = rz_cmd_desc_oldinput_new(core->rcmd, s_cd, "s/", rz_seek_search, &seek_search_help); - rz_warn_if_fail(seek_search_cd); - RzCmdDesc *seek_asz_cd = rz_cmd_desc_argv_new(core->rcmd, s_cd, "sa", rz_seek_asz_handler, &seek_asz_help); rz_warn_if_fail(seek_asz_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 2d8fd37b261..6183ebcbb88 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -61,6 +61,28 @@ RZ_IPI RzCmdStatus rz_interpret_pipe_handler(RzCore *core, int argc, const char RZ_IPI RzCmdStatus rz_interpret_macro_handler(RzCore *core, int argc, const char **argv); // "..(" RZ_IPI RzCmdStatus rz_interpret_macro_multiple_handler(RzCore *core, int argc, const char **argv); +// "/a" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/ca" +RZ_IPI RzCmdStatus rz_cmd_search_aes_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/cp" +RZ_IPI RzCmdStatus rz_cmd_search_private_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/e" +RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/ei" +RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/g" +RZ_IPI RzCmdStatus rz_cmd_search_graph_path_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/gg" +RZ_IPI RzCmdStatus rz_cmd_search_graph_path_follow_jumps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/h" +RZ_IPI RzCmdStatus rz_cmd_search_hash_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/m" +RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/E" +RZ_IPI RzCmdStatus rz_cmd_search_entropy_section_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/r" +RZ_IPI RzCmdStatus rz_cmd_search_reference_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/R" RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/R/" @@ -69,8 +91,20 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/Rg" RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); -// "/" -RZ_IPI int rz_cmd_search(void *data, const char *input); +// "/v1" +RZ_IPI RzCmdStatus rz_cmd_search_value_8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/v2" +RZ_IPI RzCmdStatus rz_cmd_search_value_16_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/v4" +RZ_IPI RzCmdStatus rz_cmd_search_value_32_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/v8" +RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/x" +RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/z" +RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/zi" +RZ_IPI RzCmdStatus rz_cmd_search_string_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "R" RZ_IPI RzCmdStatus rz_remote_handler(RzCore *core, int argc, const char **argv); // "R<" @@ -2280,8 +2314,6 @@ RZ_IPI RzCmdStatus rz_seek_redo_handler(RzCore *core, int argc, const char **arg RZ_IPI RzCmdStatus rz_seek_undo_handler(RzCore *core, int argc, const char **argv); // "sh-" RZ_IPI RzCmdStatus rz_seek_undo_reset_handler(RzCore *core, int argc, const char **argv); -// "s/" -RZ_IPI int rz_seek_search(void *data, const char *input); // "sa" RZ_IPI RzCmdStatus rz_seek_asz_handler(RzCore *core, int argc, const char **argv); // "sb" diff --git a/librz/core/cmd_descs/cmd_descs.yaml b/librz/core/cmd_descs/cmd_descs.yaml index b5e77e3df7f..6111d8a2a9c 100644 --- a/librz/core/cmd_descs/cmd_descs.yaml +++ b/librz/core/cmd_descs/cmd_descs.yaml @@ -148,12 +148,10 @@ commands: - text: "*" arg_str: "entry0" comment: read the value contained at the entrypoint - - name: . + - name: "." summary: Interpret commands subcommands: cmd_interpret - - name: / - cname: cmd_search - type: RZ_CMD_DESC_TYPE_OLDINPUT + - name: "/" summary: Search for bytes, regexps, patterns, .. subcommands: cmd_search - name: "R" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 4cb3f3777eb..42e5c90c368 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -3,8 +3,173 @@ --- name: cmd_search commands: + - name: "/a" + summary: Assemble the opcodes and search its bytes + cname: cmd_search_assemble + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: opcodes + type: RZ_CMD_ARG_TYPE_STRING + + - name: "/c" + summary: Cryptographic material search + subcommands: + - name: "/ca" + summary: Search for AES keys + cname: cmd_search_aes_key + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: [] + - name: "/cp" + summary: Search for private RSA/ECC/EdDSA keys + cname: cmd_search_private_key + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: [] + + - name: "/e" + summary: Raw regular expression search. + subcommands: + - name: "/e" + summary: Raw regular expression search (case-sensitive). + cname: cmd_search_regex_raw_sensitive + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: regex + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ei" + summary: Raw regular expression search (case-insensitive). + cname: cmd_search_regex_raw_insensitive + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: regex + type: RZ_CMD_ARG_TYPE_STRING + + - name: "/g" + summary: Search for all graph paths A to B (/gg follow jumps, see search.count and analysis.depth). + subcommands: + - name: "/g" + summary: Search for all graph paths A to B (does not follow jumps). + cname: cmd_search_graph_path + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: from + type: RZ_CMD_ARG_TYPE_RZNUM + - name: to + type: RZ_CMD_ARG_TYPE_RZNUM + - name: "/gg" + summary: Search for all graph paths A to B (follow jumps, see `search.count` and `analysis.depth`). + cname: cmd_search_graph_path_follow_jumps + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: from + type: RZ_CMD_ARG_TYPE_RZNUM + - name: to + type: RZ_CMD_ARG_TYPE_RZNUM + + - name: "/h" + summary: Search for blocks that have the same hash (see also command `ph`). + cname: cmd_search_hash_block + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: algo + type: RZ_CMD_ARG_TYPE_STRING + - name: hash + type: RZ_CMD_ARG_TYPE_STRING + details: + - name: Usage example + entries: + - text: "MD5 hash search within blocks of 512 bytes." + comment: "/h md5 0bc8f8c426b74ffaedac8330a7464014 @! 512" + + - name: "/m" + summary: Magic constants search. + cname: cmd_search_magic_const + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: [] + + - name: "/E" + summary: Entropy search on sections by grouping in blocks. + cname: cmd_search_entropy_section + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: threshold + type: RZ_CMD_ARG_TYPE_STRING + + - name: "/r" + summary: Reference search. + cname: cmd_search_reference + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: address + type: RZ_CMD_ARG_TYPE_RZNUM + - name: "/R" - summary: List ROP Gadgets + summary: Search, List, Query for ROP Gadgets subcommands: - name: "/R" cname: cmd_info_gadget @@ -60,4 +225,155 @@ commands: args: - name: Gadget address type: RZ_CMD_ARG_TYPE_STRING - optional: true \ No newline at end of file + optional: true + - name: "/v" + summary: Value search. + subcommands: + - name: "/v1" + summary: 8-bit value search. + cname: cmd_search_value_8 + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value8 + type: RZ_CMD_ARG_TYPE_NUM + + - name: "/v2" + summary: 16-bit size value search. + cname: cmd_search_value_16 + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value16 + type: RZ_CMD_ARG_TYPE_NUM + + - name: "/v4" + summary: 32-bit size value search. + cname: cmd_search_value_32 + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value32 + type: RZ_CMD_ARG_TYPE_NUM + + - name: "/v8" + summary: 64-bit size value search. + cname: cmd_search_value_64 + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value64 + type: RZ_CMD_ARG_TYPE_NUM + details: + - name: Usage example + entries: + - text: "512 value search of its 32-bit representation" + comment: "/v4 512" + + - name: "/x" + summary: Raw hexadecimal search. + cname: cmd_search_hex + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: bytes + type: RZ_CMD_ARG_TYPE_STRING + details: + - name: Usage example + entries: + - text: "Hexadecimal search of the exact bytes" + comment: "/x ffcc33" + - text: "Hexadecimal search of the bytes with ignored nibbles" + comment: "/x ff..33" + - text: "Hexadecimal search of the bytes with bytes mask" + comment: "/x ff43:ffd0" + + - name: "/z" + summary: String search. + subcommands: + - name: "/z" + summary: String search (case-sensitive). + cname: cmd_search_string_sensitive + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: string + type: RZ_CMD_ARG_TYPE_STRING + - name: encoding + type: RZ_CMD_ARG_TYPE_CHOICES + optional: true + choices: + - "ascii" + - "8bit" + - "mutf8" + - "utf8" + - "utf16le" + - "utf32le" + - "utf16be" + - "utf32be" + - "ibm037" + - "ibm290" + - "ebcdices" + - "ebcdicuk" + - "ebcdicus" + + - name: "/zi" + summary: String search (case-insensitive). + cname: cmd_search_string_insensitive + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: string + type: RZ_CMD_ARG_TYPE_STRING + - name: encoding + type: RZ_CMD_ARG_TYPE_CHOICES + optional: true + choices: + - "ascii" + - "8bit" + - "mutf8" + - "utf8" + - "utf16le" + - "utf32le" + - "utf16be" + - "utf32be" + - "ibm037" + - "ibm290" + - "ebcdices" + - "ebcdicuk" + - "ebcdicus" diff --git a/librz/core/cmd_descs/cmd_seek.yaml b/librz/core/cmd_descs/cmd_seek.yaml index 475e17c27f6..c9efff1a261 100644 --- a/librz/core/cmd_descs/cmd_seek.yaml +++ b/librz/core/cmd_descs/cmd_seek.yaml @@ -67,10 +67,6 @@ commands: cname: seek_undo_reset summary: Clear seek history args: [] - - name: s/ - cname: seek_search - summary: Seek to the first hit of a search - type: RZ_CMD_DESC_TYPE_OLDINPUT - name: sa cname: seek_asz summary: Seek to current offset (or ) aligned to From 4fc86226075a2bf37c922a58e7643044a344e7d9 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 11 Dec 2024 10:50:07 -0500 Subject: [PATCH 003/157] Import new RzSearch from reference branch. This makes only small edits (renames) to keep the build working. --- librz/include/rz_core.h | 6 +- librz/include/rz_search.h | 77 +++++++++++- librz/include/rz_th.h | 2 +- librz/meson.build | 2 +- librz/search/aes-find.c | 8 +- librz/search/meson.build | 6 +- librz/search/privkey-find.c | 2 +- librz/search/regexp.c | 2 +- librz/search/search.c | 207 +++++++++++++++++++++++++++++++-- librz/search/search_internal.h | 90 ++++++++++++++ 10 files changed, 375 insertions(+), 27 deletions(-) create mode 100644 librz/search/search_internal.h diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 4d7034b2571..1f7dcb65534 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -282,7 +282,9 @@ struct rz_core_t { RzLang *lang; RzDebug *dbg; RzFlag *flags; - RzSearch *search; + char *lastsearch; ///< Legacy search. Will be removed + RzSearch *search; ///< Legacy search. Will be removed + RzSearchOpt *search_opts; RzEgg *egg; RzCrypto *crypto; RzAGraph *graph; @@ -318,7 +320,6 @@ struct rz_core_t { int curtab; // current tab int seltab; // selected tab char *cmdremote; - char *lastsearch; char *cmdfilter; char *curtheme; bool break_loop; @@ -1083,6 +1084,7 @@ RZ_API void rz_core_rtr_cmd(RzCore *core, const char *input); RZ_API int rz_core_rtr_http(RzCore *core, int launch, int browse, const char *path); RZ_API int rz_core_rtr_gdb(RzCore *core, int launch, const char *path); +/// Legacy search RZ_API int rz_core_search_preludes(RzCore *core, bool log); RZ_API int rz_core_search_prelude(RzCore *core, ut64 from, ut64 to, const ut8 *buf, int blen, const ut8 *mask, int mlen); diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index e273bd6930e..c206fc3de2b 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -44,10 +45,10 @@ typedef struct rz_search_keyword_t { ut64 last; // last hit hint } RzSearchKeyword; -typedef struct rz_search_hit_t { +typedef struct { RzSearchKeyword *kw; ut64 addr; -} RzSearchHit; +} RzSearchLegacyHit; typedef int (*RzSearchCallback)(RzSearchKeyword *kw, void *user, ut64 where); @@ -109,7 +110,7 @@ RZ_API int rz_search_deltakey_update(RzSearch *s, ut64 from, const ut8 *buf, int RZ_API int rz_search_strings_update(RzSearch *s, ut64 from, const ut8 *buf, int len); RZ_API int rz_search_regexp_update(RzSearch *s, ut64 from, const ut8 *buf, int len); // Returns 2 if search.maxhits is reached, 0 on error, otherwise 1 -RZ_API int rz_search_hit_new(RzSearch *s, RzSearchKeyword *kw, ut64 addr); +RZ_API int rz_search_legacy_hit_new(RzSearch *s, RzSearchKeyword *kw, ut64 addr); RZ_API void rz_search_set_distance(RzSearch *s, int dist); RZ_API int rz_search_set_string_limits(RzSearch *s, ut32 min, ut32 max); // dup again? // RZ_API int rz_search_set_callback(RzSearch *s, int (*callback)(struct rz_search_kw_t *, void *, ut64), void *user); @@ -120,9 +121,77 @@ RZ_API int rz_search_begin(RzSearch *s); RZ_API void rz_search_pattern_size(RzSearch *s, int size); RZ_API int rz_search_pattern(RzSearch *s, ut64 from, ut64 to); +#endif // RZ_API + +// +// New search. +// Everything above is only there to not break the build. +// + +RZ_LIB_VERSION_HEADER(rz_search); + +#define RZ_SEARCH_MIN_BUFFER_SIZE 512u +#define RZ_SEARCH_CANCEL_CHECK_INTERVAL_USEC 1000 * 1000 + +typedef struct rz_search_opt_t RzSearchOpt; + +typedef struct rz_search_collection_t RzSearchCollection; + +typedef struct rz_search_hit_t { + char *hit_desc; ///< Hit description (can be NULL) + ut64 address; ///< Address the matched data + size_t size; ///< Size of the matched data (can be 0) +} RzSearchHit; + +typedef enum { + RZ_SEARCH_CANCEL_REGULAR_CHECK, ///< Regular cancel check. Repeated every RZ_SEARCH_CANCEL_CHECK_INTERVAL_USEC microseconds. + RZ_SEARCH_CANCEL_SIGINT, ///< Interrupt signal (likely ctrl + c). +} RzSearchCancelReason; + +/** + * \brief The cancel callback. It is invoked to check, if the search should be stopped. + * + * \param user The private user data. + * \param n_hits Number of hits already found during the search. + * \param invoe_reason The reason it is called. + * + * \return True, if the search should be canceled. + * \return False, if the search should continue. + */ +typedef bool (*RzSearchCancelCallback)(void *user, size_t n_hits, RzSearchCancelReason invoke_reason); + +RZ_API RZ_OWN RzSearchOpt *rz_search_opt_new(); +RZ_API void rz_search_opt_free(RZ_NULLABLE RzSearchOpt *opt); +RZ_API bool rz_search_opt_set_inverse_match(RZ_NONNULL RzSearchOpt *opt, bool inverse_match); +RZ_API bool rz_search_opt_set_buffer_size(RZ_NONNULL RzSearchOpt *opt, size_t buffer_size); +RZ_API bool rz_search_opt_set_max_hits(RZ_NONNULL RzSearchOpt *opt, size_t max_hits); +RZ_API bool rz_search_opt_set_max_threads(RZ_NONNULL RzSearchOpt *opt, RzThreadNCores max_threads); +RZ_API bool rz_search_opt_set_cancel_cb(RZ_NONNULL RzSearchOpt *opt, RzSearchCancelCallback callback, void *user); + +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_aes_keys(); + +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_private_keys(); + +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_regex(); +RZ_API bool rz_search_collection_regex_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *regex, bool caseless); + +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_bytes(); +RZ_API bool rz_search_collection_bytes_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *metadata, RZ_NONNULL const ut8 *bytes, RZ_NULLABLE const ut8 *mask, size_t length); +RZ_API bool rz_search_collection_bytes_add_pattern(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *hex_pattern); + +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, bool caseless); +RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *string); + +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_magic(RZ_NONNULL const char *magic_dir); + +RZ_API bool rz_search_collection_match_any(RZ_NULLABLE RzSearchCollection *sc, RZ_NONNULL const ut8 *buffer, size_t length); +RZ_API void rz_search_collection_free(RZ_NULLABLE RzSearchCollection *sc); +RZ_API void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit); + +RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *opt, RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RzIO *io, RZ_NONNULL RzList /**/ *search_in); + #ifdef __cplusplus } #endif #endif -#endif diff --git a/librz/include/rz_th.h b/librz/include/rz_th.h index 7332c881f25..8e0532f3622 100644 --- a/librz/include/rz_th.h +++ b/librz/include/rz_th.h @@ -34,7 +34,7 @@ typedef struct rz_th_t RzThread; typedef struct rz_th_pool_t RzThreadPool; typedef struct rz_th_queue_t RzThreadQueue; typedef void *(*RzThreadFunction)(void *user); -typedef void (*RzThreadIterator)(void *element, void *user); +typedef bool (*RzThreadIterator)(void *element, void *user); typedef struct rz_atomic_bool_t RzAtomicBool; diff --git a/librz/meson.build b/librz/meson.build index bc57eb27e58..bf29e954587 100644 --- a/librz/meson.build +++ b/librz/meson.build @@ -14,8 +14,8 @@ subdir('diff') subdir('io') subdir('bp') subdir('syscall') -subdir('search') subdir('magic') +subdir('search') subdir('flag') subdir('reg') subdir('type') diff --git a/librz/search/aes-find.c b/librz/search/aes-find.c index 5934d28fda5..e04602c66cb 100644 --- a/librz/search/aes-find.c +++ b/librz/search/aes-find.c @@ -51,7 +51,7 @@ RZ_API int rz_search_aes_update(RzSearch *s, ut64 from, const ut8 *buf, int len) for (i = 0; i < last; i++) { if (aes128_key_test(buf + i)) { kw->keyword_length = AES128_KEY_LENGTH; - t = rz_search_hit_new(s, kw, from + i); + t = rz_search_legacy_hit_new(s, kw, from + i); if (!t) { return -1; } @@ -62,7 +62,7 @@ RZ_API int rz_search_aes_update(RzSearch *s, ut64 from, const ut8 *buf, int len) } if (len - i - AES192_SEARCH_LENGTH >= 0 && aes192_key_test(buf + i)) { kw->keyword_length = AES192_KEY_LENGTH; - t = rz_search_hit_new(s, kw, from + i); + t = rz_search_legacy_hit_new(s, kw, from + i); if (!t) { return -1; } @@ -73,7 +73,7 @@ RZ_API int rz_search_aes_update(RzSearch *s, ut64 from, const ut8 *buf, int len) } if (len - i - AES256_SEARCH_LENGTH >= 0 && aes256_key_test(buf + i)) { kw->keyword_length = AES256_KEY_LENGTH; - t = rz_search_hit_new(s, kw, from + i); + t = rz_search_legacy_hit_new(s, kw, from + i); if (!t) { return -1; } @@ -86,4 +86,4 @@ RZ_API int rz_search_aes_update(RzSearch *s, ut64 from, const ut8 *buf, int len) } } return -1; -} \ No newline at end of file +} diff --git a/librz/search/meson.build b/librz/search/meson.build index ab0bf39e869..6d25bc442c3 100644 --- a/librz/search/meson.build +++ b/librz/search/meson.build @@ -5,11 +5,13 @@ rz_search_sources = [ 'regexp.c', 'privkey-find.c', 'search.c', + 'collection.c', + 'options.c', ] rz_search = library('rz_search', rz_search_sources, include_directories: [platform_inc], - dependencies: [rz_util_dep], + dependencies: [rz_util_dep, rz_io_dep, rz_magic_dep], install: true, implicit_include_directories: false, install_rpath: rpath_lib, @@ -25,5 +27,5 @@ meson.override_dependency('rz_search', rz_search_dep) modules += { 'rz_search': { 'target': rz_search, - 'dependencies': ['rz_util'] + 'dependencies': ['rz_util', 'rz_io', 'rz_magic'] }} diff --git a/librz/search/privkey-find.c b/librz/search/privkey-find.c index 7f9deb000c3..4c8c99167d3 100644 --- a/librz/search/privkey-find.c +++ b/librz/search/privkey-find.c @@ -110,7 +110,7 @@ RZ_API int rz_search_privkey_update(RzSearch *s, ut64 from, const ut8 *buf, int if (check_fields(buf + index)) { parse_next_field(buf + index, &kw->keyword_length); - t = rz_search_hit_new(s, kw, from + index); + t = rz_search_legacy_hit_new(s, kw, from + index); if (t > 1) { return s->nhits - old_nhits; } diff --git a/librz/search/regexp.c b/librz/search/regexp.c index e7a0c6e46e2..22bfafc726b 100644 --- a/librz/search/regexp.c +++ b/librz/search/regexp.c @@ -37,7 +37,7 @@ RZ_API int rz_search_regexp_update(RzSearch *s, ut64 from, const ut8 *buf, int l rz_pvector_foreach (matches, it) { RzRegexMatch *m = *it; kw->keyword_length = m->len; // For a regex search, the keyword can be of variable length - int t = rz_search_hit_new(s, kw, from + m->start); + int t = rz_search_legacy_hit_new(s, kw, from + m->start); if (t == 0) { ret = -1; rz_pvector_free(matches); diff --git a/librz/search/search.c b/librz/search/search.c index b077dbd209d..71db2f163e8 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -1,9 +1,8 @@ -// SPDX-FileCopyrightText: 2008-2016 pancake +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-FileCopyrightText: 2024 deroad // SPDX-License-Identifier: LGPL-3.0-only #include -#include -#include // Experimental search engine (fails, because stops at first hit of every block read #define USE_BMH 0 @@ -97,7 +96,7 @@ RZ_API int rz_search_strings_update(RzSearch *s, ut64 from, const ut8 *buf, int rz_list_foreach (s->kws, iter, kw) { RzDetectedString *dstr; rz_list_foreach (str_list, iter2, dstr) { - rz_search_hit_new(s, kw, dstr->addr); + rz_search_legacy_hit_new(s, kw, dstr->addr); matches++; } } @@ -139,7 +138,7 @@ RZ_API int rz_search_begin(RzSearch *s) { } // Returns 2 if search.maxhits is reached, 0 on error, otherwise 1 -RZ_API int rz_search_hit_new(RzSearch *s, RzSearchKeyword *kw, ut64 addr) { +RZ_API int rz_search_legacy_hit_new(RzSearch *s, RzSearchKeyword *kw, ut64 addr) { if (s->align && (addr % s->align)) { eprintf("0x%08" PFMT64x " unaligned\n", addr); return 1; @@ -165,7 +164,7 @@ RZ_API int rz_search_hit_new(RzSearch *s, RzSearchKeyword *kw, ut64 addr) { } kw->count++; s->nhits++; - RzSearchHit *hit = RZ_NEW0(RzSearchHit); + RzSearchLegacyHit *hit = RZ_NEW0(RzSearchLegacyHit); if (hit) { hit->kw = kw; hit->addr = addr; @@ -233,7 +232,7 @@ RZ_API int rz_search_deltakey_update(RzSearch *s, ut64 from, const ut8 *buf, int j++; } if (j == kw->keyword_length) { - int t = rz_search_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - 1 - i + left->len : from + i - left->len); + int t = rz_search_legacy_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - 1 - i + left->len : from + i - left->len); kw->last += s->bckwrds ? 0 : 1; if (!t) { return -1; @@ -257,7 +256,7 @@ RZ_API int rz_search_deltakey_update(RzSearch *s, ut64 from, const ut8 *buf, int j++; } if (j == kw->keyword_length) { - int t = rz_search_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - 1 - i : from + i); + int t = rz_search_legacy_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - 1 - i : from + i); kw->last += s->bckwrds ? 0 : 1; if (!t) { return -1; @@ -390,7 +389,7 @@ RZ_API int rz_search_mybinparse_update(RzSearch *s, ut64 from, const ut8 *buf, i : 0; for (; i + kw->keyword_length <= len1 && i < left->len; i++) { if (brute_force_match(s, kw, left->data, i) != s->inverse) { - int t = rz_search_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - i + left->len : from + i - left->len); + int t = rz_search_legacy_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - i + left->len : from + i - left->len); if (!t) { return -1; } @@ -407,7 +406,7 @@ RZ_API int rz_search_mybinparse_update(RzSearch *s, ut64 from, const ut8 *buf, i : 0; for (; i + kw->keyword_length <= len; i++) { if (brute_force_match(s, kw, buf, i) != s->inverse) { - int t = rz_search_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - i : from + i); + int t = rz_search_legacy_hit_new(s, kw, s->bckwrds ? from - kw->keyword_length - i : from + i); if (!t) { return -1; } @@ -475,7 +474,7 @@ RZ_API int rz_search_update_i(RzSearch *s, ut64 from, const ut8 *buf, long len) } static int listcb(RzSearchKeyword *k, void *user, ut64 addr) { - RzSearchHit *hit = RZ_NEW0(RzSearchHit); + RzSearchLegacyHit *hit = RZ_NEW0(RzSearchLegacyHit); if (!hit) { return 0; } @@ -536,3 +535,189 @@ RZ_API void rz_search_kw_reset(RzSearch *s) { rz_list_purge(s->hits); RZ_FREE(s->data); } + + +// +// New search. +// Everything above is only there to not break the build. +// + +#include "search_internal.h" + +// RZ_LIB_VERSION(rz_search); + +typedef struct search_ctx { + RzIO *io; ///< the RzIO struct to use + RzSearchCollection *col; ///< collection to use + RzSearchOpt *opt; ///< User options + RzThreadQueue *hits; ///< Hits list + RzAtomicBool *loop; ///< If set, the execution will continue until it terminates. If unset, the execution cancels. +} search_ctx_t; + +static void *search_cancel_th(void *user) { + search_ctx_t *ctx = (search_ctx_t *)user; + RzSearchOpt *opt = ctx->opt; + + do { + size_t n_hits = rz_th_queue_size(ctx->hits); + if (!opt->cancel_cb(opt->cancel_usr, n_hits, RZ_SEARCH_CANCEL_REGULAR_CHECK)) { + rz_atomic_bool_set(ctx->loop, false); + break; + } + rz_sys_usleep(RZ_SEARCH_CANCEL_CHECK_INTERVAL_USEC); + } while (rz_atomic_bool_get(ctx->loop)); + + return NULL; +} + +static bool search_iterator_bytes_cb(void *element, void *user) { + search_ctx_t *ctx = (search_ctx_t *)user; + RzIOMap *map = (RzIOMap *)element; + if (!map) { + return rz_atomic_bool_get(ctx->loop); + } + + RzSearchOpt *opt = ctx->opt; + RzSearchCollection *col = ctx->col; + + ut8 *buffer = malloc(opt->buffer_size); + if (!buffer) { + rz_atomic_bool_set(ctx->loop, false); + return false; + } + + const ut64 from = rz_itv_begin(map->itv); + const ut64 to = rz_itv_end(map->itv); + + for (ut64 at = from; at < to; at += opt->buffer_size) { + if (!rz_atomic_bool_get(ctx->loop)) { + break; + } + // calculate the buffer size + size_t size = opt->buffer_size; + if ((at + opt->buffer_size) > to) { + size = to - at; + } + // read the buffer + if (!rz_io_read_at(ctx->io, at, buffer, size)) { + RZ_LOG_ERROR("search: failed to read at 0x%08" PFMT64x " (%" PFMTSZu " bytes)\n", at, size); + break; + } + RzSearchFindBytesCallback find = col->find; + if (!find(col->user, at, buffer, size, ctx->hits)) { + RZ_LOG_ERROR("search: failed search at 0x%08" PFMT64x "\n", at); + break; + } + } + + free(buffer); + return rz_atomic_bool_get(ctx->loop); +} + +/** + * \brief Perform a search within the given search maps of a collection + * + * \param opt The RzSearchOpt to use + * \param col The RzSearchCollection to use + * \param io The RzIO layer to use + * \param search_in The search maps for the boundaries + * + * \return On success returns all the hits. + */ +RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *opt, RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RzIO *io, RZ_NONNULL RzList /**/ *search_in) { + rz_return_val_if_fail(opt && col && io && search_in, NULL); + search_ctx_t ctx = { 0 }; + RzList *results = NULL; + RzThreadQueue *hits = NULL; + RzThread *cancel_th = NULL; + + if (!rz_search_collection_on_bytes_space(col)) { + RZ_LOG_ERROR("search: The search collection is not initialized for bytes.\n"); + return NULL; + } + + if (opt->buffer_size < RZ_SEARCH_MIN_BUFFER_SIZE) { + RZ_LOG_ERROR("search: cannot search when buffer size is less than %u bytes.\n", RZ_SEARCH_MIN_BUFFER_SIZE); + return NULL; + } + + if (rz_list_empty(search_in)) { + RZ_LOG_ERROR("search: cannot search in an empty RzIOMap list.\n"); + return NULL; + } + + if (rz_search_collection_is_empty(col)) { + RZ_LOG_ERROR("search: cannot perform the search when the search collection is empty.\n"); + return NULL; + } + + hits = rz_th_queue_new(RZ_THREAD_QUEUE_UNLIMITED, (RzListFree)rz_search_hit_free); + if (!hits) { + RZ_LOG_ERROR("search: cannot allocate RzSearchHit queue.\n"); + return NULL; + } + + ctx.col = col; + ctx.opt = opt; + ctx.io = io; + ctx.loop = rz_atomic_bool_new(true); + + if (opt->cancel_cb) { + // create cancel thread + cancel_th = rz_th_new(search_cancel_th, &ctx); + if (!cancel_th) { + RZ_LOG_ERROR("search: cannot allocate cancel thread.\n"); + rz_th_queue_free(hits); + return NULL; + } + } + + if (!rz_th_iterate_list(search_in, search_iterator_bytes_cb, opt->max_threads, &ctx)) { + RZ_LOG_ERROR("search: cannot iterate over list.\n"); + } else { + results = rz_th_queue_pop_all(hits); + } + + if (cancel_th) { + // stop & free cancel thread. + rz_atomic_bool_set(ctx.loop, false); + rz_th_wait(cancel_th); + rz_th_free(cancel_th); + } + + rz_th_queue_free(hits); + return results; +} + +/** + * \brief Allocate and initialize a new RzSearchHit + * + * \param[in] hit_desc The hit description linked to the hit (can be NULL) + * \param[in] address The address where the hit happened + * \param[in] size The size of the hit data (can be 0) + * + * \return On success returns a valid pointer, otherwise NULL + */ +RZ_IPI RZ_OWN RzSearchHit *rz_search_hit_new(const char *hit_desc, ut64 address, size_t size) { + RzSearchHit *hit = RZ_NEW0(RzSearchHit); + if (!hit) { + return NULL; + } + hit->hit_desc = rz_str_dup(hit_desc); + hit->address = address; + hit->size = size; + return hit; +} + +/** + * \brief Frees a RzSearchHit structure + * + * \param hit The RzSearchHit pointer to free + */ +RZ_API void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit) { + if (!hit) { + return; + } + free(hit->hit_desc); + free(hit); +} diff --git a/librz/search/search_internal.h b/librz/search/search_internal.h new file mode 100644 index 00000000000..df3a6cc6f91 --- /dev/null +++ b/librz/search/search_internal.h @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-FileCopyrightText: 2024 deroad +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_SEARCH_INTERNAL_H +#define RZ_SEARCH_INTERNAL_H + +#include +#include +#include + +#define RZ_SEARCH_AES_LENGTH 40 +#define RZ_SEARCH_PRIVATE_KEY_LENGTH 11 +#define RZ_SEARCH_MAX_HEX_PATTERN UT16_MAX + +/** + * \brief The callback to free the private user data in the RzSearchCollection. + * + * \param user The private user data to free. + */ +typedef void (*RzSearchFreeCallback)(void *user); + +/** + * \brief The callback to check if the search collection is considered empty. + * + * \param user The private user data. + */ +typedef bool (*RzSearchIsEmptyCallback)(void *user); + +/** + * \brief A callback checking a chunk of bytes if it matches the search criteria. + * + * \param user The private user data. + * \param address The address associated with the given bytes. + * \param buffer The bytes buffer. + * \param size The buffer size in bytes. + * \param The queue to push new hits onto. + * + * \return True, if a match was found. + * \return False otherwise. + */ +typedef bool (*RzSearchFindBytesCallback)(void *user, ut64 address, const ut8 *buffer, size_t size, RZ_OUT RzThreadQueue *hits); + +/** + * \brief A callback to search a graph for a pattern. + * + * \param user The private user data. + * \param graph The graph to search in. + * \param The queue to push new hits onto. + * + * \return True, if a match was found. + * \return False otherwise. + */ +typedef bool (*RzSearchFindGraphCallback)(void *user, const RzGraph *graph, RZ_OUT RzThreadQueue *hits); + +typedef enum { + RZ_SEARCH_SPACE_BYTES = 0, ///< The search is performed on bytes. + RZ_SEARCH_SPACE_GRAPH, ///< The search is performed on a graph. + RZ_SEARCH_SPACE_KB, ///< The search is performed on the knowledge base. +} RzSearchSpace; + +struct rz_search_collection_t { + void *user; ///< Context defined by the various collections + RzSearchSpace space; ///< The search space of this collection. + void *find; ///< Callback to do the search in a given chunk. The callback type depends on \ref rz_search_collection_t.space. + RzSearchIsEmptyCallback is_empty; ///< Callback used to check if the collection is empty. + RzSearchFreeCallback free; ///< Callback used to free the collection. +}; + +struct rz_search_opt_t { + bool inverse_match; + size_t buffer_size; + size_t max_hits; + RzThreadNCores max_threads; + + // cancel callback + void *cancel_usr; + RzSearchCancelCallback cancel_cb; +}; + +RZ_IPI RZ_OWN RzSearchHit *rz_search_hit_new(const char *metadata, ut64 address, size_t size); + +RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_bytes(RZ_NONNULL RzSearchFindBytesCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); +RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_graph(RZ_NONNULL RzSearchFindGraphCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); +RZ_IPI bool rz_search_collection_has_find_callback(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL void *expected); +RZ_IPI bool rz_search_collection_is_empty(RZ_NONNULL RzSearchCollection *col); +RZ_IPI static inline bool rz_search_collection_on_bytes_space(RZ_NONNULL RzSearchCollection *col) { return col->space == RZ_SEARCH_SPACE_BYTES; }; +RZ_IPI static inline bool rz_search_collection_on_graph_space(RZ_NONNULL RzSearchCollection *col) { return col->space == RZ_SEARCH_SPACE_GRAPH; }; + +#endif /* RZ_SEARCH_INTERNAL_H */ From 542c0b53a79c6b78f489d8293fa85b39a966756f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 11 Dec 2024 16:17:16 -0500 Subject: [PATCH 004/157] Reimplement hex bytes (/x) search. This sets search.overlap=true by default. Mostly because I think this what people expect. Also, with the search.align or search.alignment options there will be the option to search at alignments. This also adds some hex string to bytes helpers. Fixes them and adds tests. Unfinished reimplementation of /x. Fix up the hex string to buffer functions. Fix fast mask comparison macro. Fix byte comparison with UB. Invert condition to match documentation of callback Handle search options from the settings and add tests. This sets search.overlap=true by default. Mostly because I think this what people expect. Also, with the search.align or search.alignment there are way better options to consider for seraching not overlapping data. Fix rz_hex_str2bin_mask() did set mask bits for 0 Refine documentation for rz_hex_str2bin functions. Add byte search tests. Don't allow wildcards with a custom mask. Change buffer to chunk size and make it a search setting. Make search over bytes more efficient. Searching over windows of memory. Add some helper functions to read from IO into a RzBuffer Simplify buffer management and fix leaks Fix bugs add tests regarding search windows Revert design with RzBuffer due to https://github.com/rizinorg/rizin/issues/4769 Fix several stupidity bugs Change order of byte pattern and mask. Apply suggestions. --- librz/core/cconfig.c | 32 +++- librz/core/cmd/cmd_search.c | 157 ++++++++++++++- librz/core/cmd_descs/cmd_descs.c | 8 +- librz/core/cmd_descs/cmd_search.yaml | 13 +- librz/core/csearch.c | 149 +++++++++++++++ librz/core/meson.build | 1 + librz/include/rz_core.h | 6 +- librz/include/rz_io.h | 3 +- librz/include/rz_search.h | 37 +++- librz/include/rz_util/rz_buf.h | 11 ++ librz/include/rz_util/rz_hex.h | 7 +- librz/io/io.c | 35 +++- librz/search/bytepat.c | 135 ------------- librz/search/bytes_search.c | 274 +++++++++++++++++++++++++++ librz/search/collection.c | 91 +++++++++ librz/search/keyword.c | 2 +- librz/search/meson.build | 2 +- librz/search/options.c | 120 ++++++++++++ librz/search/search.c | 123 ++++++++---- librz/search/search_internal.h | 60 +++++- librz/util/buf.c | 34 ++++ librz/util/hex.c | 242 ++++++++++++++++++++--- test/db/cmd/cmd_search_x | 258 +++++++++++++++++++++++++ test/unit/test_hex.c | 141 +++++++++++++- 24 files changed, 1700 insertions(+), 241 deletions(-) create mode 100644 librz/core/csearch.c delete mode 100644 librz/search/bytepat.c create mode 100644 librz/search/bytes_search.c create mode 100644 librz/search/collection.c create mode 100644 librz/search/options.c create mode 100644 test/db/cmd/cmd_search_x diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index daabad16707..e7e924ecc5d 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1130,6 +1130,16 @@ static bool cb_str_search_max_threads(void *user, void *data) { return true; } +static bool cb_search_max_threads(void *user, void *data) { + RzConfigNode *node = (RzConfigNode *)data; + RzThreadNCores max_threads = rz_th_max_threads(node->i_value); + if (node->value[0] == '?') { + rz_cons_printf("%d\n", max_threads); + return false; + } + return true; +} + static bool cb_str_search_min_length(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; @@ -2430,6 +2440,16 @@ static bool cb_searchalign(void *user, void *data) { return true; } +static bool cb_searchalignment(void *user, void *data) { + RzConfigNode *node = (RzConfigNode *)data; + ut64 alignment = node->i_value; + if (alignment >= 64 || alignment < 1) { + RZ_LOG_ERROR("Alignment has to be between 1-63.\n"); + return false; + } + return true; +} + static bool cb_segoff(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; @@ -3765,6 +3785,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETBPREF("search.flags", "true", "All search results are flagged, otherwise only printed"); SETBPREF("search.overlap", "false", "Look for overlapped search hits"); SETI("search.maxhits", 0, "Maximum number of hits (0: no limit)"); + SETICB("search.max_threads", RZ_THREAD_N_CORES_ALL_AVAILABLE, &cb_search_max_threads, "Maximum core number. '0' for all cores. '?' to show available."); SETI("search.from", 0, "Search start address (inclusive)"); SETI("search.to", UT64_MAX, "Search end address (exclusive)"); n = NODECB("search.in", "io.maps", &cb_search_in); @@ -3776,8 +3797,17 @@ RZ_API int rz_core_config_init(RzCore *core) { "dbg.map", "dbg.maps", "dbg.maps.rwx", "dbg.maps.r", "dbg.maps.rw", "dbg.maps.rx", "dbg.maps.wx", "dbg.maps.x", "analysis.fcn", "analysis.bb", NULL); - SETICB("search.kwidx", 0, &cb_search_kwidx, "Store last search index count"); SETPREF("search.prefix", "hit", "Prefix name in search hits label"); + SETI("search.maxhits", 0, "Maximum number of hits ('0' means no limit)"); + SETBPREF("search.show_progress", "true", "Show the search process."); + SETBPREF("search.overlap", "true", "Look for overlapped search hits."); + SETICB("search.io.alignment", 1, &cb_searchalignment, "Only search at set byte alignment."); + + SETICB("search.align", 0, &cb_searchalign, "Only catch aligned search hits"); + SETI("search.esilcombo", 8, "Stop search after N consecutive hits"); + SETI("search.distance", 0, "Search string distance"); + SETBPREF("search.flags", "true", "All search results are flagged, otherwise only printed"); + SETICB("search.kwidx", 0, &cb_search_kwidx, "Store last search index count"); SETBPREF("search.show", "true", "Show search results"); n = NODECB("search.case_sensitive", "smart", &cb_search_case_sensitive); SETDESC(n, "Set grep(~) as case smart/sensitive/insensitive"); diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index fc5d7f74177..72539f08e1d 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -6,10 +6,15 @@ #include #include #include +#include #include #include "../core_private.h" #include "cmd_search_rop.c" +#include "rz_cons.h" +#include +#include +#include #define AES_SEARCH_LENGTH 40 #define PRIVATE_KEY_SEARCH_LENGTH 11 @@ -1771,7 +1776,127 @@ static void __core_cmd_search_asm_byteswap(RzCore *core, int nth) { } } -RZ_IPI int rz_cmd_search(void *data, const char *input) { return RZ_CMD_STATUS_ERROR; } +RZ_IPI int rz_cmd_search(void *data, const char *input) { + return RZ_CMD_STATUS_ERROR; +} + +// New search + +#define CMD_SEARCH_BEGIN() \ + if (core->in_search) { \ + RZ_LOG_ERROR("core: recursive search is forbidden.\n"); \ + return RZ_CMD_STATUS_ERROR; \ + } \ + rz_cons_break_push(NULL, NULL); \ + RzSearchOpt *search_opts = rz_search_opt_new(); \ + bool opt_applid = rz_search_opt_set_max_hits(search_opts, rz_config_get_i(core->config, "search.maxhits")); \ + opt_applid &= rz_search_opt_set_max_threads(search_opts, rz_th_max_threads(rz_config_get_i(core->config, "search.max_threads"))); \ + RzSearchFindOpt *fopts = rz_core_setup_default_search_find_opts(core); \ + if (!fopts) { \ + RZ_LOG_ERROR("Failed setup find options.\n"); \ + return RZ_CMD_STATUS_ERROR; \ + } \ + rz_search_opt_set_find_options(search_opts, fopts); \ + core->in_search = true; + +#define CMD_SEARCH_END() \ + do { \ + rz_search_opt_free(search_opts); \ + rz_cons_break_pop(); \ + core->in_search = false; \ + } while (0) + +static bool cmd_search_progress_cancel(void *user, size_t n_hits, RzSearchCancelReason invoke_reason) { + if (user) { + // we have RzCmdStateOutput state + rz_cons_printf("Searching... hits: %" PFMTSZu "\r", n_hits); + } + return rz_cons_is_breaked(); +} + +static void cmd_search_output_to_state(RzCmdStateOutput *state, RzSearchHit *hit, const char *flag_name) { + switch (state->mode) { + case RZ_OUTPUT_MODE_QUIET: + rz_cons_printf("%08" PFMT64x "\n", hit->address); + break; + case RZ_OUTPUT_MODE_STANDARD: + rz_cons_printf("%08" PFMT64x " %" PFMTSZu " %s\n", hit->address, hit->size, flag_name); + break; + case RZ_OUTPUT_MODE_JSON: + pj_o(state->d.pj); + pj_kn(state->d.pj, "address", hit->address); + pj_kn(state->d.pj, "size", hit->size); + pj_ks(state->d.pj, "flag", flag_name); + pj_end(state->d.pj); + break; + case RZ_OUTPUT_MODE_TABLE: + rz_table_add_rowf(state->d.t, "xXs", hit->address, hit->size, flag_name); + break; + default: + rz_warn_if_reached(); + break; + } +} + +static void cmd_search_call_command(RzCore *core, RzSearchHit *hit, const char *command) { + ut64 old_offset = core->offset; + rz_core_seek(core, hit->address, true); + rz_core_cmd(core, command, false); + rz_core_seek(core, old_offset, true); +} + +static RzCmdStatus cmd_core_handle_search_hits(RzCore *core, RzCmdStateOutput *state, RZ_OWN RzList *hits) { + if (!hits) { + core->num->value = 0; + return RZ_CMD_STATUS_ERROR; + } + + RzListIter *it = NULL; + RzSearchHit *hit = NULL; + const char *cmd_hit = NULL; + const char *search_prefix = NULL; + size_t counter = 0; + + cmd_hit = rz_config_get(core->config, "cmd.hit"); + search_prefix = rz_config_get(core->config, "search.prefix"); + if (RZ_STR_ISEMPTY(search_prefix)) { + // ensure thre prefix is always set. + search_prefix = "hit"; + } + + if (RZ_STR_ISEMPTY(cmd_hit)) { + // setup output and flagspace + rz_cmd_state_output_array_start(state); + rz_cmd_state_output_set_columnsf(state, "xXs", "offset", "size", "flag"); + rz_flag_space_push(core->flags, "search"); + } + + rz_list_foreach (hits, it, hit) { + if (RZ_STR_ISNOTEMPTY(cmd_hit)) { + cmd_search_call_command(core, hit, cmd_hit); + continue; + } + + // only output & add flag when cmd.hit is not set. + const char *meta = hit->hit_desc ? hit->hit_desc : "match"; + char *flag = rz_str_newf("%s.%s.%" PFMTSZu, search_prefix, meta, counter); + rz_flag_set(core->flags, flag, hit->address, hit->size); + cmd_search_output_to_state(state, hit, flag); + free(flag); + counter++; + } + + if (RZ_STR_ISEMPTY(cmd_hit)) { + // terminating output and flagspace + rz_flag_space_pop(core->flags); + rz_cmd_state_output_array_end(state); + } + + // set return value to the number of hits before returning + core->num->value = rz_list_length(hits); + rz_list_free(hits); + return RZ_CMD_STATUS_OK; +} // "/a" RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { @@ -1850,7 +1975,35 @@ RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const // "/x" RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + CMD_SEARCH_BEGIN(); + + RzList *hits = NULL; + RzSearchBytesPattern *pattern = rz_search_parse_byte_pattern(argv[1], NULL); + + if (!pattern) { + RZ_LOG_ERROR("Failed to parse given pattern.\n"); + goto error; + } + + bool progress = rz_config_get_b(core->config, "search.show_progress"); + opt_applid &= rz_search_opt_set_cancel_cb(search_opts, cmd_search_progress_cancel, progress ? state : NULL); + if (!opt_applid) { + RZ_LOG_ERROR("code: Failed to setup default search options.\n"); + goto error; + } + hits = rz_core_search_bytes(core, search_opts, pattern); + if (!hits) { + RZ_LOG_ERROR("Failed to perform search.\n"); + goto error; + } + + CMD_SEARCH_END(); + return cmd_core_handle_search_hits(core, state, hits); + +error: + rz_list_free(hits); + CMD_SEARCH_END(); + return RZ_CMD_STATUS_ERROR; } // "/z" diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index c5e8ea60a20..339aec96c46 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -1697,9 +1697,9 @@ static const RzCmdDescHelp cmd_search_value_64_help = { }; static const RzCmdDescDetailEntry cmd_search_hex_Usage_space_example_detail_entries[] = { - { .text = "Hexadecimal search of the exact bytes", .arg_str = NULL, .comment = "/x ffcc33" }, - { .text = "Hexadecimal search of the bytes with ignored nibbles", .arg_str = NULL, .comment = "/x ff..33" }, - { .text = "Hexadecimal search of the bytes with bytes mask", .arg_str = NULL, .comment = "/x ff43:ffd0" }, + { .text = "Hexadecimal search for the exact bytes 'ffcc33'.", .arg_str = NULL, .comment = "/x ffcc33" }, + { .text = "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits.", .arg_str = NULL, .comment = "/x ff..33.0" }, + { .text = "Hexadecimal search of the bytes with mask. Pattern: ':'", .arg_str = NULL, .comment = "/x ffd0:ff43" }, { 0 }, }; static const RzCmdDescDetail cmd_search_hex_details[] = { @@ -1708,7 +1708,7 @@ static const RzCmdDescDetail cmd_search_hex_details[] = { }; static const RzCmdDescArg cmd_search_hex_args[] = { { - .name = "bytes", + .name = "pattern", .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 42e5c90c368..a6f647b56a1 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -301,18 +301,17 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: bytes + - name: pattern type: RZ_CMD_ARG_TYPE_STRING details: - name: Usage example entries: - - text: "Hexadecimal search of the exact bytes" + - text: "Hexadecimal search for the exact bytes 'ffcc33'." comment: "/x ffcc33" - - text: "Hexadecimal search of the bytes with ignored nibbles" - comment: "/x ff..33" - - text: "Hexadecimal search of the bytes with bytes mask" - comment: "/x ff43:ffd0" - + - text: "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits." + comment: "/x ff..33.0" + - text: "Hexadecimal search of the bytes with mask. Pattern: ':'" + comment: "/x ffd0:ff43" - name: "/z" summary: String search. subcommands: diff --git a/librz/core/csearch.c b/librz/core/csearch.c new file mode 100644 index 00000000000..fb6645a16e0 --- /dev/null +++ b/librz/core/csearch.c @@ -0,0 +1,149 @@ +// SPDX-FileCopyrightText: 2024 deroad +// SPDX-FileCopyrightText: 2024 Rot127 +// SPDX-License-Identifier: LGPL-3.0-only + +#include "rz_config.h" +#include +#include +#include +#include +#include + +/** + * \brief Sets up the search find options according to the core config. + * + * \param core The core to get the config from. + * + * \return The find options to use. Or NULL in case of failure. + */ +RZ_API RZ_OWN RzSearchFindOpt *rz_core_setup_default_search_find_opts(RzCore *core) { + RzSearchFindOpt *fopts = rz_search_find_opt_new(); + if (!fopts) { + RZ_LOG_ERROR("Failed allocating find options.\n"); + return NULL; + } + if (!(rz_search_find_opt_set_inverse_match(fopts, rz_config_get_b(core->config, "search.inverse")) && + rz_search_find_opt_set_overlap_match(fopts, rz_config_get_b(core->config, "search.overlap")) && + rz_search_find_opt_set_alignment(fopts, rz_config_get_i(core->config, "search.io.alignment")))) { + RZ_LOG_ERROR("Failed set find options.\n"); + rz_search_find_opt_free(fopts); + return NULL; + } + return fopts; +} + +/** + * \brief Sets up the search parameters according to the core IO layer and config. + * + * \param core The core to get the IO maps, settings and other relevant information from. + * \param search_opts Search options to set up. Only fields to search behavior will be set (max_threads, max hits). Can be NULL. + * + * \return The boundaries to search in. Or NULL in case of failure. + */ +RZ_API RZ_OWN RzList /**/ *rz_core_setup_io_search_parameters(RzCore *core, RZ_NULLABLE RZ_OUT RzSearchOpt *search_opts) { + rz_return_val_if_fail(core && core->io && core->config, NULL); + RzList *boundaries = NULL; + + if (!core->io) { + RZ_LOG_ERROR("core: RzIO is not available.\n"); + return NULL; + } + + boundaries = rz_core_get_boundaries_select(core, "search.from", "search.to", "search.in"); + if (!boundaries || rz_list_empty(boundaries)) { + ut64 from = rz_config_get_i(core->config, "search.from"); + ut64 to = rz_config_get_i(core->config, "search.to"); + RZ_LOG_ERROR("core: Failed to get search boundaries within [0x%" PFMT64x ", 0x%" PFMT64x "].\n", from, to); + goto fail; + } + + if (search_opts) { + // Set search options known by core. + ut32 max_threads = rz_th_max_threads(rz_config_get_i(core->config, "search.max_threads")); + ut32 max_hits = rz_config_get_i(core->config, "search.maxhits"); + if (!(rz_search_opt_set_max_threads(search_opts, max_threads) && + rz_search_opt_set_max_hits(search_opts, max_hits))) { + RZ_LOG_ERROR("core: Failed to setup search options.\n"); + goto fail; + } + + RzSearchFindOpt *fopts = rz_core_setup_default_search_find_opts(core); + if (!fopts) { + RZ_LOG_ERROR("Failed setup find options.\n"); + goto fail; + } + rz_search_opt_set_find_options(search_opts, fopts); + } + + return boundaries; +fail: + rz_list_free(boundaries); + return NULL; +} + +static bool default_search_no_cancel(void *user, size_t n_hits, RzSearchCancelReason invoke_reason) { + return rz_cons_is_breaked(); +} + +/** + * \brief Finds a byte array in the IO layer of the given core and core configuration. + * + * \param core The RzCore core. + * \param opt The search options to apply. If it is NULL a default set of options is used. + * \param pattern The bytes pattern to search. + * + * \return On success returns a valid pointer, otherwise NULL + */ +RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NULLABLE RzSearchOpt *user_opts, RZ_NONNULL RZ_OWN RzSearchBytesPattern *pattern) { + rz_return_val_if_fail(core && core->config && pattern, NULL); + if (pattern->length < 1) { + RZ_LOG_ERROR("core: Cannot search for byte pattern if 'length' < 1.\n"); + rz_search_bytes_pattern_free(pattern); + return NULL; + } + + RzList *hits = NULL; + RzList *boundaries = NULL; + RzSearchOpt *search_opts = NULL; + + RzSearchCollection *collection = rz_search_collection_bytes(); + if (!collection || + !rz_search_collection_bytes_add_pattern(collection, pattern)) { + RZ_LOG_ERROR("core: Failed to initialize search collection.\n"); + rz_search_bytes_pattern_free(pattern); + goto quit; + } + + if (!user_opts) { + search_opts = rz_search_opt_new(); + if (!rz_search_opt_set_cancel_cb(search_opts, default_search_no_cancel, NULL)) { + RZ_LOG_ERROR("search: Failed to setup callback for search options.\n"); + goto quit; + } + } + + // Don't pass the user provided search options. + // They were set up by the user and we respect them. + boundaries = rz_core_setup_io_search_parameters(core, user_opts ? NULL : search_opts); + if (!boundaries) { + RZ_LOG_ERROR("core: Setting up search from core failed.\n"); + goto quit; + } + if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, pattern->length)) { + RZ_LOG_ERROR("search: Failed to update chunk size in the search options.\n"); + goto quit; + } + + hits = rz_search_on_io(user_opts ? user_opts : search_opts, collection, core->io, boundaries); + if (!hits) { + ut64 from = rz_config_get_i(core->config, "search.from"); + ut64 to = rz_config_get_i(core->config, "search.to"); + RZ_LOG_ERROR("core: Failed to search within [0x%" PFMT64x ", 0x%" PFMT64x "].\n", from, to); + } + +quit: + rz_list_free(boundaries); + rz_search_opt_free(search_opts); + rz_search_collection_free(collection); + return hits; +} diff --git a/librz/core/meson.build b/librz/core/meson.build index 296b0df3b5b..abf5394ce49 100644 --- a/librz/core/meson.build +++ b/librz/core/meson.build @@ -44,6 +44,7 @@ rz_core_sources = [ 'cplugin.c', 'cprint.c', 'creg.c', + 'csearch.c', 'csign.c', 'ctypes.c', 'cvfile.c', diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 1f7dcb65534..590aea83599 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -284,7 +284,6 @@ struct rz_core_t { RzFlag *flags; char *lastsearch; ///< Legacy search. Will be removed RzSearch *search; ///< Legacy search. Will be removed - RzSearchOpt *search_opts; RzEgg *egg; RzCrypto *crypto; RzAGraph *graph; @@ -1350,6 +1349,11 @@ RZ_API void rz_core_analysis_bytes_il(RZ_NONNULL RzCore *core, ut64 len, ut64 nu RZ_API bool rz_core_disasm_until_ret(RZ_NONNULL RzCore *core, ut64 addr, int limit, RzOutputMode mode, bool ret_val, RZ_NULLABLE RZ_OUT RzStrBuf *buf); +RZ_API RZ_OWN RzList /**/ *rz_core_setup_io_search_parameters(RzCore *core, RZ_OUT RzSearchOpt *search_opts); +RZ_API RZ_OWN RzSearchFindOpt *rz_core_setup_default_search_find_opts(RzCore *core); + +RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NULLABLE RzSearchOpt *user_opts, RZ_NONNULL RZ_OWN RzSearchBytesPattern *pattern); + #endif #ifdef __cplusplus diff --git a/librz/include/rz_io.h b/librz/include/rz_io.h index 1f485ccaccd..908218aeb48 100644 --- a/librz/include/rz_io.h +++ b/librz/include/rz_io.h @@ -338,9 +338,10 @@ RZ_API int rz_io_close_all(RzIO *io); RZ_API int rz_io_pread_at(RzIO *io, ut64 paddr, ut8 *buf, size_t len); RZ_API int rz_io_pwrite_at(RzIO *io, ut64 paddr, const ut8 *buf, size_t len); RZ_API bool rz_io_vread_at_mapped(RzIO *io, ut64 vaddr, ut8 *buf, size_t len); -RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, size_t len); +RZ_DEPRECATE RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, size_t len); RZ_API bool rz_io_read_at_mapped(RzIO *io, ut64 addr, ut8 *buf, size_t len); RZ_API int rz_io_nread_at(RzIO *io, ut64 addr, ut8 *buf, size_t len); +RZ_API RZ_OWN RzBuffer *rz_io_nread_at_new_buf(RZ_NONNULL RzIO *io, ut64 addr, size_t len); RZ_API bool rz_io_write_at(RzIO *io, ut64 addr, const ut8 *buf, size_t len); RZ_API bool rz_io_read(RzIO *io, ut8 *buf, size_t len); RZ_API bool rz_io_write(RzIO *io, const ut8 *buf, size_t len); diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index c206fc3de2b..4cd7ce6c56d 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -130,11 +130,16 @@ RZ_API int rz_search_pattern(RzSearch *s, ut64 from, ut64 to); RZ_LIB_VERSION_HEADER(rz_search); -#define RZ_SEARCH_MIN_BUFFER_SIZE 512u -#define RZ_SEARCH_CANCEL_CHECK_INTERVAL_USEC 1000 * 1000 - +/** + * \brief Private search options for the search module. Use the rz_search_opt_*() functions to edit it. + */ typedef struct rz_search_opt_t RzSearchOpt; +/** + * \brief Options for the find() callback of the different searches. + */ +typedef struct rz_search_find_opt_t RzSearchFindOpt; + typedef struct rz_search_collection_t RzSearchCollection; typedef struct rz_search_hit_t { @@ -148,6 +153,18 @@ typedef enum { RZ_SEARCH_CANCEL_SIGINT, ///< Interrupt signal (likely ctrl + c). } RzSearchCancelReason; +typedef struct bytes_pattern { + const char *pattern_desc; ///< Pattern metadata + ut8 *bytes; ///< Pattern bytes. + ut8 *mask; ///< Pattern mask (when NULL full match) + size_t length; ///< Pattern & mask length +} RzSearchBytesPattern; + +RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern *hp); +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp); +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_OWN ut8 *mask, size_t length, const char *pattern_desc); +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byte_pattern, RZ_NULLABLE const char *pattern_desc); + /** * \brief The cancel callback. It is invoked to check, if the search should be stopped. * @@ -162,11 +179,17 @@ typedef bool (*RzSearchCancelCallback)(void *user, size_t n_hits, RzSearchCancel RZ_API RZ_OWN RzSearchOpt *rz_search_opt_new(); RZ_API void rz_search_opt_free(RZ_NULLABLE RzSearchOpt *opt); -RZ_API bool rz_search_opt_set_inverse_match(RZ_NONNULL RzSearchOpt *opt, bool inverse_match); -RZ_API bool rz_search_opt_set_buffer_size(RZ_NONNULL RzSearchOpt *opt, size_t buffer_size); RZ_API bool rz_search_opt_set_max_hits(RZ_NONNULL RzSearchOpt *opt, size_t max_hits); +RZ_API bool rz_search_opt_set_elemet_size(RZ_NONNULL RzSearchOpt *opt, ut64 chunk_size); RZ_API bool rz_search_opt_set_max_threads(RZ_NONNULL RzSearchOpt *opt, RzThreadNCores max_threads); RZ_API bool rz_search_opt_set_cancel_cb(RZ_NONNULL RzSearchOpt *opt, RzSearchCancelCallback callback, void *user); +RZ_API bool rz_search_opt_set_find_options(RZ_NONNULL RzSearchOpt *opt, RZ_OWN RzSearchFindOpt *find_opts); + +RZ_API RZ_OWN RzSearchFindOpt *rz_search_find_opt_new(); +RZ_API void rz_search_find_opt_free(RZ_NULLABLE RzSearchFindOpt *opt); +RZ_API bool rz_search_find_opt_set_inverse_match(RZ_NONNULL RzSearchFindOpt *opt, bool inverse_match); +RZ_API bool rz_search_find_opt_set_overlap_match(RZ_NONNULL RzSearchFindOpt *opt, bool overlap_match); +RZ_API bool rz_search_find_opt_set_alignment(RZ_NONNULL RzSearchFindOpt *opt, size_t alignment); RZ_API RZ_OWN RzSearchCollection *rz_search_collection_aes_keys(); @@ -177,7 +200,7 @@ RZ_API bool rz_search_collection_regex_add(RZ_NONNULL RzSearchCollection *col, R RZ_API RZ_OWN RzSearchCollection *rz_search_collection_bytes(); RZ_API bool rz_search_collection_bytes_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *metadata, RZ_NONNULL const ut8 *bytes, RZ_NULLABLE const ut8 *mask, size_t length); -RZ_API bool rz_search_collection_bytes_add_pattern(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *hex_pattern); +RZ_API bool rz_search_collection_bytes_add_pattern(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RZ_OWN RzSearchBytesPattern *bytes_pattern); RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, bool caseless); RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *string); @@ -188,7 +211,7 @@ RZ_API bool rz_search_collection_match_any(RZ_NULLABLE RzSearchCollection *sc, R RZ_API void rz_search_collection_free(RZ_NULLABLE RzSearchCollection *sc); RZ_API void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit); -RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *opt, RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RzIO *io, RZ_NONNULL RzList /**/ *search_in); +RZ_API RZ_OWN RzList /**/ *rz_search_on_io(RZ_BORROW RZ_NONNULL RzSearchOpt *opt, RZ_BORROW RZ_NONNULL RzSearchCollection *col, RZ_BORROW RZ_NONNULL RzIO *io, RZ_BORROW RZ_NONNULL RzList /**/ *search_in); #ifdef __cplusplus } diff --git a/librz/include/rz_util/rz_buf.h b/librz/include/rz_util/rz_buf.h index ce3a2986c41..001ffff68cb 100644 --- a/librz/include/rz_util/rz_buf.h +++ b/librz/include/rz_util/rz_buf.h @@ -110,6 +110,7 @@ RZ_API RZ_OWN RzBuffer *rz_buf_new_sparse(ut8 Oxff); RZ_API RZ_OWN RzBuffer *rz_buf_new_sparse_overlay(RzBuffer *b, RzBufferSparseWriteMode write_mode); RZ_API RZ_OWN RzBuffer *rz_buf_new_with_buf(RzBuffer *b); RZ_API RZ_OWN RzBuffer *rz_buf_new_with_bytes(RZ_NULLABLE RZ_BORROW const ut8 *bytes, ut64 len); +RZ_API RZ_OWN RzBuffer *rz_buf_new_from_bytes(RZ_NULLABLE RZ_OWN const ut8 *bytes, ut64 len); RZ_API RZ_OWN RzBuffer *rz_buf_new_with_io_fd(RZ_NONNULL void /* RzIOBind */ *iob, int fd); RZ_API RZ_OWN RzBuffer *rz_buf_new_with_io(RZ_NONNULL void /* RzIOBind */ *iob); RZ_API RZ_OWN RzBuffer *rz_buf_new_with_methods(RZ_NONNULL const RzBufferMethods *methods, void *init_user, RzBufferType type); @@ -154,9 +155,19 @@ RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b); RZ_API ut64 rz_buf_tell(RZ_NONNULL RzBuffer *b); RZ_API void rz_buf_free(RzBuffer *b); RZ_API void rz_buf_set_overflow_byte(RZ_NONNULL RzBuffer *b, ut8 Oxff); +RZ_API bool rz_buf_is_bytes_buf(const RzBuffer *b); RZ_DEPRECATE RZ_API RZ_BORROW ut8 *rz_buf_data(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut64 *size); RZ_API RZ_BORROW const ut8 *rz_buf_get_whole_hot_paths(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut64 *sz); +/** + * \brief Callback to be used with rz_buf_fwd_scan(). + * + * \param buf Buffer it can read. + * \param len Length of buffer to read. + * \param user User data. + * + * \return The number of bytes read. + */ typedef ut64 (*RzBufferFwdScan)(RZ_BORROW RZ_NONNULL const ut8 *buf, ut64 len, RZ_NULLABLE void *user); RZ_API ut64 rz_buf_fwd_scan(RZ_NONNULL RzBuffer *b, ut64 start, ut64 amount, RZ_NONNULL RzBufferFwdScan fwd_scan, RZ_NULLABLE void *user); diff --git a/librz/include/rz_util/rz_hex.h b/librz/include/rz_util/rz_hex.h index 6c74cf2eaf6..a0d39ff6824 100644 --- a/librz/include/rz_util/rz_hex.h +++ b/librz/include/rz_util/rz_hex.h @@ -8,12 +8,15 @@ extern "C" { #endif RZ_API int rz_hex_pair2bin(const char *arg); -RZ_API int rz_hex_str2binmask(const char *in, ut8 *out, ut8 *mask); -RZ_API int rz_hex_str2bin(const char *in, ut8 *out); +RZ_API int rz_hex_str2bin_msb(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out); +RZ_API size_t rz_hex_str2bin_mask(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out, RZ_NULLABLE RZ_OUT ut8 *mask, bool lsb_extend); +RZ_API int rz_hex_str2bin(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out); RZ_API int rz_hex_bin2str(const ut8 *in, int len, char *out); RZ_API void rz_hex_ut2st_str(const ut32 in, RZ_INOUT char *out, const int len); RZ_API char *rz_hex_bin2strdup(const ut8 *in, int len); RZ_API bool rz_hex_to_byte(ut8 *val, ut8 c); +RZ_API ut8 rz_hex_digit_to_byte(const char c); +RZ_API ut16 rz_hex_digit_pair_to_byte(const char *c); RZ_API int rz_hex_str_is_valid(const char *s, bool allow_prefix); RZ_API st64 rz_hex_bin_truncate(ut64 in, int n); RZ_API char *rz_hex_from_c(const char *code); diff --git a/librz/io/io.c b/librz/io/io.c index bfde065ebf2..7d85dc56d2e 100644 --- a/librz/io/io.c +++ b/librz/io/io.c @@ -6,6 +6,9 @@ #include #include #include "io_private.h" +#include +#include +#include #if __WINDOWS__ #include @@ -294,7 +297,7 @@ static bool rz_io_vwrite_at(RzIO *io, ut64 vaddr, const ut8 *buf, size_t len) { // and complete. // For physical mode, the interface is broken because the actual read bytes are // not available. This requires fixes in all call sites. -RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, size_t len) { +RZ_DEPRECATE RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, size_t len) { rz_return_val_if_fail(io && buf && len >= 0, false); if (len == 0) { return false; @@ -352,6 +355,36 @@ RZ_API int rz_io_nread_at(RzIO *io, ut64 addr, ut8 *buf, size_t len) { return ret; } +/** + * \brief Reads from IO and returns the result in a RzBuffer. + * The actual number of bytes read, should be checked with rz_buf_size() + * on the returned buffer. + * + * \param io The IO object to read from. + * \param addr The address to read data from. + * \param len The number of bytes to read. It must be >0. + * + * \return The buffer holding the read bytes or NULL in case of failure. + */ +RZ_API RZ_OWN RzBuffer *rz_io_nread_at_new_buf(RZ_NONNULL RzIO *io, ut64 addr, size_t len) { + rz_return_val_if_fail(io && len > 0, NULL); + + ut8* raw_buf = malloc(len); + int ret = rz_io_nread_at(io, addr, raw_buf, len); + if (ret <= 0) { + RZ_LOG_ERROR("Failed to read from IO.\n"); + free(raw_buf); + return NULL; + } + RzBuffer *buf = rz_buf_new_from_bytes(raw_buf, len); + if (!buf) { + RZ_LOG_ERROR("Failed to initialize RzBuffer.\n"); + free(raw_buf); + return NULL; + } + return buf; +} + /** * \brief Writes \p len bytes of data from \p buf to \p addr into the given \p io. * diff --git a/librz/search/bytepat.c b/librz/search/bytepat.c deleted file mode 100644 index 4d776db57d3..00000000000 --- a/librz/search/bytepat.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-FileCopyrightText: 2006-2019 esteve -// SPDX-FileCopyrightText: 2006-2019 pancake -// SPDX-License-Identifier: LGPL-3.0-only - -#include -#include -#include - -#define CTXMINB 5 -#define BSIZE (1024 * 1024) -#define MAX_PATLEN 1024 - -typedef struct _fnditem { - unsigned char str[MAX_PATLEN]; - void *next; -} fnditem; - -static fnditem *init_fi(void) { - fnditem *n; - n = (fnditem *)malloc(sizeof(fnditem)); - if (!n) { - return NULL; - } - n->next = NULL; - return n; -} - -static void fini_fi(fnditem *fi) { - fnditem *fu; - fu = fi; - while (fi->next) { - fu = fi; - fi = fi->next; - free(fu); - fu = NULL; - } - free(fu); -} - -static void add_fi(fnditem *n, unsigned char *blk, int patlen) { - fnditem *p; - for (p = n; p->next != NULL; p = p->next) { - ; - } - p->next = (fnditem *)malloc(sizeof(fnditem)); - p = p->next; - memcpy(p->str, blk, patlen); - p->next = NULL; -} - -static int is_fi_present(fnditem *n, unsigned char *blk, int patlen) { - fnditem *p; - for (p = n; p->next != NULL; p = p->next) { - if (!memcmp(blk, p->str, patlen)) { - return true; - } - } - return false; -} - -RZ_API int rz_search_pattern(RzSearch *s, ut64 from, ut64 to) { - ut8 block[BSIZE + MAX_PATLEN], sblk[BSIZE + MAX_PATLEN + 1]; - ut64 addr, bact, bytes, intaddr, rb, bproc = 0; - int nr, i, moar = 0, pcnt, cnt = 0, k = 0; - int patlen = s->pattern_size; - fnditem *root; - - eprintf("Searching patterns between 0x%08" PFMT64x " and 0x%08" PFMT64x "\n", from, to); - if (patlen < 1 || patlen > MAX_PATLEN) { - eprintf("Invalid pattern length (must be > 1 and < %d)\n", MAX_PATLEN); - return false; - } - bact = from; - bytes = to; - // bytes += bact; - root = init_fi(); - pcnt = -1; - - // bact = from - // bytes = to - // bproc = from2 - while (bact < bytes) { - addr = bact; - if (rz_print_is_interrupted()) { - break; - } - - bproc = bact + patlen; - // read ( fd, sblk, patlen ); - // XXX bytepattern should be used with a read callback - nr = ((bytes - bproc) < BSIZE) ? (bytes - bproc) : BSIZE; - // XXX rizin_read_at(bact, sblk, patlen); - s->iob.read_at(s->iob.io, addr, sblk, nr); - sblk[patlen] = 0; // XXX - - intaddr = bact; - cnt = 0; - while (bproc < bytes) { - // TODO: handle ^C here - nr = ((bytes - bproc) < BSIZE) ? (bytes - bproc) : BSIZE; - nr += (patlen - (nr % patlen)); // tamany de bloc llegit multiple superior de tamany busqueda - rb = s->iob.read_at(s->iob.io, bproc, block, nr); - if (rb < 1) { - break; - } - nr = rb; - addr += nr; - moar = 0; - for (i = 0; i < nr; i++) { - if (!memcmp(&block[i], sblk, patlen) && !is_fi_present(root, sblk, patlen)) { - if (cnt == 0) { - add_fi(root, sblk, patlen); - pcnt++; - eprintf("\nbytes: %d: ", pcnt); - for (k = 0; k < patlen; k++) { - eprintf("%02x", sblk[k]); - } - eprintf("\nfound: %d: 0x%08" PFMT64x " ", pcnt, intaddr); - } - moar++; - cnt++; - eprintf("0x%08" PFMT64x " ", bproc + i); - } - } - if (moar > 0) { - eprintf("\ncount: %d: %d\n", pcnt, moar + 1); - } - bproc += rb; - } - bact += (moar > 0) ? patlen : 1; - } - eprintf("\n"); - fini_fi(root); - return 0; -} diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c new file mode 100644 index 00000000000..7e45e708517 --- /dev/null +++ b/librz/search/bytes_search.c @@ -0,0 +1,274 @@ +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-FileCopyrightText: 2024 deroad +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include + +#include +#include +#include +#include +#include "search_internal.h" + +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc) { + RzSearchBytesPattern *pat = RZ_NEW0(RzSearchBytesPattern); + if (!pat) { + return NULL; + } + pat->bytes = bytes; + pat->mask = mask; + pat->length = length; + pat->pattern_desc = pattern_desc; + return pat; +} + +RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern *hp) { + if (!hp) { + return; + } + free(hp->bytes); + free(hp->mask); + free(hp); +} + +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp) { + rz_return_val_if_fail(hp, NULL); + return rz_search_bytes_pattern_new(rz_new_copy(hp->length, hp->bytes), rz_new_copy(hp->length, hp->mask), hp->length, hp->pattern_desc); +} + +static bool parse_custom_mask(const char *bytes_pattern, const RzRegexMatch *mask_match, const RzRegexMatch *bytes_match, ut8 *mask) { + if (mask_match->len != bytes_match->len) { + RZ_LOG_ERROR("Mask and bytes must have the same number of nibbles. " + "But they mismatch: %" PFMTSZu " != %" PFMTSZu "\n", + mask_match->len, bytes_match->len); + return false; + } + if (strchr(bytes_pattern + bytes_match->start, '.')) { + RZ_LOG_ERROR("With a custom mask no wildcards are allowed.\n"); + return false; + } + + rz_hex_str2bin_mask(bytes_pattern + mask_match->start, mask, NULL, false); + return true; +} + +/** + * \brief Parses a byte pattern description string to a RzSearchBytesPattern object. + * + * The given byte pattern string should be of the form: `:`. + * + * Formatting rules: + * - The `mask` is optional. + * - Mask and bytes should be given in hexadeciaml numbers. + * - If the mask is given, it must be the same length as the bytes. + * - Each nibble can be replaced with a '.' to indicate a wildcard nibble. + * + * Examples: + * - `a987`: Exact pattern for the bytes '\xa9\x87'. + * - `a9.7`: Pattern for the bytes '\xa9\x.7', but the '.' part can be any nibble. + * - `.a9...c.99`: Pattern with multiple wildcards. + * - `a907:ff0f`: Pattern with a mask of `ff0f` and bytes of '\xa9\x07'. + * - `0xa907:0xff0f`: Mask and bytes with "0x" prefixes. + */ +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byte_pattern, RZ_NULLABLE const char *pattern_desc) { + rz_return_val_if_fail(byte_pattern, NULL); + + size_t size = 0; + ut8 *bytes = RZ_NEWS0(ut8, strlen(byte_pattern) + 1); + ut8 *mask = RZ_NEWS0(ut8, strlen(byte_pattern) + 1); + RzPVector *matches = NULL; + + // Some sanity checks + size_t ddot_count = rz_str_char_count(byte_pattern, ':'); + if (ddot_count > 1) { + RZ_LOG_ERROR("More than one ':' is invalid.\n"); + goto error; + } + bool has_wildcard = strchr(byte_pattern, '.') != NULL; + bool custom_mask = ddot_count == 1 ? true : false; + + if (rz_regex_contains("[^a-fA-F0-9.:x]", byte_pattern, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT)) { + RZ_LOG_ERROR("Pattern contains forbitten characters. Allowed is only '0x', '0-9', 'a-f', 'A-F', '.' and ':'.\n"); + goto error; + } + RzRegex *regex = rz_regex_new("^(0x)?([a-fA-F.0-9]+)(:(0x)?([a-fA-F0-9.]+))?", RZ_REGEX_DEFAULT, RZ_REGEX_DEFAULT); + matches = rz_regex_match_all_not_grouped(regex, byte_pattern, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT); + rz_regex_free(regex); + + if (!matches) { + RZ_LOG_ERROR("Regex matching failed.\n"); + goto error; + } + RzRegexMatch *bytes_match = rz_pvector_at(matches, 2); + RzRegexMatch *mask_match = rz_pvector_at(matches, 5); + if (!bytes_match || (custom_mask && !mask_match)) { + RZ_LOG_ERROR("Regex matching failed. Wrong group count.\n"); + goto error; + } + if (custom_mask && strchr(byte_pattern + mask_match->len, '.')) { + RZ_LOG_ERROR("The mask cannot contain wildcards.\n"); + goto error; + } + + bool odd_nibbles = bytes_match->len % 2 == 1; + bool use_mask = custom_mask || has_wildcard || odd_nibbles; + + if (custom_mask) { + use_mask = true; + if (!parse_custom_mask(byte_pattern, mask_match, bytes_match, mask)) { + goto error; + } + } + char *byte_str = rz_str_newlen(byte_pattern + bytes_match->start, bytes_match->len); + size = rz_hex_str2bin_mask(byte_str, bytes, custom_mask ? NULL : mask, false); + free(byte_str); + + rz_pvector_free(matches); + RzSearchBytesPattern *pat = rz_search_bytes_pattern_new(bytes, use_mask ? mask : NULL, size, pattern_desc); + if (!use_mask) { + free(mask); + } + return pat; + +error: + free(mask); + free(bytes); + rz_pvector_free(matches); + return NULL; +} + +static inline bool bytes_pattern_compare_no_mask(RZ_BORROW RZ_NONNULL const ut8 *buffer, RzSearchBytesPattern *hp) { + // Without mask only a memcmp(). + return memcmp(buffer, hp->bytes, hp->length) == 0; +} + +static inline bool bytes_pattern_compare_masked(RZ_BORROW RZ_NONNULL const ut8 *buffer, RzSearchBytesPattern *hp) { + // We can't compare by casting the buffer address + // to an ut64, ut32 etc. because the buffer address can be unaligned + // for this integer. So we would get undefined behavior. + // This is pretty much the simplest we can do + // (except writing assembly I guess). + for (size_t i = 0; i < hp->length; i++) { + ut8 mbyte = hp->mask[i]; + if ((hp->bytes[i] & mbyte) != (buffer[i] & mbyte)) { + return false; + } + } + return true; +} + +static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, ut8 *buffer, size_t size, RzThreadQueue *hits) { + if (!fopts) { + RZ_LOG_ERROR("bytes_find requires valid find options.\n"); + return false; + } + + RzPVector /**/ *patterns = (RzPVector *)user; + void **it = NULL; + + rz_pvector_foreach (patterns, it) { + RzSearchBytesPattern *hp = (RzSearchBytesPattern *)*it; + for (size_t offset = 0; offset < size;) { + size_t leftovers = size - offset; + if (hp->length > leftovers) { + break; + } + if (!hp->mask) { + if (!bytes_pattern_compare_no_mask(buffer + offset, hp)) { + offset++; + continue; + } + } else { + if (!bytes_pattern_compare_masked(buffer + offset, hp)) { + offset++; + continue; + } + } + RzSearchHit *hit = rz_search_hit_new(hp->pattern_desc, address + offset, hp->length); + if (!hit || !rz_th_queue_push(hits, hit, true)) { + rz_search_hit_free(hit); + return false; + } + offset += fopts->match_overlap ? 1 : hp->length; + } + } + return true; +} + +static bool bytes_is_empty(void *user) { + return rz_pvector_empty((RzPVector *)user); +} + +/** + * \brief Allocates and initialize a RzSearchCollection for hexadecimal byte searching. + * + * \return On success returns a valid pointer, otherwise NULL + */ +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_bytes() { + RzPVector /**/ *patterns = rz_pvector_new((RzPVectorFree)rz_search_bytes_pattern_free); + if (!patterns) { + RZ_LOG_ERROR("search: failed to initialize bytes collection\n"); + return NULL; + } + return rz_search_collection_new_bytes_space(bytes_find, bytes_is_empty, (RzSearchFreeCallback)rz_pvector_free, patterns); +} + +/** + * \brief Parses and adds a hex pattern into a bytes RzSearchCollection + * + * \param[in] col The RzSearchCollection to use + * \param[in] bytes_pattern The hexadecimal pattern to add + * + * \return On success returns true, otherwise false + */ +RZ_API bool rz_search_collection_bytes_add_pattern(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RZ_OWN RzSearchBytesPattern *bytes_pattern) { + rz_return_val_if_fail(col && bytes_pattern, false); + + if (!rz_search_collection_has_find_callback(col, bytes_find)) { + RZ_LOG_ERROR("search: cannot add hex to non-bytes collection\n"); + return false; + } + + if (!rz_pvector_push((RzPVector *)col->user, bytes_pattern)) { + RZ_LOG_ERROR("search: cannot add byte pattern to search.\n"); + return false; + } + return true; +} + +/** + * \brief Adds a custom bytes & mask pattern into a bytes RzSearchCollection + * + * \param col The RzSearchCollection to use + * \param[in] pattern_desc The pattern description + * \param[in] bytes The bytes to use + * \param[in] mask The mask to apply (can be NULL) + * \param[in] length The length of bytes & mask + * + * \return On success returns true, otherwise false + */ +RZ_API bool rz_search_collection_bytes_add(RZ_NONNULL RzSearchCollection *col, RZ_NULLABLE const char *pattern_desc, RZ_NONNULL const ut8 *bytes, RZ_NULLABLE const ut8 *mask, size_t length) { + rz_return_val_if_fail(col && pattern_desc && bytes, false); + + if (!rz_search_collection_has_find_callback(col, bytes_find)) { + RZ_LOG_ERROR("search: cannot add bytes to non-bytes collection\n"); + return false; + } else if (length < 1) { + RZ_LOG_ERROR("search: cannot add an empty byte sequence to a bytes collection\n"); + return false; + } else if (RZ_STR_ISEMPTY(pattern_desc)) { + RZ_LOG_ERROR("search: metadata is empty for the bytes collection\n"); + return false; + } + + RzSearchBytesPattern *hp = rz_search_bytes_pattern_new(rz_new_copy(length, bytes), rz_new_copy(length, mask), length, pattern_desc); + if (!hp) { + return false; + } else if (!rz_pvector_push((RzPVector *)col->user, hp)) { + RZ_LOG_ERROR("search: cannot add bytes pattern.\n"); + rz_search_bytes_pattern_free(hp); + return false; + } + return true; +} diff --git a/librz/search/collection.c b/librz/search/collection.c new file mode 100644 index 00000000000..0c6831c6613 --- /dev/null +++ b/librz/search/collection.c @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-FileCopyrightText: 2024 deroad +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "search_internal.h" + +static RZ_OWN RzSearchCollection *rz_search_collection_new(RzSearchSpace space, RZ_NONNULL void *find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user) { + rz_return_val_if_fail(find && is_empty, NULL); + RzSearchCollection *sc = RZ_NEW0(RzSearchCollection); + if (!sc) { + RZ_LOG_ERROR("search: failed to allocate RzSearchCollection\n"); + return NULL; + } + sc->space = space; + sc->find = find; + sc->is_empty = is_empty; + sc->free = free; + sc->user = user; + return sc; +} + +/** + * \brief Initialize a new RzSearchCollection over a graph. + * + * \param[in] find The find callback to set + * \param[in] is_empty The callback to use to check if collection is empty + * \param[in] free The callback to use to free the context + * \param user The additional context needed. + * + * \return On success returns a valid pointer, otherwise NULL. + */ +RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_graph_space(RZ_NONNULL RzSearchFindGraphCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user) { + rz_return_val_if_fail(find && is_empty, NULL); + return rz_search_collection_new(RZ_SEARCH_SPACE_GRAPH, find, is_empty, free, user); +} + +/** + * \brief Initialize a new RzSearchCollection over bytes. + * + * \param[in] find The find callback to set + * \param[in] is_empty The callback to use to check if collection is empty + * \param[in] free The callback to use to free the context + * \param user The additional context needed. + * + * \return On success returns a valid pointer, otherwise NULL. + */ +RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_bytes_space(RZ_NONNULL RzSearchFindBytesCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user) { + rz_return_val_if_fail(find && is_empty, NULL); + return rz_search_collection_new(RZ_SEARCH_SPACE_BYTES, find, is_empty, free, user); +} + +/** + * \brief Frees a RzSearchCollection structure + * + * \param[in] sc The RzSearchCollection pointer to free + */ +RZ_API void rz_search_collection_free(RZ_NULLABLE RzSearchCollection *sc) { + if (!sc) { + return; + } + if (sc->free) { + sc->free(sc->user); + } + free(sc); +} + +/** + * \brief Checks if a given RzSearchCollection has an expected find callback + * + * \param col The RzSearchCollection to test + * \param[in] expected The expected find callback + * + * \return Returns true when the RzSearchCollection callback matches the expected one. + */ +RZ_IPI bool rz_search_collection_has_find_callback(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL void *expected) { + rz_return_val_if_fail(col && expected, false); + return col->find == expected; +} + +/** + * \brief Checks if a given RzSearchCollection is empty + * + * \param col The RzSearchCollection to test + * + * \return Returns true when the RzSearchCollection is empty. + */ +RZ_IPI bool rz_search_collection_is_empty(RZ_NONNULL RzSearchCollection *col) { + rz_return_val_if_fail(col && col->is_empty, false); + return col->is_empty(col->user); +} diff --git a/librz/search/keyword.c b/librz/search/keyword.c index c4bfe00a751..2a32994dde3 100644 --- a/librz/search/keyword.c +++ b/librz/search/keyword.c @@ -189,7 +189,7 @@ RZ_API RzSearchKeyword *rz_search_keyword_new_hexmask(const char *kwstr, const c kw = malloc(len + 4); bm = malloc(len + 4); if (kw != NULL && bm != NULL) { - len = rz_hex_str2binmask(kwstr, (ut8 *)kw, (ut8 *)bm); + len = rz_hex_str2bin_mask(kwstr, (ut8 *)kw, (ut8 *)bm, true); if (len < 0) { len = -len - 1; } diff --git a/librz/search/meson.build b/librz/search/meson.build index 6d25bc442c3..ce12c18001f 100644 --- a/librz/search/meson.build +++ b/librz/search/meson.build @@ -1,12 +1,12 @@ rz_search_sources = [ 'aes-find.c', - 'bytepat.c', 'keyword.c', 'regexp.c', 'privkey-find.c', 'search.c', 'collection.c', 'options.c', + 'bytes_search.c', ] rz_search = library('rz_search', rz_search_sources, diff --git a/librz/search/options.c b/librz/search/options.c new file mode 100644 index 00000000000..e16c32eb1eb --- /dev/null +++ b/librz/search/options.c @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-FileCopyrightText: 2024 deroad +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "search_internal.h" + +RZ_API RZ_OWN RzSearchOpt *rz_search_opt_new() { + RzSearchOpt *opt = RZ_NEW0(RzSearchOpt); + if (!opt) { + return NULL; + } + opt->max_threads = RZ_THREAD_N_CORES_ALL_AVAILABLE; + opt->chunk_size = RZ_SEARCH_DEFAULT_CHUNK_SIZE; + return opt; +} + +RZ_API void rz_search_opt_free(RZ_NULLABLE RzSearchOpt *opt) { + if (opt) { + rz_search_find_opt_free(opt->find_opts); + } + free(opt); +} + +RZ_API bool rz_search_opt_set_max_hits(RZ_NONNULL RzSearchOpt *opt, size_t max_hits) { + rz_return_val_if_fail(opt, false); + opt->max_hits = max_hits; + return true; +} + +static bool set_chunk_size(RZ_NONNULL RzSearchOpt *opt, ut64 chunk_size) { + rz_return_val_if_fail(opt, false); + if (chunk_size < RZ_SEARCH_MIN_CHUNK_SIZE || chunk_size > RZ_SEARCH_MAX_CHUNK_SIZE) { + RZ_LOG_ERROR("search: Chunk size is not in range of %#" PFMT64x "-%#" PFMT64x " bytes.\n", + RZ_SEARCH_MIN_CHUNK_SIZE, + RZ_SEARCH_MAX_CHUNK_SIZE); + return false; + } + opt->chunk_size = chunk_size; + return true; +} + +static bool element_chunk_ratio_ok(ut64 element_size, ut64 chunk_size) { + if (element_size >= chunk_size) { + return false; + } + return (chunk_size / element_size) >= RZ_SEARCH_MIN_ELEMENTS_PER_CHUNK; +} + +RZ_API bool rz_search_opt_set_elemet_size(RZ_NONNULL RzSearchOpt *opt, ut64 element_size) { + rz_return_val_if_fail(opt, false); + if (!element_chunk_ratio_ok(element_size, opt->chunk_size)) { + if (!set_chunk_size(opt, element_size * RZ_SEARCH_MIN_ELEMENTS_PER_CHUNK)) { + RZ_LOG_ERROR("search: Element to search is too big.\n"); + return false; + } + } + opt->element_size = element_size; + return true; +} + +RZ_API bool rz_search_opt_set_max_threads(RZ_NONNULL RzSearchOpt *opt, RzThreadNCores max_threads) { + rz_return_val_if_fail(opt, false); + opt->max_threads = max_threads; + return true; +} + +RZ_API bool rz_search_opt_set_cancel_cb(RZ_NONNULL RzSearchOpt *opt, RzSearchCancelCallback callback, void *user) { + rz_return_val_if_fail(opt, false); + opt->cancel_cb = callback; + opt->cancel_usr = user; + return true; +} + +RZ_API bool rz_search_opt_set_find_options(RZ_NONNULL RzSearchOpt *opt, RZ_OWN RzSearchFindOpt *find_opts) { + rz_return_val_if_fail(opt, false); + opt->find_opts = find_opts; + return true; +} + +RZ_API RZ_OWN RzSearchFindOpt *rz_search_find_opt_new() { + return RZ_NEW0(RzSearchFindOpt); +} + +RZ_API void rz_search_find_opt_free(RZ_NULLABLE RzSearchFindOpt *opt) { + free(opt); +} + +RZ_API bool rz_search_find_opt_set_inverse_match(RZ_NONNULL RzSearchFindOpt *opt, bool inverse_match) { + rz_return_val_if_fail(opt, false); + opt->match_inverse = inverse_match; + return true; +} + +RZ_API bool rz_search_find_opt_get_inverse_match(RZ_NONNULL RzSearchFindOpt *opt) { + rz_return_val_if_fail(opt, false); + return opt->match_inverse; +} + +RZ_API bool rz_search_find_opt_set_overlap_match(RZ_NONNULL RzSearchFindOpt *opt, bool overlap_match) { + rz_return_val_if_fail(opt, false); + opt->match_overlap = overlap_match; + return true; +} + +RZ_API bool rz_search_find_opt_get_overlap_match(RZ_NONNULL RzSearchFindOpt *opt) { + rz_return_val_if_fail(opt, false); + return opt->match_overlap; +} + +RZ_API bool rz_search_find_opt_set_alignment(RZ_NONNULL RzSearchFindOpt *opt, size_t alignment) { + rz_return_val_if_fail(opt, false); + opt->alignment = alignment; + return true; +} + +RZ_API ut16 rz_search_find_opt_get_alignment(RZ_NONNULL RzSearchFindOpt *opt) { + rz_return_val_if_fail(opt, 0); + return opt->alignment; +} diff --git a/librz/search/search.c b/librz/search/search.c index 71db2f163e8..ae49156080c 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -2,7 +2,11 @@ // SPDX-FileCopyrightText: 2024 deroad // SPDX-License-Identifier: LGPL-3.0-only +#include +#include +#include #include +#include "search_internal.h" // Experimental search engine (fails, because stops at first hit of every block read #define USE_BMH 0 @@ -536,7 +540,6 @@ RZ_API void rz_search_kw_reset(RzSearch *s) { RZ_FREE(s->data); } - // // New search. // Everything above is only there to not break the build. @@ -548,9 +551,10 @@ RZ_API void rz_search_kw_reset(RzSearch *s) { typedef struct search_ctx { RzIO *io; ///< the RzIO struct to use + RzThreadLock *io_lock; RzSearchCollection *col; ///< collection to use RzSearchOpt *opt; ///< User options - RzThreadQueue *hits; ///< Hits list + RzThreadQueue /* RzSearchHits */ *hits; ///< Hits list RzAtomicBool *loop; ///< If set, the execution will continue until it terminates. If unset, the execution cancels. } search_ctx_t; @@ -560,7 +564,7 @@ static void *search_cancel_th(void *user) { do { size_t n_hits = rz_th_queue_size(ctx->hits); - if (!opt->cancel_cb(opt->cancel_usr, n_hits, RZ_SEARCH_CANCEL_REGULAR_CHECK)) { + if (opt->cancel_cb(opt->cancel_usr, n_hits, RZ_SEARCH_CANCEL_REGULAR_CHECK)) { rz_atomic_bool_set(ctx->loop, false); break; } @@ -570,48 +574,73 @@ static void *search_cancel_th(void *user) { return NULL; } -static bool search_iterator_bytes_cb(void *element, void *user) { +static bool search_iterator_io_map_cb(void *element, void *user) { search_ctx_t *ctx = (search_ctx_t *)user; - RzIOMap *map = (RzIOMap *)element; - if (!map) { + RzInterval *window = (RzInterval *)element; + if (!window) { return rz_atomic_bool_get(ctx->loop); } + if (!ctx->opt) { + RZ_LOG_ERROR("No search options given.\n"); + return false; + } - RzSearchOpt *opt = ctx->opt; RzSearchCollection *col = ctx->col; - ut8 *buffer = malloc(opt->buffer_size); - if (!buffer) { - rz_atomic_bool_set(ctx->loop, false); - return false; - } + ut64 at = window->addr; + ut64 size = window->size; - const ut64 from = rz_itv_begin(map->itv); - const ut64 to = rz_itv_end(map->itv); + // read the buffer + ut8 *buffer = malloc(size); + rz_th_lock_enter(ctx->io_lock); + int read = rz_io_nread_at(ctx->io, at, buffer, size); + if (!buffer || read != size) { + RZ_LOG_ERROR("search: failed to read at 0x%08" PFMT64x " (0x%08" PFMT64x " bytes)\n", at, size); + rz_th_lock_leave(ctx->io_lock); + goto failure; + } + rz_th_lock_leave(ctx->io_lock); - for (ut64 at = from; at < to; at += opt->buffer_size) { - if (!rz_atomic_bool_get(ctx->loop)) { - break; - } - // calculate the buffer size - size_t size = opt->buffer_size; - if ((at + opt->buffer_size) > to) { - size = to - at; - } - // read the buffer - if (!rz_io_read_at(ctx->io, at, buffer, size)) { - RZ_LOG_ERROR("search: failed to read at 0x%08" PFMT64x " (%" PFMTSZu " bytes)\n", at, size); - break; - } - RzSearchFindBytesCallback find = col->find; - if (!find(col->user, at, buffer, size, ctx->hits)) { - RZ_LOG_ERROR("search: failed search at 0x%08" PFMT64x "\n", at); - break; - } + RzSearchFindBytesCallback find = col->find; + if (!find(ctx->opt->find_opts, col->user, at, buffer, size, ctx->hits)) { + RZ_LOG_ERROR("search: failed search at 0x%08" PFMT64x "\n", at); + goto failure; } free(buffer); return rz_atomic_bool_get(ctx->loop); + +failure: + free(buffer); + rz_atomic_bool_set(ctx->loop, false); + return false; +} + +static RzList *assemble_search_window_list(RzList /**/ *search_in, RzSearchOpt *opt) { + rz_return_val_if_fail(search_in && opt && opt->element_size, NULL); + RzList *list = rz_list_newf(free); + if (!list) { + return NULL; + } + + RzIOMap *map; + RzListIter *iter; + rz_list_foreach(search_in, iter, map) { + ut64 start = map->itv.addr; + ut64 end = start + map->itv.size; + for (size_t chunk_begin = start; chunk_begin < end; chunk_begin += opt->chunk_size) { + ut64 window_size = opt->chunk_size + opt->element_size - 1; + if (chunk_begin + window_size > end) { + window_size = end - chunk_begin; + } + + RzInterval *window = RZ_NEW0(RzInterval); + window->addr = chunk_begin; + window->size = window_size; + rz_list_append(list, window); + } + } + return list; } /** @@ -624,20 +653,25 @@ static bool search_iterator_bytes_cb(void *element, void *user) { * * \return On success returns all the hits. */ -RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *opt, RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RzIO *io, RZ_NONNULL RzList /**/ *search_in) { +RZ_API RZ_OWN RzList /**/ *rz_search_on_io( + RZ_BORROW RZ_NONNULL RzSearchOpt *opt, + RZ_BORROW RZ_NONNULL RzSearchCollection *col, + RZ_BORROW RZ_NONNULL RzIO *io, + RZ_BORROW RZ_NONNULL RzList /**/ *search_in) { rz_return_val_if_fail(opt && col && io && search_in, NULL); search_ctx_t ctx = { 0 }; RzList *results = NULL; RzThreadQueue *hits = NULL; + RzList /* RzInterval */ *windows = NULL; RzThread *cancel_th = NULL; if (!rz_search_collection_on_bytes_space(col)) { - RZ_LOG_ERROR("search: The search collection is not initialized for bytes.\n"); + RZ_LOG_ERROR("search: The search collection is not initialized for byte space.\n"); return NULL; } - if (opt->buffer_size < RZ_SEARCH_MIN_BUFFER_SIZE) { - RZ_LOG_ERROR("search: cannot search when buffer size is less than %u bytes.\n", RZ_SEARCH_MIN_BUFFER_SIZE); + if (opt->chunk_size < RZ_SEARCH_MIN_CHUNK_SIZE) { + RZ_LOG_ERROR("search: cannot search when buffer size is less than %#" PFMT64x " bytes.\n", RZ_SEARCH_MIN_CHUNK_SIZE); return NULL; } @@ -657,10 +691,19 @@ RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *o return NULL; } + windows = assemble_search_window_list(search_in, opt); + if (!windows) { + RZ_LOG_ERROR("search: Could not prepare search window queue.\n"); + rz_list_free(windows); + return NULL; + } + ctx.col = col; ctx.opt = opt; ctx.io = io; + ctx.io_lock = rz_th_lock_new(false); ctx.loop = rz_atomic_bool_new(true); + ctx.hits = hits; if (opt->cancel_cb) { // create cancel thread @@ -668,11 +711,12 @@ RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *o if (!cancel_th) { RZ_LOG_ERROR("search: cannot allocate cancel thread.\n"); rz_th_queue_free(hits); + rz_atomic_bool_free(ctx.loop); return NULL; } } - if (!rz_th_iterate_list(search_in, search_iterator_bytes_cb, opt->max_threads, &ctx)) { + if (!rz_th_iterate_list(windows, search_iterator_io_map_cb, opt->max_threads, &ctx)) { RZ_LOG_ERROR("search: cannot iterate over list.\n"); } else { results = rz_th_queue_pop_all(hits); @@ -683,8 +727,11 @@ RZ_IPI RZ_OWN RzList /**/ *rz_search_io(RZ_NONNULL RzSearchOpt *o rz_atomic_bool_set(ctx.loop, false); rz_th_wait(cancel_th); rz_th_free(cancel_th); + rz_atomic_bool_free(ctx.loop); } + rz_th_lock_free(ctx.io_lock); + rz_list_free(windows); rz_th_queue_free(hits); return results; } diff --git a/librz/search/search_internal.h b/librz/search/search_internal.h index df3a6cc6f91..455ec5286fd 100644 --- a/librz/search/search_internal.h +++ b/librz/search/search_internal.h @@ -13,6 +13,38 @@ #define RZ_SEARCH_PRIVATE_KEY_LENGTH 11 #define RZ_SEARCH_MAX_HEX_PATTERN UT16_MAX +/** + * \brief The number of elements per search chunk. + * Note, the actual buffer, passed to the find() callback, + * will be bigger by sizeof(element) - 1. + * To also find elements crossing chunk boundaries. + * + * ATTENTION: If you change this value, update the test + * in cmd_search_x::"search over boundary" + */ +#define RZ_SEARCH_MIN_ELEMENTS_PER_CHUNK 64u + +/** + * \brief Minimal buffer size for each find() thread in bytes. + */ +#define RZ_SEARCH_MIN_CHUNK_SIZE 32ull + +/** + * \brief Default buffer size for each find() thread in bytes. + * Size: 4096 + * + * ATTENTION: If you change this value, update the test + * in cmd_search_x::"search over boundary" + */ +#define RZ_SEARCH_DEFAULT_CHUNK_SIZE 0x1000ull + +/** + * \brief Maximum buffer size to check in each find() thread in bytes. + * Size: 4G + */ +#define RZ_SEARCH_MAX_CHUNK_SIZE 0x100000000ull +#define RZ_SEARCH_CANCEL_CHECK_INTERVAL_USEC 100 * 1000 + /** * \brief The callback to free the private user data in the RzSearchCollection. * @@ -33,13 +65,12 @@ typedef bool (*RzSearchIsEmptyCallback)(void *user); * \param user The private user data. * \param address The address associated with the given bytes. * \param buffer The bytes buffer. - * \param size The buffer size in bytes. * \param The queue to push new hits onto. * * \return True, if a match was found. * \return False otherwise. */ -typedef bool (*RzSearchFindBytesCallback)(void *user, ut64 address, const ut8 *buffer, size_t size, RZ_OUT RzThreadQueue *hits); +typedef bool (*RzSearchFindBytesCallback)(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 address, ut8 *buffer, size_t size, RZ_OUT RzThreadQueue *hits); /** * \brief A callback to search a graph for a pattern. @@ -51,7 +82,7 @@ typedef bool (*RzSearchFindBytesCallback)(void *user, ut64 address, const ut8 *b * \return True, if a match was found. * \return False otherwise. */ -typedef bool (*RzSearchFindGraphCallback)(void *user, const RzGraph *graph, RZ_OUT RzThreadQueue *hits); +typedef bool (*RzSearchFindGraphCallback)(RzSearchFindOpt *fopt, void *user, const RzGraph *graph, RZ_OUT RzThreadQueue *hits); typedef enum { RZ_SEARCH_SPACE_BYTES = 0, ///< The search is performed on bytes. @@ -68,9 +99,10 @@ struct rz_search_collection_t { }; struct rz_search_opt_t { - bool inverse_match; - size_t buffer_size; + RzSearchFindOpt *find_opts; size_t max_hits; + ut64 chunk_size; + ut64 element_size; RzThreadNCores max_threads; // cancel callback @@ -78,13 +110,23 @@ struct rz_search_opt_t { RzSearchCancelCallback cancel_cb; }; +struct rz_search_find_opt_t { + bool match_inverse; ///< Set if the inverse of the given pattern should be matched. + bool match_overlap; ///< Set if hits can overlap. + size_t alignment; ///< The address alignment to start the search from. If >1, only `buffer + (alignment * x)` is searched. +}; + RZ_IPI RZ_OWN RzSearchHit *rz_search_hit_new(const char *metadata, ut64 address, size_t size); -RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_bytes(RZ_NONNULL RzSearchFindBytesCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); -RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_graph(RZ_NONNULL RzSearchFindGraphCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); +RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_bytes_space(RZ_NONNULL RzSearchFindBytesCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); +RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_graph_space(RZ_NONNULL RzSearchFindGraphCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); RZ_IPI bool rz_search_collection_has_find_callback(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL void *expected); RZ_IPI bool rz_search_collection_is_empty(RZ_NONNULL RzSearchCollection *col); -RZ_IPI static inline bool rz_search_collection_on_bytes_space(RZ_NONNULL RzSearchCollection *col) { return col->space == RZ_SEARCH_SPACE_BYTES; }; -RZ_IPI static inline bool rz_search_collection_on_graph_space(RZ_NONNULL RzSearchCollection *col) { return col->space == RZ_SEARCH_SPACE_GRAPH; }; +RZ_IPI static inline bool rz_search_collection_on_bytes_space(RZ_NONNULL RzSearchCollection *col) { + return col->space == RZ_SEARCH_SPACE_BYTES; +}; +RZ_IPI static inline bool rz_search_collection_on_graph_space(RZ_NONNULL RzSearchCollection *col) { + return col->space == RZ_SEARCH_SPACE_GRAPH; +}; #endif /* RZ_SEARCH_INTERNAL_H */ diff --git a/librz/util/buf.c b/librz/util/buf.c index 7be77d9773f..fd7213411c2 100644 --- a/librz/util/buf.c +++ b/librz/util/buf.c @@ -547,6 +547,29 @@ RZ_API RZ_OWN RzBuffer *rz_buf_new_with_bytes(RZ_NULLABLE RZ_BORROW const ut8 *b return new_buffer(RZ_BUFFER_BYTES, &u); } +/** + * \brief Creates a new buffer with a bytes array. + * The buffer takes ownership of the bytes array. + * + * \param bytes The bytes array used to initialized the buffer. + * \param len The length of the bytes array. + * \return Return the new allocated buffer. + * + * The function creates a new buffer in memory, initializing it with the bytes + * passed as argument. The bytes parameter can be NULL, but the length should + * be set to 0. + */ +RZ_API RZ_OWN RzBuffer *rz_buf_new_from_bytes(RZ_NULLABLE RZ_OWN const ut8 *bytes, ut64 len) { + rz_return_val_if_fail(bytes || !len, NULL); // if bytes == NULL, then len must be 0 + + struct buf_bytes_user u = { 0 }; + u.length = len; + u.data_steal = bytes; + u.steal = true; + + return new_buffer(RZ_BUFFER_BYTES, &u); +} + // TODO: Optimize to use memcpy when buffers are not in range.. // check buf boundaries and offsets and use memcpy or memmove @@ -1381,6 +1404,17 @@ RZ_API void rz_buf_set_overflow_byte(RZ_NONNULL RzBuffer *b, ut8 Oxff) { b->Oxff_priv = Oxff; } +/** + * \brief Returns true if \b is a bytes buffer. + * + * \param b The buffer to check. + * + * \return True if the buffer is a raw bytes buffer. False otherwise. + */ +RZ_API bool rz_buf_is_bytes_buf(const RzBuffer *b) { + return b->type == RZ_BUFFER_BYTES; +} + /** * \brief Return a borrowed array of bytes representing the buffer data. * \param b Buffer to get the data from. diff --git a/librz/util/hex.c b/librz/util/hex.c index 981332bbbe7..c69d3e6aa02 100644 --- a/librz/util/hex.c +++ b/librz/util/hex.c @@ -6,6 +6,71 @@ #include #include +/** + * \brief Returns the byte value for a hexadecimal nibble. + * + * Example: + * assert(rz_hex_nibble_to_byte('1') == 1); + * assert(rz_hex_nibble_to_byte('A') == 10); + * assert(rz_hex_nibble_to_byte('b') == 11); + * assert(rz_hex_nibble_to_byte('S') == UT8_MAX); + * assert(rz_hex_nibble_to_byte('\0') == UT8_MAX); + * + * \param The hexadecimal nibble to get the raw byte value for. + * + * \param The byte value of the nibble. + * Or UT8_MAX if the nibble is no hexadecimal character. + */ +RZ_API ut8 rz_hex_digit_to_byte(const char c) { + if (!isxdigit(c)) { + return UT8_MAX; + } + // Check an ASCII table for this. + // Bit 6 indicates if it is A-F or a-f. + ut8 byte = (c & 0x40) ? 9 : 0; + // Bit 3-0 are the same bits for upper and lower case A-F. + // And 'a' & 0xf == 1, so 9 + 1 == 10. + byte += (c & 0xf); + return byte; +} + +/** + * \brief Returns the byte value for a hexadecimal nibble pair. + * It stops parsing at the first non hex digit. + * + * Example: + * assert(rz_hex_nibble_pair_to_byte("1") == 1); + * assert(rz_hex_nibble_pair_to_byte("11") == 17); + * assert(rz_hex_nibble_pair_to_byte("fe") == 254); + * + * assert(rz_hex_nibble_pair_to_byte("ff01") == 255); + * assert(rz_hex_nibble_pair_to_byte("F@") == 15); + * assert(rz_hex_nibble_pair_to_byte("p1") == UT16_MAX); + * assert(rz_hex_nibble_pair_to_byte("") == UT16_MAX); + * + * \param The string to parse as hex digit pair. + * + * \param The byte value of the nibble pair. + * Or UT16_MAX if the nibble is no hexadecimal character. + */ +RZ_API ut16 rz_hex_digit_pair_to_byte(const char *npair) { + if (!isxdigit(npair[0])) { + return UT16_MAX; + } + ut8 n0 = rz_hex_digit_to_byte(npair[0]); + if (n0 == UT8_MAX) { + return UT16_MAX; + } + if (!isxdigit(npair[1])) { + return n0; + } + ut8 n1 = rz_hex_digit_to_byte(npair[1]); + if (n1 == UT8_MAX) { + return UT16_MAX; + } + return (n0 << 4 | n1); +} + /* int c = 0; ret = hex_to_byte(&c, 'c'); */ RZ_API bool rz_hex_to_byte(ut8 *val, ut8 c) { if (IS_DIGIT(c)) { @@ -436,17 +501,77 @@ RZ_API char *rz_hex_bin2strdup(const ut8 *in, int len) { return out; } +/** + * \brief Convert an input string \p in into the binary form in \p out. + * For odd number of nibbles, the MSB side is extended with a 0 nibble. + * + * If \p in contains non-hexadecimal digits, the result is undefined. + * + * Convert an input string in the hexadecimal form (e.g. "41424344") into the + * raw binary form (e.g. "\x41\x42\x43\x44" or "ABCD"). + * + * Note: If an odd number of nibbles is given, the buffer is extended on the side of the MSB with a 0 nibble. + * So, "444" becomes "\x04\x44". + * Use rz_hex_str2bin() if you need to extend it on the LSB side. + * + * \param in Input string in hexadecimal form. An optional "0x" prefix may be present. + * \param out Output buffer having at least strlen(in) / 2 bytes available + * \return Number of bytes written into \p out. The number is negative if an odd number of nibbles was parsed. + */ +RZ_API int rz_hex_str2bin_msb(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out) { + rz_return_val_if_fail(in && out, 0); + + if (!in[0]) { + return 0; + } + + size_t i = 0, j = 0; + if (in[0] == '0' && in[1] == 'x') { + i += 2; + } + + ut8 byte = 0; + size_t nibbles = rz_str_ansi_len(in + i); + + bool odd_nibble = (nibbles % 2) == 1; + if (odd_nibble) { + byte = rz_hex_digit_to_byte(in[i]); + if (byte == UT8_MAX) { + return 0; + } + out[j] = byte; + i++; + j++; + } + + + for (byte = rz_hex_digit_pair_to_byte(in + i); i < strlen(in) && byte != UT16_MAX; j++, i += 2, byte = rz_hex_digit_pair_to_byte(in + i)) { + out[j] = byte; + } + + return odd_nibble ? -j : j; +} + /** * \brief Convert an input string \p in into the binary form in \p out + * For odd number of nibbles, the LSB side is extended with a 0 nibble. + * + * If \p in contains non-hexadecimal digits, the result is undefined. * * Convert an input string in the hexadecimal form (e.g. "41424344") into the - * raw binary form (e.g. "ABCD") + * raw binary form (e.g. "\x41\x42\x43\x44" or "ABCD"). + * + * Note: If an odd number of nibbles is given, the buffer is extended on the side of the LSB with a 0 nibble. + * So, "444" becomes "\x44\x40". + * Use rz_hex_str2bin_msb() if you need to extend it on the MSB side. * * \param in Input string in hexadecimal form. An optional "0x" prefix may be present. * \param out Output buffer having at least strlen(in) / 2 bytes available - * \return number of bytes written into \p out + * \return Number of bytes written into \p out. The number is negative if an odd number of nibbles was parsed. */ -RZ_API int rz_hex_str2bin(const char *in, ut8 *out) { +RZ_API int rz_hex_str2bin(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out) { + rz_return_val_if_fail(in && out, 0); + long nibbles = 0; while (in && *in) { @@ -492,39 +617,96 @@ RZ_API int rz_hex_str2bin(const char *in, ut8 *out) { return nibbles / 2; } -RZ_API int rz_hex_str2binmask(const char *in, ut8 *out, ut8 *mask) { - ut8 *ptr; - int len, ilen = strlen(in) + 1; - int has_nibble = 0; - memcpy(out, in, ilen); - for (ptr = out; *ptr; ptr++) { - if (*ptr == '.') { - *ptr = '0'; - } +/** + * \brief Transforms an input hex string to its byte array eqivalent and a mask for it. + * The hex string is allowed to contain '.' characters as wildcard. + * Wildcards in \p in are set to '0' in the mask and \p out. + * It stops at the first invalid character and returns. + * + * If \p in contains non-hexadecimal digits, the result is undefined. + * + * The input string may be prefixed with a "0x". + * + * Example: + * rz_hex_str2bin_mask("ffe4", out, mask, false); + * assert_mem_eq(out, { 0xff, 0xe4 }); + * assert_mem_eq(mask, { 0xff, 0xff }); + * + * rz_hex_str2bin_mask("ff.4", out, mask, false); + * assert_mem_eq(out, { 0xff, 0x04 }); + * assert_mem_eq(mask, { 0xff, 0x0f }); + * + * // Extend on MSB side + * rz_hex_str2bin_mask("ffee4", out, mask, false); + * assert_mem_eq(out, { 0x0f, 0xfe, 0xe4 }); + * assert_mem_eq(mask, { 0x0f, 0xff, 0xff }); + * + * // Extend on LSB side + * rz_hex_str2bin_mask("ee4", out, mask, true); + * assert_mem_eq(out, { 0xee, 0x40 }); + * assert_mem_eq(mask, { 0xff, 0xf0 }); + * + * \param in The hex string to parse and transform. + * \param out The output buffer. It must be the same size as \p strlen(in) / 2. + * \param mask The output buffer for the mask. It must be the same size as \p out. + * Can be NULL, if no mask is required. + * \param lsb_extend If set and \p in has an odd number hex digits, + * it extends the byte buffer with a wildcard nibble at the LSB (right) side. + * If unset and with an odd digit count, it extends on the MSB (left) side. + * + * \return The number of bytes written to \p out and \p mask. In case of failure it returns less then 0. + * Note: In case of failure the content of \p out and \p mask are undefined. + */ +RZ_API size_t rz_hex_str2bin_mask(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out, RZ_NULLABLE RZ_OUT ut8 *mask, bool lsb_extend) { + rz_return_val_if_fail(in && out, 0); + + if (in[0] == '\0') { + return 0; } - len = rz_hex_str2bin((char *)out, out); - if (len < 0) { - has_nibble = 1; - len = -(len + 1); + + char *in_cpy = strdup(in); + for (size_t i = 0; in_cpy[i]; ++i) { + if (in_cpy[i] == '.') { + in_cpy[i] = '0'; + } } - if (len != -1) { - memcpy(mask, in, ilen); - if (has_nibble) { - memcpy(mask + ilen, "f0", 3); + + int bytes_copied; + if (lsb_extend) { + bytes_copied = rz_hex_str2bin(in_cpy, out); + } else { + bytes_copied = rz_hex_str2bin_msb(in_cpy, out); + } + size_t ret = bytes_copied < 0 ? -bytes_copied : bytes_copied; + + if (!mask) { + free(in_cpy); + return ret; + } + bool odd_nibbles = bytes_copied < 0; + for (size_t i = 0; i < ret; ++i) { + int low_offset = (i * 2); + int high_offset = (i * 2) + 1; + char low_digit; + char high_digit; + if (odd_nibbles && (i == 0 || i == (ret - 1))) { + low_digit = (i == 0 && !lsb_extend) ? '.' : in[low_offset]; + high_digit = (i == ret - 1) && lsb_extend ? '.' : in[high_offset - 1]; + } else { + low_digit = in[low_offset]; + high_digit = in[high_offset]; } - for (ptr = mask; *ptr; ptr++) { - if (IS_HEXCHAR(*ptr)) { - *ptr = 'f'; - } else if (*ptr == '.') { - *ptr = '0'; - } + + mask[i] = 0x00; + if (low_digit != '.') { + mask[i] |= 0xf0; } - len = rz_hex_str2bin((char *)mask, mask); - if (len < 0) { - len++; + if (high_digit != '.') { + mask[i] |= 0x0f; } } - return len; + free(in_cpy); + return ret; } RZ_API st64 rz_hex_bin_truncate(ut64 in, int n) { diff --git a/test/db/cmd/cmd_search_x b/test/db/cmd/cmd_search_x new file mode 100644 index 00000000000..05557f900ba --- /dev/null +++ b/test/db/cmd/cmd_search_x @@ -0,0 +1,258 @@ +NAME=Search hex byte search - errors +FILE=bins/cmd/search/hex_bytes +CMDS=< Date: Wed, 1 Jan 2025 14:00:30 -0500 Subject: [PATCH 005/157] Add search test within debug maps. --- test/db/archos/linux-x64/dbg_search_x | 20 ++++++++++++++++++++ test/db/cmd/cmd_search_x | 14 ++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/db/archos/linux-x64/dbg_search_x diff --git a/test/db/archos/linux-x64/dbg_search_x b/test/db/archos/linux-x64/dbg_search_x new file mode 100644 index 00000000000..57f860c139a --- /dev/null +++ b/test/db/archos/linux-x64/dbg_search_x @@ -0,0 +1,20 @@ +NAME=Search library maps. +FILE=bins/elf/arch-x86_64-ls +ARGS=-d +CMDS=< Date: Wed, 1 Jan 2025 14:13:50 -0500 Subject: [PATCH 006/157] Make BytesPattern implementation private. --- librz/core/csearch.c | 6 +++--- librz/include/rz_search.h | 11 ++++------- librz/search/bytes_search.c | 32 ++++++++++++++++++++++++++++++++ librz/search/search_internal.h | 7 +++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/librz/core/csearch.c b/librz/core/csearch.c index fb6645a16e0..92892210cbf 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -96,8 +96,8 @@ static bool default_search_no_cancel(void *user, size_t n_hits, RzSearchCancelRe */ RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NULLABLE RzSearchOpt *user_opts, RZ_NONNULL RZ_OWN RzSearchBytesPattern *pattern) { rz_return_val_if_fail(core && core->config && pattern, NULL); - if (pattern->length < 1) { - RZ_LOG_ERROR("core: Cannot search for byte pattern if 'length' < 1.\n"); + if (rz_search_bytes_pattern_len(pattern) == 0) { + RZ_LOG_ERROR("core: Cannot search for byte pattern if 'length' == 0.\n"); rz_search_bytes_pattern_free(pattern); return NULL; } @@ -129,7 +129,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore RZ_LOG_ERROR("core: Setting up search from core failed.\n"); goto quit; } - if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, pattern->length)) { + if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, rz_search_bytes_pattern_len(pattern))) { RZ_LOG_ERROR("search: Failed to update chunk size in the search options.\n"); goto quit; } diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index 4cd7ce6c56d..505a88e248d 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -153,17 +153,14 @@ typedef enum { RZ_SEARCH_CANCEL_SIGINT, ///< Interrupt signal (likely ctrl + c). } RzSearchCancelReason; -typedef struct bytes_pattern { - const char *pattern_desc; ///< Pattern metadata - ut8 *bytes; ///< Pattern bytes. - ut8 *mask; ///< Pattern mask (when NULL full match) - size_t length; ///< Pattern & mask length -} RzSearchBytesPattern; +typedef struct rz_search_bytes_pattern_t RzSearchBytesPattern; RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern *hp); RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp); -RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_OWN ut8 *mask, size_t length, const char *pattern_desc); +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc); RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byte_pattern, RZ_NULLABLE const char *pattern_desc); +RZ_API size_t rz_search_bytes_pattern_len(RZ_NONNULL const RzSearchBytesPattern *hp); +RZ_API const char *rz_search_bytes_pattern_desc(RZ_NONNULL const RzSearchBytesPattern *bp); /** * \brief The cancel callback. It is invoked to check, if the search should be stopped. diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index 7e45e708517..ee187bb08a4 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -11,9 +11,21 @@ #include #include "search_internal.h" +/** + * \brief Initialize a new search bytes pattern and return it. + * + * \param bytes The bytes to search for. + * \param mask The mask to apply to the pattern and the data before comparison. (optional) + * \param length Length of \p bytes and \p mask (if not NULL). + * \param pattern_desc An optional description string of the pattern. + * + * \return The initalized pattern or NULL in case of failure. + */ RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc) { + rz_return_val_if_fail(bytes && length > 0, NULL); RzSearchBytesPattern *pat = RZ_NEW0(RzSearchBytesPattern); if (!pat) { + RZ_LOG_ERROR("Failed to allocate pattern struct.\n"); return NULL; } pat->bytes = bytes; @@ -32,6 +44,26 @@ RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern free(hp); } +/** + * \brief Return the pattern description if any. + * + * \return The pattern description string or NULL if there is none. + */ +RZ_API const char *rz_search_bytes_pattern_desc(RZ_NONNULL const RzSearchBytesPattern *bp) { + rz_return_val_if_fail(bp, 0); + return bp->pattern_desc; +} + +/** + * \brief Return the pattern length in number of bytes. + * + * \return Return the pattern length in number of bytes or 0 in case of failure. + */ +RZ_API size_t rz_search_bytes_pattern_len(RZ_NONNULL const RzSearchBytesPattern *bp) { + rz_return_val_if_fail(bp, 0); + return bp->length; +} + RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp) { rz_return_val_if_fail(hp, NULL); return rz_search_bytes_pattern_new(rz_new_copy(hp->length, hp->bytes), rz_new_copy(hp->length, hp->mask), hp->length, hp->pattern_desc); diff --git a/librz/search/search_internal.h b/librz/search/search_internal.h index 455ec5286fd..3fbd55b7ba3 100644 --- a/librz/search/search_internal.h +++ b/librz/search/search_internal.h @@ -98,6 +98,13 @@ struct rz_search_collection_t { RzSearchFreeCallback free; ///< Callback used to free the collection. }; +struct rz_search_bytes_pattern_t { + const char *pattern_desc; ///< Pattern description string. + ut8 *bytes; ///< Pattern bytes. + ut8 *mask; ///< Pattern mask (when NULL full match) + size_t length; ///< Pattern & mask length +}; + struct rz_search_opt_t { RzSearchFindOpt *find_opts; size_t max_hits; From 5fb3ca9a07a0f83be57e0a42332f8053c270aa0f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 2 Jan 2025 11:55:03 -0500 Subject: [PATCH 007/157] Use RzBuffer for byte search. --- librz/search/bytes_search.c | 12 +++++++----- librz/search/search.c | 12 +++++------- librz/search/search_internal.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index ee187bb08a4..9dfc31c6b2c 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -190,15 +190,17 @@ static inline bool bytes_pattern_compare_masked(RZ_BORROW RZ_NONNULL const ut8 * return true; } -static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, ut8 *buffer, size_t size, RzThreadQueue *hits) { +static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const RzBuffer *buffer, RzThreadQueue *hits) { if (!fopts) { RZ_LOG_ERROR("bytes_find requires valid find options.\n"); return false; } - RzPVector /**/ *patterns = (RzPVector *)user; + ut64 size = 0; + // Remove const classifier. Because the buffer API is not constified, unfortunately. + const ut8 *raw_buf = rz_buf_get_whole_hot_paths((RzBuffer *)buffer, &size); void **it = NULL; - + RzPVector /**/ *patterns = (RzPVector *)user; rz_pvector_foreach (patterns, it) { RzSearchBytesPattern *hp = (RzSearchBytesPattern *)*it; for (size_t offset = 0; offset < size;) { @@ -207,12 +209,12 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, ut8 *bu break; } if (!hp->mask) { - if (!bytes_pattern_compare_no_mask(buffer + offset, hp)) { + if (!bytes_pattern_compare_no_mask(raw_buf + offset, hp)) { offset++; continue; } } else { - if (!bytes_pattern_compare_masked(buffer + offset, hp)) { + if (!bytes_pattern_compare_masked(raw_buf + offset, hp)) { offset++; continue; } diff --git a/librz/search/search.c b/librz/search/search.c index ae49156080c..bba40c80aaf 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -590,11 +590,9 @@ static bool search_iterator_io_map_cb(void *element, void *user) { ut64 at = window->addr; ut64 size = window->size; - // read the buffer - ut8 *buffer = malloc(size); rz_th_lock_enter(ctx->io_lock); - int read = rz_io_nread_at(ctx->io, at, buffer, size); - if (!buffer || read != size) { + RzBuffer *buffer = rz_io_nread_at_new_buf(ctx->io, at, size); + if (!buffer || rz_buf_size(buffer) != size) { RZ_LOG_ERROR("search: failed to read at 0x%08" PFMT64x " (0x%08" PFMT64x " bytes)\n", at, size); rz_th_lock_leave(ctx->io_lock); goto failure; @@ -602,16 +600,16 @@ static bool search_iterator_io_map_cb(void *element, void *user) { rz_th_lock_leave(ctx->io_lock); RzSearchFindBytesCallback find = col->find; - if (!find(ctx->opt->find_opts, col->user, at, buffer, size, ctx->hits)) { + if (!find(ctx->opt->find_opts, col->user, at, buffer, ctx->hits)) { RZ_LOG_ERROR("search: failed search at 0x%08" PFMT64x "\n", at); goto failure; } - free(buffer); + rz_buf_free(buffer); return rz_atomic_bool_get(ctx->loop); failure: - free(buffer); + rz_buf_free(buffer); rz_atomic_bool_set(ctx->loop, false); return false; } diff --git a/librz/search/search_internal.h b/librz/search/search_internal.h index 3fbd55b7ba3..1319a0a9fba 100644 --- a/librz/search/search_internal.h +++ b/librz/search/search_internal.h @@ -70,7 +70,7 @@ typedef bool (*RzSearchIsEmptyCallback)(void *user); * \return True, if a match was found. * \return False otherwise. */ -typedef bool (*RzSearchFindBytesCallback)(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 address, ut8 *buffer, size_t size, RZ_OUT RzThreadQueue *hits); +typedef bool (*RzSearchFindBytesCallback)(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 address, const RzBuffer *buffer, RZ_OUT RzThreadQueue *hits); /** * \brief A callback to search a graph for a pattern. From edfd934153d6c5025775dc9608440603cfac7461 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 3 Jan 2025 13:26:45 -0500 Subject: [PATCH 008/157] Hex byte search: Add test for search of all file content. --- test/db/cmd/cmd_search_x | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/db/cmd/cmd_search_x b/test/db/cmd/cmd_search_x index f706a8675cf..aa529eb2a78 100644 --- a/test/db/cmd/cmd_search_x +++ b/test/db/cmd/cmd_search_x @@ -66,6 +66,20 @@ EXPECT=< Date: Thu, 2 Jan 2025 14:05:53 -0500 Subject: [PATCH 009/157] Add string search implementation. --- librz/core/cmd/cmd_search.c | 95 +++++++++++++--- librz/core/csearch.c | 78 ++++++++++++- librz/include/rz_core.h | 1 + librz/include/rz_util/rz_str_search.h | 2 +- librz/search/meson.build | 1 + librz/search/string_search.c | 152 ++++++++++++++++++++++++++ 6 files changed, 308 insertions(+), 21 deletions(-) create mode 100644 librz/search/string_search.c diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 72539f08e1d..c2c3cc2ed3c 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -1788,20 +1788,10 @@ RZ_IPI int rz_cmd_search(void *data, const char *input) { return RZ_CMD_STATUS_ERROR; \ } \ rz_cons_break_push(NULL, NULL); \ - RzSearchOpt *search_opts = rz_search_opt_new(); \ - bool opt_applid = rz_search_opt_set_max_hits(search_opts, rz_config_get_i(core->config, "search.maxhits")); \ - opt_applid &= rz_search_opt_set_max_threads(search_opts, rz_th_max_threads(rz_config_get_i(core->config, "search.max_threads"))); \ - RzSearchFindOpt *fopts = rz_core_setup_default_search_find_opts(core); \ - if (!fopts) { \ - RZ_LOG_ERROR("Failed setup find options.\n"); \ - return RZ_CMD_STATUS_ERROR; \ - } \ - rz_search_opt_set_find_options(search_opts, fopts); \ core->in_search = true; #define CMD_SEARCH_END() \ do { \ - rz_search_opt_free(search_opts); \ rz_cons_break_pop(); \ core->in_search = false; \ } while (0) @@ -1973,8 +1963,33 @@ RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const return RZ_CMD_STATUS_NONEXISTINGCMD; } +static RzSearchOpt *setup_search_options(RzCore *core) { + RzSearchOpt *search_opts = rz_search_opt_new(); + if (!(rz_search_opt_set_max_hits(search_opts, rz_config_get_i(core->config, "search.maxhits")) && + rz_search_opt_set_max_threads(search_opts, rz_th_max_threads(rz_config_get_i(core->config, "search.max_threads"))))) { + RZ_LOG_ERROR("Failed setup find options.\n"); + return NULL; + } + + RzSearchFindOpt *fopts = rz_core_setup_default_search_find_opts(core); + if (!fopts) { + RZ_LOG_ERROR("Failed init find options.\n"); + return NULL; + } + if (!rz_search_opt_set_find_options(search_opts, fopts)) { + RZ_LOG_ERROR("Failed add find options to the search optoins.\n"); + return NULL; + } + return search_opts; +} + // "/x" RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + RzSearchOpt *search_opts = setup_search_options(core); + if (!search_opts) { + goto error; + } + CMD_SEARCH_BEGIN(); RzList *hits = NULL; @@ -1986,8 +2001,7 @@ RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char } bool progress = rz_config_get_b(core->config, "search.show_progress"); - opt_applid &= rz_search_opt_set_cancel_cb(search_opts, cmd_search_progress_cancel, progress ? state : NULL); - if (!opt_applid) { + if (!rz_search_opt_set_cancel_cb(search_opts, cmd_search_progress_cancel, progress ? state : NULL)) { RZ_LOG_ERROR("code: Failed to setup default search options.\n"); goto error; } @@ -1998,20 +2012,73 @@ RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char } CMD_SEARCH_END(); + rz_search_opt_free(search_opts); return cmd_core_handle_search_hits(core, state, hits); error: rz_list_free(hits); + rz_search_opt_free(search_opts); CMD_SEARCH_END(); return RZ_CMD_STATUS_ERROR; } +static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, const char *encoding, bool caseless, RzCmdStateOutput *state) { + RzSearchOpt *search_opts = setup_search_options(core); + if (!search_opts) { + return RZ_CMD_STATUS_ERROR; + } + + CMD_SEARCH_BEGIN(); + + RzStrEnc expected = RZ_STRING_ENC_GUESS; + char *search_str = rz_str_dup(string); + if (!RZ_STR_ISEMPTY(search_str)) { + RZ_LOG_ERROR("core: invalid string: empty string.\n"); + free(search_str); + return RZ_CMD_STATUS_WRONG_ARGS; + } + + if (rz_str_unescape(search_str) < 1) { + RZ_LOG_ERROR("core: invalid string: failed to unescape.\n"); + free(search_str); + return RZ_CMD_STATUS_WRONG_ARGS; + } + + if (RZ_STR_ISNOTEMPTY(encoding)) { + expected = rz_str_enc_string_as_type(encoding); + if (expected == RZ_STRING_ENC_GUESS) { + RZ_LOG_ERROR("core: invalid encoding %s.\n", encoding); + free(search_str); + return RZ_CMD_STATUS_WRONG_ARGS; + } + } + + bool progress = rz_config_get_b(core->config, "search.show_progress"); + if (!rz_search_opt_set_cancel_cb(search_opts, cmd_search_progress_cancel, progress ? state : NULL)) { + RZ_LOG_ERROR("code: Failed to setup default search options.\n"); + free(search_str); + rz_search_opt_free(search_opts); + CMD_SEARCH_END(); + return RZ_CMD_STATUS_ERROR; + } + RzList *hits = rz_core_search_string(core, search_opts, search_str, expected, caseless); + free(search_str); + + CMD_SEARCH_END(); + rz_search_opt_free(search_opts); + return cmd_core_handle_search_hits(core, state, hits); +} + // "/z" RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + const char *encoding = argc > 2 ? argv[2] : NULL; + RzCmdStatus res = cmd_string_search_generic(core, argv[1], encoding, false, state); + return res; } // "/zi" RZ_IPI RzCmdStatus rz_cmd_search_string_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + const char *encoding = argc > 2 ? argv[2] : NULL; + RzCmdStatus res = cmd_string_search_generic(core, argv[1], encoding, true, state); + return res; } diff --git a/librz/core/csearch.c b/librz/core/csearch.c index 92892210cbf..cc4f8a05afc 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -2,7 +2,8 @@ // SPDX-FileCopyrightText: 2024 Rot127 // SPDX-License-Identifier: LGPL-3.0-only -#include "rz_config.h" +#include +#include #include #include #include @@ -85,6 +86,18 @@ static bool default_search_no_cancel(void *user, size_t n_hits, RzSearchCancelRe return rz_cons_is_breaked(); } +static RzList *perform_search_on_core_io(RzCore *core, RZ_BORROW RzSearchOpt *search_opts, RZ_BORROW RzList *boundaries, RZ_BORROW RzSearchCollection *collection) { + RzList *hits = NULL; + + hits = rz_search_on_io(search_opts, collection, core->io, boundaries); + if (!hits) { + ut64 from = rz_config_get_i(core->config, "search.from"); + ut64 to = rz_config_get_i(core->config, "search.to"); + RZ_LOG_ERROR("core: Failed to search within [0x%" PFMT64x ", 0x%" PFMT64x "].\n", from, to); + } + return hits; +} + /** * \brief Finds a byte array in the IO layer of the given core and core configuration. * @@ -134,13 +147,66 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore goto quit; } - hits = rz_search_on_io(user_opts ? user_opts : search_opts, collection, core->io, boundaries); - if (!hits) { - ut64 from = rz_config_get_i(core->config, "search.from"); - ut64 to = rz_config_get_i(core->config, "search.to"); - RZ_LOG_ERROR("core: Failed to search within [0x%" PFMT64x ", 0x%" PFMT64x "].\n", from, to); + hits = perform_search_on_core_io(core, user_opts ? user_opts : search_opts, boundaries, collection); + +quit: + rz_list_free(boundaries); + rz_search_opt_free(search_opts); + rz_search_collection_free(collection); + return hits; +} + +/** + * \brief Finds a string within the search.in boundaries. + * + * \param core The RzCore core. + * \param opt The search options to apply. If NULL, a default set of options is used. + * \param[in] string The string to search. + * \param[in] expected The expected encoding. + * \param[in] caseless When true, caseless match. + * + * \return On success returns a valid pointer to a list of search hits, otherwise NULL. + */ +RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *string, RzStrEnc expected, bool caseless) { + rz_return_val_if_fail(core && user_opts && string, NULL); + + if (!RZ_STR_ISEMPTY(string)) { + RZ_LOG_ERROR("core: invalid string: empty string.\n"); + return NULL; } + // Copy RzUtilStrScanOptions from RzBin + RzUtilStrScanOptions scan_opt = { + .buf_size = rz_config_get_i(core->config, "search.buffer_size"), + .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, + .min_str_length = core->bin->str_search_cfg.min_length, + .prefer_big_endian = core->analysis->big_endian, + .check_ascii_freq = core->bin->str_search_cfg.check_ascii_freq, + }; + + RzList *hits = NULL; + RzList *boundaries = NULL; + RzSearchOpt *search_opts = NULL; + + RzSearchCollection *collection = rz_search_collection_strings(&scan_opt, expected, caseless); + if (!collection || + !rz_search_collection_string_add(collection, string)) { + rz_search_collection_free(collection); + RZ_LOG_ERROR("core: Failed to initialize search collection.\n"); + return NULL; + } + boundaries = rz_core_setup_io_search_parameters(core, user_opts ? NULL : search_opts); + if (!boundaries) { + RZ_LOG_ERROR("core: Setting up search from core failed.\n"); + goto quit; + } + if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, strlen(string))) { + RZ_LOG_ERROR("search: Failed to update chunk size in the search options.\n"); + goto quit; + } + + hits = perform_search_on_core_io(core, user_opts ? user_opts : search_opts, boundaries, collection); + quit: rz_list_free(boundaries); rz_search_opt_free(search_opts); diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 590aea83599..01152f1cda7 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -1353,6 +1353,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_setup_io_search_parameters(RzCore RZ_API RZ_OWN RzSearchFindOpt *rz_core_setup_default_search_find_opts(RzCore *core); RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NULLABLE RzSearchOpt *user_opts, RZ_NONNULL RZ_OWN RzSearchBytesPattern *pattern); +RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *string, RzStrEnc expected, bool caseless); #endif diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index 75c0ccc715d..8f0819a8925 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -15,7 +15,7 @@ extern "C" { */ typedef struct { char *string; ///< Pointer to the string - ut64 addr; ///< Address of the string in the RzBuffer + ut64 addr; ///< Address/offset of the string in the RzBuffer ut32 size; ///< Size of buffer containing the string in bytes ut32 length; ///< Length of string in chars RzStrEnc type; ///< String type diff --git a/librz/search/meson.build b/librz/search/meson.build index ce12c18001f..98191cbd131 100644 --- a/librz/search/meson.build +++ b/librz/search/meson.build @@ -7,6 +7,7 @@ rz_search_sources = [ 'collection.c', 'options.c', 'bytes_search.c', + 'string_search.c', ] rz_search = library('rz_search', rz_search_sources, diff --git a/librz/search/string_search.c b/librz/search/string_search.c new file mode 100644 index 00000000000..ddd900569c2 --- /dev/null +++ b/librz/search/string_search.c @@ -0,0 +1,152 @@ +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-FileCopyrightText: 2024 deroad +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include + +#include "rz_util/rz_buf.h" +#include "search_internal.h" + +typedef struct string_search { + RzUtilStrScanOptions options; ///< String scan options + RzStrEnc encoding; ///< Expected encoding + bool caseless; ///< Caseless search. + RzPVector /**/ *strings; ///< Strings to search +} StringSearch; + +static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offset, const RzBuffer *buffer, RZ_OUT RzThreadQueue *hits) { + StringSearch *ss = (StringSearch *)user; + RzDetectedString *detected = NULL; + RzListIter *it_s = NULL; + + RzList *found = rz_list_newf((RzListFree)rz_detected_string_free); + if (!found) { + RZ_LOG_ERROR("search: failed to allocate found list for strings collection\n"); + return false; + } + + ut64 size; + const ut8 *buffer_raw = rz_buf_get_whole_hot_paths((RzBuffer *)buffer, &size); + const ut64 end = offset + size; + if (rz_scan_strings_raw(buffer_raw, found, &ss->options, offset, end, ss->encoding) <= 0) { + rz_list_free(found); + return true; + } + + rz_list_foreach (found, it_s, detected) { + void **it_m = NULL; + rz_pvector_foreach (ss->strings, it_m) { + RzDetectedString *find = *it_m; + if (detected->length < find->length) { + // ignore strings that are smaller than the one we are looking for. + continue; + } + size_t len = RZ_MIN(detected->length, find->length); + if ((ss->caseless && rz_str_ncasecmp(detected->string, find->string, len)) || + (!ss->caseless && strncmp(detected->string, find->string, len))) { + // ignore strings that are not matching till len. + continue; + } + + RzSearchHit *hit = rz_search_hit_new("string", detected->addr, detected->size); + if (!hit || !rz_th_queue_push(hits, hit, true)) { + rz_search_hit_free(hit); + rz_list_free(found); + return false; + } + } + } + + rz_list_free(found); + return true; +} + +static bool string_is_empty(void *user) { + StringSearch *ss = (StringSearch *)user; + return rz_pvector_empty(ss->strings); +} + +static void string_free(void *user) { + if (!user) { + return; + } + StringSearch *ss = (StringSearch *)user; + rz_pvector_free(ss->strings); + free(ss); +} + +/** + * \brief Allocates and initialize a string RzSearchCollection + * + * \param opts The RzUtilStrScanOptions options to use + * \param[in] expected The expected encoding + * \param[in] caseless When true performs a caseless compare + * + * \return On success returns a valid pointer, otherwise NULL + */ +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, bool caseless) { + rz_return_val_if_fail(opts, NULL); + + StringSearch *ss = RZ_NEW0(StringSearch); + if (!ss) { + RZ_LOG_ERROR("search: failed to allocate StringSearch\n"); + return NULL; + } + + ss->strings = rz_pvector_new((RzPVectorFree)rz_detected_string_free); + if (!ss->strings) { + RZ_LOG_ERROR("search: failed to initialize string collection\n"); + string_free(ss); + return NULL; + } + + ss->options = *opts; // copy the values + ss->encoding = expected; + ss->caseless = caseless; + + return rz_search_collection_new_bytes_space(string_find, string_is_empty, string_free, ss); +} + +static RzDetectedString *string_copy(const char *string) { + char *copy = rz_str_dup(string); + if (!copy) { + return NULL; + } + RzDetectedString *ds = RZ_NEW0(RzDetectedString); + if (!ds) { + free(copy); + return NULL; + } + ds->length = strlen(copy); + return ds; +} + +/** + * \brief Adds a new string into a string RzSearchCollection + * + * \param[in] col The RzSearchCollection to use + * \param[in] string The regular expression to add + * + * \return On success returns true, otherwise false + */ +RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *string) { + rz_return_val_if_fail(col && string, false); + + if (!rz_search_collection_has_find_callback(col, string_find)) { + RZ_LOG_ERROR("search: cannot add string to non-string collection\n"); + return false; + } else if (RZ_STR_ISEMPTY(string)) { + RZ_LOG_ERROR("search: cannot add an empty string to a string collection\n"); + return false; + } + StringSearch *ss = (StringSearch *)col->user; + + RzDetectedString *s = string_copy(string); + if (!s || !rz_pvector_push(ss->strings, s)) { + RZ_LOG_ERROR("search: cannot add the string '%s'.\n", string); + rz_detected_string_free(s); + return false; + } + return true; +} From b08ccef5b29dbdc354ca0f9a1a51f77d5f57737d Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 10:22:13 -0500 Subject: [PATCH 010/157] Clean up error handling in cmd_string_search_generic() --- librz/core/cmd/cmd_search.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index c2c3cc2ed3c..3da63e9e4ee 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2032,24 +2032,21 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c RzStrEnc expected = RZ_STRING_ENC_GUESS; char *search_str = rz_str_dup(string); - if (!RZ_STR_ISEMPTY(search_str)) { + if (RZ_STR_ISEMPTY(search_str)) { RZ_LOG_ERROR("core: invalid string: empty string.\n"); - free(search_str); - return RZ_CMD_STATUS_WRONG_ARGS; + goto invalid_args; } if (rz_str_unescape(search_str) < 1) { RZ_LOG_ERROR("core: invalid string: failed to unescape.\n"); - free(search_str); - return RZ_CMD_STATUS_WRONG_ARGS; + goto invalid_args; } if (RZ_STR_ISNOTEMPTY(encoding)) { expected = rz_str_enc_string_as_type(encoding); if (expected == RZ_STRING_ENC_GUESS) { RZ_LOG_ERROR("core: invalid encoding %s.\n", encoding); - free(search_str); - return RZ_CMD_STATUS_WRONG_ARGS; + goto invalid_args; } } @@ -2062,11 +2059,17 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c return RZ_CMD_STATUS_ERROR; } RzList *hits = rz_core_search_string(core, search_opts, search_str, expected, caseless); - free(search_str); - CMD_SEARCH_END(); + free(search_str); rz_search_opt_free(search_opts); + CMD_SEARCH_END(); return cmd_core_handle_search_hits(core, state, hits); + +invalid_args: + free(search_str); + rz_search_opt_free(search_opts); + CMD_SEARCH_END(); + return RZ_CMD_STATUS_WRONG_ARGS; } // "/z" From cc130d590e9685e8bd96a51a043058fc6750181e Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 11:09:43 -0500 Subject: [PATCH 011/157] Add encoding details to help --- librz/core/cmd/cmd_search.c | 2 +- librz/core/cmd_descs/cmd_descs.c | 22 ++++++++++++++++++++ librz/core/cmd_descs/cmd_search.yaml | 30 +++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 3da63e9e4ee..1fe1e1a75ca 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2045,7 +2045,7 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c if (RZ_STR_ISNOTEMPTY(encoding)) { expected = rz_str_enc_string_as_type(encoding); if (expected == RZ_STRING_ENC_GUESS) { - RZ_LOG_ERROR("core: invalid encoding %s.\n", encoding); + RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); goto invalid_args; } } diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 339aec96c46..169610e9db2 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -17,6 +17,7 @@ static const RzCmdDescDetail interpret_macro_multiple_details[2]; static const RzCmdDescDetail cmd_search_hash_block_details[2]; static const RzCmdDescDetail slash_v_details[2]; static const RzCmdDescDetail cmd_search_hex_details[2]; +static const RzCmdDescDetail slash_z_details[2]; static const RzCmdDescDetail base64_encode_details[2]; static const RzCmdDescDetail base64_decode_details[2]; static const RzCmdDescDetail print_boundaries_prot_details[2]; @@ -1721,8 +1722,29 @@ static const RzCmdDescHelp cmd_search_hex_help = { .args = cmd_search_hex_args, }; +static const RzCmdDescDetailEntry slash_z_Encodings_detail_entries[] = { + { .text = "ascii", .arg_str = NULL, .comment = "ASCII encoding" }, + { .text = "8bit", .arg_str = NULL, .comment = "8bit encoding. Alias: ASCII" }, + { .text = "mutf8", .arg_str = NULL, .comment = "mutf8 encoding" }, + { .text = "UTF-8", .arg_str = NULL, .comment = "UTF-8 encoding" }, + { .text = "utf16le", .arg_str = NULL, .comment = "UTF-16 little endian encoding" }, + { .text = "utf32le", .arg_str = NULL, .comment = "UTF-32 little endian encoding" }, + { .text = "utf16be", .arg_str = NULL, .comment = "UTF-16 big endian encoding" }, + { .text = "utf32be", .arg_str = NULL, .comment = "UTF-32 big endian encoding" }, + { .text = "ibm037", .arg_str = NULL, .comment = "ibm037 encoding. Alias: cp037, ebcdic-cp-us, ebcdic-cp-ca, ebcdic-cp-wt, ebcdic-cp-nl, csIBM037" }, + { .text = "ibm290", .arg_str = NULL, .comment = "ibm290 encoding. Alias: cp290, EBCDIC-JP-kana, csIBM290" }, + { .text = "ebcdices", .arg_str = NULL, .comment = "EBCDIC-ES encoding. Alias: csEBCDICES" }, + { .text = "ebcdicuk", .arg_str = NULL, .comment = "EBCDIC-UK encoding. Alias: csEBCDICUK" }, + { .text = "ebcdicus", .arg_str = NULL, .comment = "EBCDIC-US encoding. Alias: csEBCDICUS" }, + { 0 }, +}; +static const RzCmdDescDetail slash_z_details[] = { + { .name = "Encodings", .entries = slash_z_Encodings_detail_entries }, + { 0 }, +}; static const RzCmdDescHelp slash_z_help = { .summary = "String search.", + .details = slash_z_details, }; static const char *cmd_search_string_sensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; static const RzCmdDescArg cmd_search_string_sensitive_args[] = { diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index a6f647b56a1..b66933a93f6 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -314,6 +314,35 @@ commands: comment: "/x ffd0:ff43" - name: "/z" summary: String search. + details: + - name: "Encodings" + entries: + - text: "ascii" + comment: "ASCII encoding" + - text: "8bit" + comment: "8bit encoding. Alias: ASCII" + - text: "mutf8" + comment: "mutf8 encoding" + - text: "UTF-8" + comment: "UTF-8 encoding" + - text: "utf16le" + comment: "UTF-16 little endian encoding" + - text: "utf32le" + comment: "UTF-32 little endian encoding" + - text: "utf16be" + comment: "UTF-16 big endian encoding" + - text: "utf32be" + comment: "UTF-32 big endian encoding" + - text: "ibm037" + comment: "ibm037 encoding. Alias: cp037, ebcdic-cp-us, ebcdic-cp-ca, ebcdic-cp-wt, ebcdic-cp-nl, csIBM037" + - text: "ibm290" + comment: "ibm290 encoding. Alias: cp290, EBCDIC-JP-kana, csIBM290" + - text: "ebcdices" + comment: "EBCDIC-ES encoding. Alias: csEBCDICES" + - text: "ebcdicuk" + comment: "EBCDIC-UK encoding. Alias: csEBCDICUK" + - text: "ebcdicus" + comment: "EBCDIC-US encoding. Alias: csEBCDICUS" subcommands: - name: "/z" summary: String search (case-sensitive). @@ -345,7 +374,6 @@ commands: - "ebcdices" - "ebcdicuk" - "ebcdicus" - - name: "/zi" summary: String search (case-insensitive). cname: cmd_search_string_insensitive From 3a195ed941ac7022e5f1df16348f207a14edc3a3 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 12:12:34 -0500 Subject: [PATCH 012/157] Make the default encoding value 'guess' --- librz/core/cmd/cmd_search.c | 20 ++++++++++---------- librz/core/cmd_descs/cmd_descs.c | 4 ++-- librz/core/cmd_descs/cmd_search.yaml | 4 ++-- librz/util/str.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 1fe1e1a75ca..b51c174da7e 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2036,18 +2036,20 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c RZ_LOG_ERROR("core: invalid string: empty string.\n"); goto invalid_args; } + if (RZ_STR_ISEMPTY(encoding)) { + RZ_LOG_ERROR("core: invalid encoding: empty encoding.\n"); + goto invalid_args; + } if (rz_str_unescape(search_str) < 1) { RZ_LOG_ERROR("core: invalid string: failed to unescape.\n"); goto invalid_args; } - if (RZ_STR_ISNOTEMPTY(encoding)) { - expected = rz_str_enc_string_as_type(encoding); - if (expected == RZ_STRING_ENC_GUESS) { - RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); - goto invalid_args; - } + expected = rz_str_enc_string_as_type(encoding); + if (!RZ_STR_EQ(encoding, "guess") && expected == RZ_STRING_ENC_GUESS) { + RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); + goto invalid_args; } bool progress = rz_config_get_b(core->config, "search.show_progress"); @@ -2074,14 +2076,12 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c // "/z" RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - const char *encoding = argc > 2 ? argv[2] : NULL; - RzCmdStatus res = cmd_string_search_generic(core, argv[1], encoding, false, state); + RzCmdStatus res = cmd_string_search_generic(core, argv[1], argv[2], false, state); return res; } // "/zi" RZ_IPI RzCmdStatus rz_cmd_search_string_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - const char *encoding = argc > 2 ? argv[2] : NULL; - RzCmdStatus res = cmd_string_search_generic(core, argv[1], encoding, true, state); + RzCmdStatus res = cmd_string_search_generic(core, argv[1], argv[2], true, state); return res; } diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 169610e9db2..18b5ed44848 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -1756,7 +1756,7 @@ static const RzCmdDescArg cmd_search_string_sensitive_args[] = { { .name = "encoding", .type = RZ_CMD_ARG_TYPE_CHOICES, - .optional = true, + .default_value = "guess", .choices.choices = cmd_search_string_sensitive_encoding_choices, }, @@ -1777,7 +1777,7 @@ static const RzCmdDescArg cmd_search_string_insensitive_args[] = { { .name = "encoding", .type = RZ_CMD_ARG_TYPE_CHOICES, - .optional = true, + .default_value = "guess", .choices.choices = cmd_search_string_insensitive_encoding_choices, }, diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index b66933a93f6..018b6c6e13c 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -359,7 +359,7 @@ commands: type: RZ_CMD_ARG_TYPE_STRING - name: encoding type: RZ_CMD_ARG_TYPE_CHOICES - optional: true + default_value: "guess" choices: - "ascii" - "8bit" @@ -389,7 +389,7 @@ commands: type: RZ_CMD_ARG_TYPE_STRING - name: encoding type: RZ_CMD_ARG_TYPE_CHOICES - optional: true + default_value: "guess" choices: - "ascii" - "8bit" diff --git a/librz/util/str.c b/librz/util/str.c index 36a9c8292dc..5a891478aa9 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -115,7 +115,7 @@ RZ_API RzStrEnc rz_str_enc_string_as_type(RZ_NULLABLE const char *encoding) { return RZ_STRING_ENC_BASE64; } - RZ_LOG_ERROR("rz_str: encoding %s not supported\n", encoding); + RZ_LOG_ERROR("rz_str: encoding '%s' not supported\n", encoding); return RZ_STRING_ENC_GUESS; } From 28999d4e5b08d9aa0ab1e787e87113124cbb949b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 12:27:13 -0500 Subject: [PATCH 013/157] Replace if with switch --- librz/util/str_search.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 95ba54d36cb..91ee6215b48 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -215,41 +215,52 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 for (i = 0; i < opt->buf_size - 4 && needle < to; i += rc) { RzCodePoint r = 0; - if (str_type == RZ_STRING_ENC_UTF32LE) { + switch(str_type) { + case RZ_STRING_ENC_UTF32LE: rc = rz_utf32le_decode(buf + needle - from, to - needle, &r); if (rc) { rc = 4; } - } else if (str_type == RZ_STRING_ENC_UTF16LE) { + break; + case RZ_STRING_ENC_UTF16LE: rc = rz_utf16le_decode(buf + needle - from, to - needle, &r); if (rc == 1) { rc = 2; } - } else if (str_type == RZ_STRING_ENC_UTF32BE) { + break; + case RZ_STRING_ENC_UTF32BE: rc = rz_utf32be_decode(buf + needle - from, to - needle, &r); if (rc) { rc = 4; } - } else if (str_type == RZ_STRING_ENC_UTF16BE) { + break; + case RZ_STRING_ENC_UTF16BE: rc = rz_utf16be_decode(buf + needle - from, to - needle, &r); if (rc == 1) { rc = 2; } - } else if (str_type == RZ_STRING_ENC_IBM037) { + break; + case RZ_STRING_ENC_IBM037: rc = rz_str_ibm037_to_unicode(*(buf + needle - from), &r); - } else if (str_type == RZ_STRING_ENC_IBM290) { + break; + case RZ_STRING_ENC_IBM290: rc = rz_str_ibm290_to_unicode(*(buf + needle - from), &r); - } else if (str_type == RZ_STRING_ENC_EBCDIC_ES) { + break; + case RZ_STRING_ENC_EBCDIC_ES: rc = rz_str_ebcdic_es_to_unicode(*(buf + needle - from), &r); - } else if (str_type == RZ_STRING_ENC_EBCDIC_UK) { + break; + case RZ_STRING_ENC_EBCDIC_UK: rc = rz_str_ebcdic_uk_to_unicode(*(buf + needle - from), &r); - } else if (str_type == RZ_STRING_ENC_EBCDIC_US) { + break; + case RZ_STRING_ENC_EBCDIC_US: rc = rz_str_ebcdic_us_to_unicode(*(buf + needle - from), &r); - } else { + break; + default: rc = rz_utf8_decode(buf + needle - from, to - needle, &r); if (rc > 1) { str_type = RZ_STRING_ENC_UTF8; } + break; } /* Invalid sequence detected */ From e168f6d42580b782bd6d5a4b46d74fb09c88c508 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 13:59:14 -0500 Subject: [PATCH 014/157] Fix some logic bugs --- librz/core/csearch.c | 4 ++-- librz/search/string_search.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/librz/core/csearch.c b/librz/core/csearch.c index cc4f8a05afc..69cf8bfa17d 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -170,14 +170,14 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *string, RzStrEnc expected, bool caseless) { rz_return_val_if_fail(core && user_opts && string, NULL); - if (!RZ_STR_ISEMPTY(string)) { + if (RZ_STR_ISEMPTY(string)) { RZ_LOG_ERROR("core: invalid string: empty string.\n"); return NULL; } // Copy RzUtilStrScanOptions from RzBin RzUtilStrScanOptions scan_opt = { - .buf_size = rz_config_get_i(core->config, "search.buffer_size"), + .buf_size = strlen(string), .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, .min_str_length = core->bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, diff --git a/librz/search/string_search.c b/librz/search/string_search.c index ddd900569c2..a7bd5a7b4c9 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -118,6 +118,7 @@ static RzDetectedString *string_copy(const char *string) { free(copy); return NULL; } + ds->string = copy; ds->length = strlen(copy); return ds; } From 4a1dbc4f338ea1da6d5f24d70e0e198a53a55746 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 15:14:51 -0500 Subject: [PATCH 015/157] Make an assumption in process_one_string explicit. --- librz/util/str_search.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 91ee6215b48..8877973c01a 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -207,6 +207,10 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 RzStrEnc str_type, bool ascii_only, const RzUtilStrScanOptions *opt, ut8 *strbuf) { rz_return_val_if_fail(str_type != RZ_STRING_ENC_GUESS, NULL); + if (opt->buf_size < 5) { + RZ_LOG_ERROR("This function assumes a buffer size of at least 5 bytes."); + return NULL; + } ut64 str_addr = needle; int rc = 0, i = 0, runes = 0; From cbfd30c87727e1f804cce2b1b846d36e425bf0a3 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 15:16:29 -0500 Subject: [PATCH 016/157] Add string scan function using the whole buffer. --- librz/include/rz_util/rz_str_search.h | 1 + librz/util/str_search.c | 29 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index 8f0819a8925..9bf1d482abd 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -39,6 +39,7 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /**/ *list, RZ_NONNULL const RzUtilStrScanOptions *opt, const ut64 from, const ut64 to, RzStrEnc type); +RZ_API int rz_scan_strings_whole_buf(RZ_NONNULL const RzBuffer *buf_to_scan, RZ_NONNULL RzList /**/ *list, RZ_NONNULL const RzUtilStrScanOptions *opt, RzStrEnc type); #ifdef __cplusplus } diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 8877973c01a..ddbec5bf747 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -551,6 +551,7 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /**/ *list, RZ_NONNULL const RzUtilStrScanOptions *opt, RzStrEnc type) { + rz_return_val_if_fail(opt && list && buf_to_scan, -1); + if (type == RZ_STRING_ENC_MUTF8 || type == RZ_STRING_ENC_BASE64) { + RZ_LOG_ERROR("rz_scan_strings_whole_buf: '%s' search type is not supported.\n", rz_str_enc_as_string(type)); + return -1; + } + + ut64 size; + const ut8 *raw_buf = rz_buf_get_whole_hot_paths((RzBuffer *) buf_to_scan, &size); + if (!raw_buf) { + RZ_LOG_ERROR("Failed to get whole buffer."); + return -1; + } + int count = rz_scan_strings_raw(raw_buf, list, opt, 0, size, type); + return count; +} From 0852426ebb7d82aea9cf5f6e59e766ddd2f78f1e Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 15:23:33 -0500 Subject: [PATCH 017/157] Use rz_scan_strings_whole_buf() instead of other scan methods. --- librz/core/csearch.c | 3 ++- librz/search/string_search.c | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/librz/core/csearch.c b/librz/core/csearch.c index 69cf8bfa17d..bf6a7335562 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -177,7 +177,8 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor // Copy RzUtilStrScanOptions from RzBin RzUtilStrScanOptions scan_opt = { - .buf_size = strlen(string), + // This value is irrelevant in our case. Because we read the whole buffer. + .buf_size = 999, .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, .min_str_length = core->bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, diff --git a/librz/search/string_search.c b/librz/search/string_search.c index a7bd5a7b4c9..a2ffada780b 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -26,12 +26,11 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs return false; } - ut64 size; - const ut8 *buffer_raw = rz_buf_get_whole_hot_paths((RzBuffer *)buffer, &size); - const ut64 end = offset + size; - if (rz_scan_strings_raw(buffer_raw, found, &ss->options, offset, end, ss->encoding) <= 0) { + int n_str_in_buf = rz_scan_strings_whole_buf(buffer, found, &ss->options, ss->encoding); + if (n_str_in_buf < 0) { + RZ_LOG_ERROR("Failed to scan buffer for strings.\n"); rz_list_free(found); - return true; + return false; } rz_list_foreach (found, it_s, detected) { From 656a486fc1773aac6ee36c027e9c36a672b0ca9f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 4 Jan 2025 15:49:31 -0500 Subject: [PATCH 018/157] Move the strbuf buffer into the function to reduce complexity. --- librz/core/csearch.c | 5 +++-- librz/util/str_search.c | 34 ++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/librz/core/csearch.c b/librz/core/csearch.c index bf6a7335562..60074d254e5 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -177,8 +177,9 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor // Copy RzUtilStrScanOptions from RzBin RzUtilStrScanOptions scan_opt = { - // This value is irrelevant in our case. Because we read the whole buffer. - .buf_size = 999, + // This value is effectively the maximum string length. + // Gets removed with the refactor. + .buf_size = RZ_BIN_STRING_SEARCH_BUFFER_SIZE, .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, .min_str_length = core->bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, diff --git a/librz/util/str_search.c b/librz/util/str_search.c index ddbec5bf747..e3fde604ebe 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -204,14 +204,18 @@ static ut64 adjust_offset(RzStrEnc str_type, const ut8 *buf, const ut64 str_star } static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut64 needle, const ut64 to, - RzStrEnc str_type, bool ascii_only, const RzUtilStrScanOptions *opt, ut8 *strbuf) { - + RzStrEnc str_type, bool ascii_only, const RzUtilStrScanOptions *opt) { rz_return_val_if_fail(str_type != RZ_STRING_ENC_GUESS, NULL); if (opt->buf_size < 5) { RZ_LOG_ERROR("This function assumes a buffer size of at least 5 bytes."); return NULL; } + ut8 *strbuf = RZ_NEWS0(ut8, opt->buf_size); + if (!strbuf) { + goto error; + } + ut64 str_addr = needle; int rc = 0, i = 0, runes = 0; @@ -301,14 +305,15 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 if (runes >= opt->min_str_length) { FalsePositiveResult false_positive_result = reduce_false_positives(opt, strbuf, strbuf_size, str_type); if (false_positive_result == SKIP_STRING) { - return NULL; + goto error; } else if (false_positive_result == RETRY_ASCII) { - return process_one_string(buf, from, str_addr, to, str_type, true, opt, strbuf); + free(strbuf); + return process_one_string(buf, from, str_addr, to, str_type, true, opt); } RzDetectedString *ds = RZ_NEW0(RzDetectedString); if (!ds) { - return NULL; + goto error; } ds->type = str_type; ds->length = runes; @@ -320,9 +325,12 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 ds->size += off_adj; ds->string = rz_str_ndup((const char *)strbuf, strbuf_size); + free(strbuf); return ds; } +error: + free(strbuf); return NULL; } @@ -415,11 +423,6 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /*buf_size, 1); - if (!strbuf) { - return -1; - } - needle = from; const ut8 *ptr = NULL; ut64 size = 0; @@ -436,8 +439,8 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 3 && can_be_utf32_le(ptr + 3, size - 3)) { // The string can be either utf32-le or utf32-be - RzDetectedString *ds_le = process_one_string(buf, from, needle + 3, to, RZ_STRING_ENC_UTF32LE, false, opt, strbuf); - RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF32BE, false, opt, strbuf); + RzDetectedString *ds_le = process_one_string(buf, from, needle + 3, to, RZ_STRING_ENC_UTF32LE, false, opt); + RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF32BE, false, opt); RzDetectedString *to_add = NULL; RzDetectedString *to_delete = NULL; @@ -472,8 +475,8 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 1 && can_be_utf16_le(ptr + 1, size - 1)) { // The string can be either utf16-le or utf16-be - RzDetectedString *ds_le = process_one_string(buf, from, needle + 1, to, RZ_STRING_ENC_UTF16LE, false, opt, strbuf); - RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF16BE, false, opt, strbuf); + RzDetectedString *ds_le = process_one_string(buf, from, needle + 1, to, RZ_STRING_ENC_UTF16LE, false, opt); + RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF16BE, false, opt); RzDetectedString *to_add = NULL; RzDetectedString *to_delete = NULL; @@ -535,7 +538,7 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /*size; } - free(strbuf); return count; } From e81384a27d62849eea8c0b16dbe224ab73b84fd6 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 20 Jan 2025 11:46:46 -0500 Subject: [PATCH 019/157] Fix types and includes. --- librz/core/csearch.c | 3 ++- librz/search/string_search.c | 8 +++----- librz/util/str_search.c | 7 ++++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/librz/core/csearch.c b/librz/core/csearch.c index 60074d254e5..a3e7bad5e60 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -2,6 +2,7 @@ // SPDX-FileCopyrightText: 2024 Rot127 // SPDX-License-Identifier: LGPL-3.0-only +#include #include #include #include @@ -157,7 +158,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore } /** - * \brief Finds a string within the search.in boundaries. + * \brief Finds a string within the `search.in` boundaries. * * \param core The RzCore core. * \param opt The search options to apply. If NULL, a default set of options is used. diff --git a/librz/search/string_search.c b/librz/search/string_search.c index a2ffada780b..d8e07537ec0 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -4,8 +4,6 @@ #include #include - -#include "rz_util/rz_buf.h" #include "search_internal.h" typedef struct string_search { @@ -38,13 +36,13 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs rz_pvector_foreach (ss->strings, it_m) { RzDetectedString *find = *it_m; if (detected->length < find->length) { - // ignore strings that are smaller than the one we are looking for. + // Ignore strings that are smaller than the one we are looking for. continue; } size_t len = RZ_MIN(detected->length, find->length); if ((ss->caseless && rz_str_ncasecmp(detected->string, find->string, len)) || (!ss->caseless && strncmp(detected->string, find->string, len))) { - // ignore strings that are not matching till len. + // Ignore strings that are not matching till len. continue; } @@ -100,7 +98,7 @@ RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtil return NULL; } - ss->options = *opts; // copy the values + ss->options = *opts; // Copy the values ss->encoding = expected; ss->caseless = caseless; diff --git a/librz/util/str_search.c b/librz/util/str_search.c index e3fde604ebe..2c6325593f4 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2021 borzacchiello // SPDX-License-Identifier: LGPL-3.0-only +#include #include #include #include @@ -598,12 +599,12 @@ RZ_API int rz_scan_strings(RZ_NONNULL RzBuffer *buf_to_scan, RZ_NONNULL RzList / * \brief Look for strings in an RzBuffer. The whole buffer is scanned. * This function is suited for usage on hot paths. * - * \param buf_to_scan Pointer to a RzBuffer to scan. + * \param buf_to_scan Pointer to an RzBuffer to scan. * \param list Pointer to a list that will be populated with the found strings - * \param opt Pointer to a RzUtilStrScanOptions that specifies search parameters + * \param opt Pointer to an RzUtilStrScanOptions that specifies search parameters * \param type Type of strings to search * - * \return Number of strings found or -1 in case of faliure. + * \return Number of strings found or -1 in case of failure. */ RZ_API int rz_scan_strings_whole_buf(RZ_NONNULL const RzBuffer *buf_to_scan, RZ_NONNULL RzList /**/ *list, RZ_NONNULL const RzUtilStrScanOptions *opt, RzStrEnc type) { rz_return_val_if_fail(opt && list && buf_to_scan, -1); From 27967668133e59bcbe05017b1a13123d747e0c69 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 20 Jan 2025 14:35:08 -0500 Subject: [PATCH 020/157] Base string search on regex expressions. --- librz/core/cmd/cmd_search.c | 52 +++++++++++++---- librz/core/cmd_descs/cmd_descs.c | 45 ++++++--------- librz/core/cmd_descs/cmd_descs.h | 2 - librz/core/cmd_descs/cmd_search.yaml | 45 +++++---------- librz/core/csearch.c | 33 ++++++----- librz/include/rz_core.h | 2 +- librz/include/rz_search.h | 4 +- librz/include/rz_util/rz_str_search.h | 4 +- librz/search/string_search.c | 82 +++++++++++++++------------ librz/util/str_search.c | 4 +- 10 files changed, 150 insertions(+), 123 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index b51c174da7e..4684b41b6cb 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -12,6 +12,7 @@ #include "cmd_search_rop.c" #include "rz_cons.h" +#include #include #include #include @@ -2022,7 +2023,7 @@ RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char return RZ_CMD_STATUS_ERROR; } -static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, const char *encoding, bool caseless, RzCmdStateOutput *state) { +static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, const char *encoding, RzRegexFlags flags, RzCmdStateOutput *state) { RzSearchOpt *search_opts = setup_search_options(core); if (!search_opts) { return RZ_CMD_STATUS_ERROR; @@ -2060,7 +2061,7 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c CMD_SEARCH_END(); return RZ_CMD_STATUS_ERROR; } - RzList *hits = rz_core_search_string(core, search_opts, search_str, expected, caseless); + RzList *hits = rz_core_search_string(core, search_opts, search_str, flags, expected); free(search_str); rz_search_opt_free(search_opts); @@ -2071,17 +2072,48 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c free(search_str); rz_search_opt_free(search_opts); CMD_SEARCH_END(); - return RZ_CMD_STATUS_WRONG_ARGS; + return RZ_CMD_STATUS_ERROR; } -// "/z" -RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzCmdStatus res = cmd_string_search_generic(core, argv[1], argv[2], false, state); - return res; +static RzRegexFlags parse_re_flag_desc(const char *re_flags_desc) { + RzRegexFlags flags = RZ_REGEX_DEFAULT; + if (RZ_STR_ISEMPTY(re_flags_desc)) { + return flags; + } + size_t fcount = 0; + if (strchr(re_flags_desc, 'd')) { + fcount++; + flags |= RZ_REGEX_CASELESS; + } + if (strchr(re_flags_desc, 'i')) { + fcount++; + flags |= RZ_REGEX_CASELESS; + } + if (strchr(re_flags_desc, 'e')) { + fcount++; + flags |= RZ_REGEX_EXTENDED; + } + if (strchr(re_flags_desc, 'E')) { + fcount++; + flags |= RZ_REGEX_EXTENDED_MORE; + } + if (strchr(re_flags_desc, 'm')) { + fcount++; + flags |= RZ_REGEX_MULTILINE; + } + if (fcount != strlen(re_flags_desc)) { + return ~RZ_REGEX_DEFAULT; + } + return flags; } -// "/zi" -RZ_IPI RzCmdStatus rz_cmd_search_string_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzCmdStatus res = cmd_string_search_generic(core, argv[1], argv[2], true, state); +// "/z" +RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + RzRegexFlags flags = parse_re_flag_desc(argv[2]); + if (flags == ~RZ_REGEX_DEFAULT) { + RZ_LOG_ERROR("Regex flags are invalid: '%s'\n", argv[2]); + return RZ_CMD_STATUS_ERROR; + } + RzCmdStatus res = cmd_string_search_generic(core, argv[1], argv[3], flags, state); return res; } diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 18b5ed44848..574036d78b6 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -17,7 +17,7 @@ static const RzCmdDescDetail interpret_macro_multiple_details[2]; static const RzCmdDescDetail cmd_search_hash_block_details[2]; static const RzCmdDescDetail slash_v_details[2]; static const RzCmdDescDetail cmd_search_hex_details[2]; -static const RzCmdDescDetail slash_z_details[2]; +static const RzCmdDescDetail slash_z_details[3]; static const RzCmdDescDetail base64_encode_details[2]; static const RzCmdDescDetail base64_decode_details[2]; static const RzCmdDescDetail print_boundaries_prot_details[2]; @@ -126,8 +126,7 @@ static const RzCmdDescArg cmd_search_value_16_args[2]; static const RzCmdDescArg cmd_search_value_32_args[2]; static const RzCmdDescArg cmd_search_value_64_args[2]; static const RzCmdDescArg cmd_search_hex_args[2]; -static const RzCmdDescArg cmd_search_string_sensitive_args[3]; -static const RzCmdDescArg cmd_search_string_insensitive_args[3]; +static const RzCmdDescArg cmd_search_string_sensitive_args[4]; static const RzCmdDescArg remote_args[3]; static const RzCmdDescArg remote_send_args[3]; static const RzCmdDescArg remote_add_args[2]; @@ -1738,8 +1737,18 @@ static const RzCmdDescDetailEntry slash_z_Encodings_detail_entries[] = { { .text = "ebcdicus", .arg_str = NULL, .comment = "EBCDIC-US encoding. Alias: csEBCDICUS" }, { 0 }, }; + +static const RzCmdDescDetailEntry slash_z_Regex_space_Flags_detail_entries[] = { + { .text = "d", .arg_str = NULL, .comment = "Default (No flag, Unicode is matched)" }, + { .text = "i", .arg_str = NULL, .comment = "Caseless (equivalent: PCRE2_CASELESS)" }, + { .text = "e", .arg_str = NULL, .comment = "Extended (equivalent: PCRE2_EXTENDED)" }, + { .text = "E", .arg_str = NULL, .comment = "Extended More (equivalent: PCRE2_EXTENDED_MORE)" }, + { .text = "m", .arg_str = NULL, .comment = "Multiline (equivalent: PCRE2_MULTILINE)" }, + { 0 }, +}; static const RzCmdDescDetail slash_z_details[] = { { .name = "Encodings", .entries = slash_z_Encodings_detail_entries }, + { .name = "Regex Flags", .entries = slash_z_Regex_space_Flags_detail_entries }, { 0 }, }; static const RzCmdDescHelp slash_z_help = { @@ -1754,38 +1763,23 @@ static const RzCmdDescArg cmd_search_string_sensitive_args[] = { }, { - .name = "encoding", - .type = RZ_CMD_ARG_TYPE_CHOICES, - .default_value = "guess", - .choices.choices = cmd_search_string_sensitive_encoding_choices, - - }, - { 0 }, -}; -static const RzCmdDescHelp cmd_search_string_sensitive_help = { - .summary = "String search (case-sensitive).", - .args = cmd_search_string_sensitive_args, -}; - -static const char *cmd_search_string_insensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; -static const RzCmdDescArg cmd_search_string_insensitive_args[] = { - { - .name = "string", + .name = "regex_flags", .type = RZ_CMD_ARG_TYPE_STRING, + .default_value = "d", }, { .name = "encoding", .type = RZ_CMD_ARG_TYPE_CHOICES, .default_value = "guess", - .choices.choices = cmd_search_string_insensitive_encoding_choices, + .choices.choices = cmd_search_string_sensitive_encoding_choices, }, { 0 }, }; -static const RzCmdDescHelp cmd_search_string_insensitive_help = { - .summary = "String search (case-insensitive).", - .args = cmd_search_string_insensitive_args, +static const RzCmdDescHelp cmd_search_string_sensitive_help = { + .summary = "String search.", + .args = cmd_search_string_sensitive_args, }; static const RzCmdDescHelp R_help = { @@ -20242,9 +20236,6 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *slash_z_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/z", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_string_sensitive_handler, &cmd_search_string_sensitive_help, &slash_z_help); rz_warn_if_fail(slash_z_cd); rz_cmd_desc_set_default_mode(slash_z_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *cmd_search_string_insensitive_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_z_cd, "/zi", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_string_insensitive_handler, &cmd_search_string_insensitive_help); - rz_warn_if_fail(cmd_search_string_insensitive_cd); - rz_cmd_desc_set_default_mode(cmd_search_string_insensitive_cd, RZ_OUTPUT_MODE_STANDARD); RzCmdDesc *R_cd = rz_cmd_desc_group_new(core->rcmd, root_cd, "R", rz_remote_handler, &remote_help, &R_help); rz_warn_if_fail(R_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 6183ebcbb88..2f77bd6592b 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -103,8 +103,6 @@ RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/z" RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); -// "/zi" -RZ_IPI RzCmdStatus rz_cmd_search_string_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "R" RZ_IPI RzCmdStatus rz_remote_handler(RzCore *core, int argc, const char **argv); // "R<" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 018b6c6e13c..797c6bd589e 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -343,9 +343,21 @@ commands: comment: "EBCDIC-UK encoding. Alias: csEBCDICUK" - text: "ebcdicus" comment: "EBCDIC-US encoding. Alias: csEBCDICUS" + - name: "Regex Flags" + entries: + - text: "d" + comment: "Default (No flag, Unicode is matched)" + - text: "i" + comment: "Caseless (equivalent: PCRE2_CASELESS)" + - text: "e" + comment: "Extended (equivalent: PCRE2_EXTENDED)" + - text: "E" + comment: "Extended More (equivalent: PCRE2_EXTENDED_MORE)" + - text: "m" + comment: "Multiline (equivalent: PCRE2_MULTILINE)" subcommands: - name: "/z" - summary: String search (case-sensitive). + summary: String search. cname: cmd_search_string_sensitive type: RZ_CMD_DESC_TYPE_ARGV_STATE default_mode: RZ_OUTPUT_MODE_STANDARD @@ -357,36 +369,9 @@ commands: args: - name: string type: RZ_CMD_ARG_TYPE_STRING - - name: encoding - type: RZ_CMD_ARG_TYPE_CHOICES - default_value: "guess" - choices: - - "ascii" - - "8bit" - - "mutf8" - - "utf8" - - "utf16le" - - "utf32le" - - "utf16be" - - "utf32be" - - "ibm037" - - "ibm290" - - "ebcdices" - - "ebcdicuk" - - "ebcdicus" - - name: "/zi" - summary: String search (case-insensitive). - cname: cmd_search_string_insensitive - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE - args: - - name: string + - name: regex_flags type: RZ_CMD_ARG_TYPE_STRING + default_value: "d" - name: encoding type: RZ_CMD_ARG_TYPE_CHOICES default_value: "guess" diff --git a/librz/core/csearch.c b/librz/core/csearch.c index a3e7bad5e60..0e8900cefd1 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -160,27 +161,31 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore /** * \brief Finds a string within the `search.in` boundaries. * - * \param core The RzCore core. - * \param opt The search options to apply. If NULL, a default set of options is used. - * \param[in] string The string to search. - * \param[in] expected The expected encoding. - * \param[in] caseless When true, caseless match. + * \param core The RzCore core. + * \param opt The search options to apply. If NULL, a default set of options is used. + * \param[in] re_pattern The regex pattern to search. + * \param[in] flags The regex flags to the \p re_pattern. + * \param[in] expected The expected encoding. * * \return On success returns a valid pointer to a list of search hits, otherwise NULL. */ -RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *string, RzStrEnc expected, bool caseless) { - rz_return_val_if_fail(core && user_opts && string, NULL); +RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *re_pattern, RzRegexFlags flags, RzStrEnc expected) { + rz_return_val_if_fail(core && user_opts && re_pattern, NULL); - if (RZ_STR_ISEMPTY(string)) { + if (RZ_STR_ISEMPTY(re_pattern)) { RZ_LOG_ERROR("core: invalid string: empty string.\n"); return NULL; } + if (strlen(re_pattern) >= core->bin->str_search_cfg.buffer_size) { + RZ_LOG_ERROR("core: String to search is larger then str.search.buffer_size.\n"); + return NULL; + } // Copy RzUtilStrScanOptions from RzBin RzUtilStrScanOptions scan_opt = { - // This value is effectively the maximum string length. - // Gets removed with the refactor. - .buf_size = RZ_BIN_STRING_SEARCH_BUFFER_SIZE, + // buf_size is effectively the maximum string length. + // Gets renamed with the refactor. + .buf_size = core->bin->str_search_cfg.buffer_size, .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, .min_str_length = core->bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, @@ -191,9 +196,9 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor RzList *boundaries = NULL; RzSearchOpt *search_opts = NULL; - RzSearchCollection *collection = rz_search_collection_strings(&scan_opt, expected, caseless); + RzSearchCollection *collection = rz_search_collection_strings(&scan_opt, expected, flags); if (!collection || - !rz_search_collection_string_add(collection, string)) { + !rz_search_collection_string_add(collection, re_pattern, flags)) { rz_search_collection_free(collection); RZ_LOG_ERROR("core: Failed to initialize search collection.\n"); return NULL; @@ -203,7 +208,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor RZ_LOG_ERROR("core: Setting up search from core failed.\n"); goto quit; } - if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, strlen(string))) { + if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, scan_opt.buf_size)) { RZ_LOG_ERROR("search: Failed to update chunk size in the search options.\n"); goto quit; } diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 01152f1cda7..f75b3f320e1 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -1353,7 +1353,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_setup_io_search_parameters(RzCore RZ_API RZ_OWN RzSearchFindOpt *rz_core_setup_default_search_find_opts(RzCore *core); RZ_API RZ_OWN RzList /**/ *rz_core_search_bytes(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NULLABLE RzSearchOpt *user_opts, RZ_NONNULL RZ_OWN RzSearchBytesPattern *pattern); -RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *string, RzStrEnc expected, bool caseless); +RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCore *core, RZ_BORROW RZ_NONNULL RzSearchOpt *user_opts, RZ_NONNULL const char *string, RzRegexFlags flags, RzStrEnc expected); #endif diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index 505a88e248d..c1e22dbf228 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -199,8 +199,8 @@ RZ_API RZ_OWN RzSearchCollection *rz_search_collection_bytes(); RZ_API bool rz_search_collection_bytes_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *metadata, RZ_NONNULL const ut8 *bytes, RZ_NULLABLE const ut8 *mask, size_t length); RZ_API bool rz_search_collection_bytes_add_pattern(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL RZ_OWN RzSearchBytesPattern *bytes_pattern); -RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, bool caseless); -RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *string); +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, RzRegexFlags re_flags); +RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *regex_pattern, RzRegexFlags re_flags); RZ_API RZ_OWN RzSearchCollection *rz_search_collection_magic(RZ_NONNULL const char *magic_dir); diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index 9bf1d482abd..b63bf043356 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -14,7 +15,8 @@ extern "C" { * Represent a detected string. */ typedef struct { - char *string; ///< Pointer to the string + char *string; ///< Pointer to the string. + RzRegex *regex; ///< Regex matching the string. If set, the string member is the pattern. ut64 addr; ///< Address/offset of the string in the RzBuffer ut32 size; ///< Size of buffer containing the string in bytes ut32 length; ///< Length of string in chars diff --git a/librz/search/string_search.c b/librz/search/string_search.c index d8e07537ec0..748936a1c54 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -4,12 +4,13 @@ #include #include +#include +#include #include "search_internal.h" typedef struct string_search { RzUtilStrScanOptions options; ///< String scan options RzStrEnc encoding; ///< Expected encoding - bool caseless; ///< Caseless search. RzPVector /**/ *strings; ///< Strings to search } StringSearch; @@ -35,23 +36,24 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs void **it_m = NULL; rz_pvector_foreach (ss->strings, it_m) { RzDetectedString *find = *it_m; - if (detected->length < find->length) { - // Ignore strings that are smaller than the one we are looking for. - continue; - } - size_t len = RZ_MIN(detected->length, find->length); - if ((ss->caseless && rz_str_ncasecmp(detected->string, find->string, len)) || - (!ss->caseless && strncmp(detected->string, find->string, len))) { - // Ignore strings that are not matching till len. - continue; - } - - RzSearchHit *hit = rz_search_hit_new("string", detected->addr, detected->size); - if (!hit || !rz_th_queue_push(hits, hit, true)) { - rz_search_hit_free(hit); - rz_list_free(found); - return false; + RzPVector *matches = rz_regex_match_all(find->regex, detected->string, detected->size, 0, RZ_REGEX_DEFAULT); + void **it; + rz_pvector_foreach (matches, it) { + RzPVector *match = *it; + RzRegexMatch *group0 = rz_pvector_at(match, 0); + if (!group0) { + RZ_LOG_ERROR("search: Failed to get group of match.\n"); + rz_list_free(found); + return false; + } + RzSearchHit *hit = rz_search_hit_new("string", detected->addr + group0->start, group0->len); + if (!hit || !rz_th_queue_push(hits, hit, true)) { + rz_search_hit_free(hit); + rz_list_free(found); + return false; + } } + rz_pvector_free(matches); } } @@ -78,11 +80,11 @@ static void string_free(void *user) { * * \param opts The RzUtilStrScanOptions options to use * \param[in] expected The expected encoding - * \param[in] caseless When true performs a caseless compare + * \param[in] flags The regex flags to the \p re_pattern. * * \return On success returns a valid pointer, otherwise NULL */ -RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, bool caseless) { +RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtilStrScanOptions *opts, RzStrEnc expected, RzRegexFlags flags) { rz_return_val_if_fail(opts, NULL); StringSearch *ss = RZ_NEW0(StringSearch); @@ -100,49 +102,59 @@ RZ_API RZ_OWN RzSearchCollection *rz_search_collection_strings(RZ_NONNULL RzUtil ss->options = *opts; // Copy the values ss->encoding = expected; - ss->caseless = caseless; return rz_search_collection_new_bytes_space(string_find, string_is_empty, string_free, ss); } -static RzDetectedString *string_copy(const char *string) { - char *copy = rz_str_dup(string); - if (!copy) { +static RzDetectedString *setup_str_regex(const char *re_pattern, RzRegexFlags flags) { + char *re_pattern_clone = rz_str_dup(re_pattern); + if (!re_pattern_clone) { + RZ_LOG_ERROR("Failed to clone regex pattern\n"); + return NULL; + } + RzRegex *re = rz_regex_new(re_pattern, flags, RZ_REGEX_DEFAULT); + if (!re) { + RZ_LOG_ERROR("Failed to compile regex pattern: '%s'\n", re_pattern); + free(re_pattern_clone); return NULL; } RzDetectedString *ds = RZ_NEW0(RzDetectedString); if (!ds) { - free(copy); + RZ_LOG_ERROR("Failed allocate memory for RzDetectedString\n"); + free(re_pattern_clone); + rz_regex_free(re); return NULL; } - ds->string = copy; - ds->length = strlen(copy); + ds->string = re_pattern_clone; + ds->regex = re; + ds->length = strlen(re_pattern_clone); return ds; } /** - * \brief Adds a new string into a string RzSearchCollection + * \brief Adds a new regex pattern into a string RzSearchCollection. * - * \param[in] col The RzSearchCollection to use - * \param[in] string The regular expression to add + * \param[in] col The RzSearchCollection to use. + * \param[in] regex_pattern The regular expression to add. + * \param[in] flags The regular expression flags. * - * \return On success returns true, otherwise false + * \return On success returns true, otherwise false. */ -RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *string) { - rz_return_val_if_fail(col && string, false); +RZ_API bool rz_search_collection_string_add(RZ_NONNULL RzSearchCollection *col, RZ_NONNULL const char *regex_pattern, RzRegexFlags flags) { + rz_return_val_if_fail(col && regex_pattern, false); if (!rz_search_collection_has_find_callback(col, string_find)) { RZ_LOG_ERROR("search: cannot add string to non-string collection\n"); return false; - } else if (RZ_STR_ISEMPTY(string)) { + } else if (RZ_STR_ISEMPTY(regex_pattern)) { RZ_LOG_ERROR("search: cannot add an empty string to a string collection\n"); return false; } StringSearch *ss = (StringSearch *)col->user; - RzDetectedString *s = string_copy(string); + RzDetectedString *s = setup_str_regex(regex_pattern, flags); if (!s || !rz_pvector_push(ss->strings, s)) { - RZ_LOG_ERROR("search: cannot add the string '%s'.\n", string); + RZ_LOG_ERROR("search: cannot add the string '%s'.\n", regex_pattern); rz_detected_string_free(s); return false; } diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 2c6325593f4..19f218c09a9 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only #include +#include #include #include #include @@ -76,6 +77,7 @@ RZ_API void rz_detected_string_free(RzDetectedString *str) { return; } free(str->string); + rz_regex_free(str->regex); free(str); } @@ -292,7 +294,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 if ((i + 32) < opt->buf_size && r < 93) { rc = rz_utf8_encode(strbuf + i, r); } else { - // string too long + // String too long break; } runes++; From be2d846218c464e4ac048cad0e69775308923402 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 20 Jan 2025 14:57:43 -0500 Subject: [PATCH 021/157] Add test cases --- test/db/cmd/cmd_search_z | 195 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 test/db/cmd/cmd_search_z diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z new file mode 100644 index 00000000000..6344ecae947 --- /dev/null +++ b/test/db/cmd/cmd_search_z @@ -0,0 +1,195 @@ +NAME=String Search - Errors - Empty string +FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ascii +CMDS=< Date: Tue, 21 Jan 2025 12:19:13 -0500 Subject: [PATCH 022/157] Add UTF8 search tests --- test/db/cmd/cmd_search_z | 80 +++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 6344ecae947..15f945b79da 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -44,10 +44,20 @@ e search.show_progress=false /z "Lorem ipsum dolor sit amet, at eligendi adipisci ius, ex natum appetere officiis has, nibh quas torquatos pro te. Quo at deleniti repudiandae, et oratio pertinacia ullamcorper quo. Per ut stet assum augue, brute pertinacia pri id. Sed omnium oblique placerat ut, eu etiam vitae nam. Per invenire expetenda dissentiet id, ea alia nostrud detraxit est, est eros intellegebat et." d ascii EOF EXPECT=< Date: Tue, 21 Jan 2025 12:58:30 -0500 Subject: [PATCH 023/157] Add UTF-16-be tests. --- test/db/cmd/cmd_search_z | 154 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 15f945b79da..d14f6d2b15b 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -205,3 +205,157 @@ EOF EXPECT_ERR= RUN +NAME=String Search - Encoding: utf16be - Arabic +FILE=bins/cmd/search/string_encodings/Arabic-Lipsum.utf16be +CMDS=< Date: Tue, 21 Jan 2025 14:00:45 -0500 Subject: [PATCH 024/157] Use renamed files --- test/db/cmd/cmd_search_z | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index d14f6d2b15b..e6e3a247e3b 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -72,8 +72,8 @@ EOF EXPECT_ERR= RUN -NAME=String Search - Encoding: utf_8 - Arabic -FILE=bins/cmd/search/string_encodings/Arabic-Lipsum.utf_8 +NAME=String Search - Encoding: utf8 - Arabic +FILE=bins/cmd/search/string_encodings/Arabic-Lipsum.utf8 CMDS=< Date: Tue, 21 Jan 2025 14:01:42 -0500 Subject: [PATCH 025/157] Fix typo --- librz/core/cmd_descs/cmd_search.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 797c6bd589e..663eea74cc1 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -323,7 +323,7 @@ commands: comment: "8bit encoding. Alias: ASCII" - text: "mutf8" comment: "mutf8 encoding" - - text: "UTF-8" + - text: "utf8" comment: "UTF-8 encoding" - text: "utf16le" comment: "UTF-16 little endian encoding" From 95cc6e806959d7b483decee73c7cc32378db059d Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 21 Jan 2025 14:15:46 -0500 Subject: [PATCH 026/157] Clearify in regex header that flags are only used for compilation. --- librz/include/rz_util/rz_regex.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/librz/include/rz_util/rz_regex.h b/librz/include/rz_util/rz_regex.h index 5e422656a0d..35159a5b8da 100644 --- a/librz/include/rz_util/rz_regex.h +++ b/librz/include/rz_util/rz_regex.h @@ -17,11 +17,18 @@ #define RZ_REGEX_ERROR_NOMATCH (-1) /* PCRE2_ERROR_NOMATCH */ #define RZ_REGEX_ERROR_PARTIAL (-2) /* PCRE2_ERROR_PARTIAL */ +/** + * \brief Regex compilation flags. They are only used for rz_regex_new() + * C alters what is compiled by rz_regex_new() + * J alters what is compiled by rz_regex_new() (with JIT enabled). + * M is inspected during rz_regex_match() execution + * D is inspected during pcre2_dfa_match() execution (not used). + */ #define RZ_REGEX_DEFAULT 0 -#define RZ_REGEX_CASELESS 0x00000008u /* PCRE2_CASELESS */ -#define RZ_REGEX_EXTENDED 0x00000080u /* PCRE2_EXTENDED */ -#define RZ_REGEX_EXTENDED_MORE 0x01000000u /* PCRE2_EXTENDED_MORE */ -#define RZ_REGEX_MULTILINE 0x00000400u /* PCRE2_MULTILINE */ +#define RZ_REGEX_CASELESS 0x00000008u /* PCRE2_CASELESS - C */ +#define RZ_REGEX_EXTENDED 0x00000080u /* PCRE2_EXTENDED - C */ +#define RZ_REGEX_EXTENDED_MORE 0x01000000u /* PCRE2_EXTENDED_MORE - C */ +#define RZ_REGEX_MULTILINE 0x00000400u /* PCRE2_MULTILINE - C */ #define RZ_REGEX_JIT_PARTIAL_SOFT 0x00000002u /* PCRE2_JIT_PARTIAL_SOFT */ #define RZ_REGEX_JIT_PARTIAL_HARD 0x00000004u /* PCRE2_JIT_PARTIAL_HARD */ From c88077b6f0076e6fe4c1b70eb9fba8b87c054311 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 21 Jan 2025 14:25:07 -0500 Subject: [PATCH 027/157] Add utf16le tests --- librz/core/cmd_descs/cmd_descs.c | 2 +- test/db/cmd/cmd_search_z | 154 +++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 574036d78b6..525b258e362 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -1725,7 +1725,7 @@ static const RzCmdDescDetailEntry slash_z_Encodings_detail_entries[] = { { .text = "ascii", .arg_str = NULL, .comment = "ASCII encoding" }, { .text = "8bit", .arg_str = NULL, .comment = "8bit encoding. Alias: ASCII" }, { .text = "mutf8", .arg_str = NULL, .comment = "mutf8 encoding" }, - { .text = "UTF-8", .arg_str = NULL, .comment = "UTF-8 encoding" }, + { .text = "utf8", .arg_str = NULL, .comment = "UTF-8 encoding" }, { .text = "utf16le", .arg_str = NULL, .comment = "UTF-16 little endian encoding" }, { .text = "utf32le", .arg_str = NULL, .comment = "UTF-32 little endian encoding" }, { .text = "utf16be", .arg_str = NULL, .comment = "UTF-16 big endian encoding" }, diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index e6e3a247e3b..b003670abd9 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -359,3 +359,157 @@ EOF EXPECT_ERR= RUN +NAME=String Search - Encoding: utf16le - Arabic +FILE=bins/cmd/search/string_encodings/Arabic-Lipsum.utf16le +CMDS=< Date: Wed, 22 Jan 2025 10:42:41 -0500 Subject: [PATCH 028/157] Add utf32 string search tests. --- test/db/cmd/cmd_search_z | 308 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index b003670abd9..a57e12cf756 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -513,3 +513,311 @@ EOF EXPECT_ERR= RUN +NAME=String Search - Encoding: utf32be - Arabic +FILE=bins/cmd/search/string_encodings/Arabic-Lipsum.utf32be +CMDS=< Date: Wed, 22 Jan 2025 15:20:17 -0500 Subject: [PATCH 029/157] Fix utf16 encode to allow codepoints up to 10ffff. --- test/unit/test_encodings.c | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 6cebd6364d6..3d52db27d7c 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -159,6 +159,50 @@ bool test_rz_utf16_encode(void) { mu_end; } +/** + * \brief Examples partially taken from: https://en.wikipedia.org/wiki/UTF-16#Examples + */ +bool test_rz_utf16_encode(void) { + ut8 utf16_out[5] = { 0 }; + + const ut8 utf16le[] = { 0xAC, 0x20 }; + RzRune codepoint = 0x20AC; + int nbytes = rz_utf16le_encode(utf16_out, codepoint); + mu_assert_eq(nbytes, 2, "Decoded number of bytes mismatch."); + mu_assert_memeq(utf16_out, utf16le, sizeof(utf16le), "Encode failed."); + memset(utf16_out, 0, sizeof(utf16_out)); + + // With surrogate + const ut8 utf16le_surr[] = { 0x01, 0xD8, 0x37, 0xDC }; + codepoint = 0x10437; + nbytes = rz_utf16le_encode(utf16_out, codepoint); + mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); + mu_assert_memeq(utf16_out, utf16le_surr, sizeof(utf16le), "Encode failed."); + memset(utf16_out, 0, sizeof(utf16_out)); + + const ut8 utf16le_first_surr[] = { 0x00, 0xD8, 0x00, 0xDC }; + codepoint = 0x10000; + nbytes = rz_utf16le_encode(utf16_out, codepoint); + mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); + mu_assert_memeq(utf16_out, utf16le_first_surr, sizeof(utf16le), "Encode failed."); + memset(utf16_out, 0, sizeof(utf16_out)); + + const ut8 utf16le_last_surr[] = { 0xFF, 0xDB, 0xFF, 0xDF }; + codepoint = 0x10FFFF; + nbytes = rz_utf16le_encode(utf16_out, codepoint); + mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); + mu_assert_memeq(utf16_out, utf16le_last_surr, sizeof(utf16le), "Encode failed."); + memset(utf16_out, 0, sizeof(utf16_out)); + + ut8 zero[5] = { 0 }; + codepoint = 0x110000; + nbytes = rz_utf16le_encode(utf16_out, codepoint); + mu_assert_eq(nbytes, 0, "Decoded number of bytes mismatch."); + mu_assert_memeq(utf16_out, zero, sizeof(utf16le), "Encode failed."); + + mu_end; +} + bool all_tests() { mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); From 4decb92afa04b2a4d353f762196a28bbc8bc611e Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 22 Jan 2025 16:21:48 -0500 Subject: [PATCH 030/157] Only print until non-printable character. --- librz/core/cmd/cmd_print.c | 22 +++++++++++++++------- librz/include/rz_core.h | 2 +- librz/include/rz_util/rz_str.h | 1 + librz/util/str.c | 10 +++++++--- test/db/cmd/print | 22 ++++++++++++++++++++++ 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 5b12e1f77f4..56c009c8524 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -1859,7 +1859,7 @@ static inline ut32 cmd_pxb_k(const ut8 *buffer, int x) { return ((ut32)buffer[3 - x]) << (8 * x); } -static void print_json_string(RzCore *core, const ut8 *block, ut32 len, RzStrEnc encoding, bool stop_at_nil) { +static void print_json_string(RzCore *core, const ut8 *block, ut32 len, RzStrEnc encoding, bool stop_at_nil, bool stop_at_unprintable) { char *section = get_section_name(core, core->offset); if (!section) { return; @@ -1871,6 +1871,7 @@ static void print_json_string(RzCore *core, const ut8 *block, ut32 len, RzStrEnc opt.encoding = encoding; opt.json = true; opt.stop_at_nil = stop_at_nil; + opt.stop_at_unprintable = stop_at_unprintable; char *dstring = rz_str_stringify_raw_buffer(&opt, &dlength); if (!dstring) { free(section); @@ -2099,10 +2100,11 @@ static RzCmdStatus core_auto_detect_and_print_string(RzCore *core, bool stop_at_ opt.length = length; opt.encoding = encoding; opt.stop_at_nil = stop_at_nil; + opt.stop_at_unprintable = true; core_print_raw_buffer(&opt); break; case RZ_OUTPUT_MODE_JSON: - print_json_string(core, buffer, length, encoding, stop_at_nil); + print_json_string(core, buffer, length, encoding, stop_at_nil, true); break; default: RZ_LOG_ERROR("core: unsupported output mode\n"); @@ -2260,10 +2262,11 @@ RZ_IPI RzCmdStatus rz_print_pascal_string_handler(RzCore *core, int argc, const opt.length = string_len; opt.encoding = RZ_STRING_ENC_8BIT; opt.stop_at_nil = true; + opt.stop_at_unprintable = true; core_print_raw_buffer(&opt); break; case RZ_OUTPUT_MODE_JSON: - print_json_string(core, core->block + offset, string_len, RZ_STRING_ENC_8BIT, true); + print_json_string(core, core->block + offset, string_len, RZ_STRING_ENC_8BIT, true, true); break; default: RZ_LOG_ERROR("core: unsupported output mode\n"); @@ -2661,13 +2664,14 @@ RZ_API void rz_print_offset(RzPrint *p, ut64 off, int invert, int offseg, int of RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16LE, true); + print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16LE, true, true); } else { RzStrStringifyOpt opt = { 0 }; opt.buffer = core->block; opt.length = core->blocksize; opt.encoding = RZ_STRING_ENC_UTF16LE; opt.stop_at_nil = true; + opt.stop_at_unprintable = true; core_print_raw_buffer(&opt); } return RZ_CMD_STATUS_OK; @@ -2675,13 +2679,14 @@ RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char * RZ_IPI RzCmdStatus rz_print_utf32le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF32LE, true); + print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF32LE, true, true); } else { RzStrStringifyOpt opt = { 0 }; opt.buffer = core->block; opt.length = core->blocksize; opt.encoding = RZ_STRING_ENC_UTF32LE; opt.stop_at_nil = true; + opt.stop_at_unprintable = true; core_print_raw_buffer(&opt); } return RZ_CMD_STATUS_OK; @@ -2689,13 +2694,14 @@ RZ_IPI RzCmdStatus rz_print_utf32le_handler(RzCore *core, int argc, const char * RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16BE, true); + print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16BE, true, true); } else { RzStrStringifyOpt opt = { 0 }; opt.buffer = core->block; opt.length = core->blocksize; opt.encoding = RZ_STRING_ENC_UTF16BE; opt.stop_at_nil = true; + opt.stop_at_unprintable = true; core_print_raw_buffer(&opt); } return RZ_CMD_STATUS_OK; @@ -2703,13 +2709,14 @@ RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char * RZ_IPI RzCmdStatus rz_print_utf32be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF32BE, true); + print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF32BE, true, true); } else { RzStrStringifyOpt opt = { 0 }; opt.buffer = core->block; opt.length = core->blocksize; opt.encoding = RZ_STRING_ENC_UTF32BE; opt.stop_at_nil = true; + opt.stop_at_unprintable = true; core_print_raw_buffer(&opt); } return RZ_CMD_STATUS_OK; @@ -4293,6 +4300,7 @@ RZ_IPI RzCmdStatus rz_print_url_encode_zero_handler(RzCore *core, int argc, cons opt.buffer = core->block; opt.length = len; opt.stop_at_nil = true; + opt.stop_at_unprintable = true; opt.encoding = RZ_STRING_ENC_8BIT; opt.urlencode = true; core_print_raw_buffer(&opt); diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index f75b3f320e1..84e984d7eb1 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -44,7 +44,7 @@ RZ_LIB_VERSION_HEADER(rz_core); #define RZ_CORE_CMD_INVALID -1 #define RZ_CORE_CMD_EXIT -2 -#define RZ_CORE_BLOCKSIZE 0x100 +#define RZ_CORE_BLOCKSIZE 0x1000 #define RZ_CORE_BLOCKSIZE_MAX 0x3200000 /* 32MB */ #define RZ_FLAGS_FS_CLASSES "classes" diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index a70a4fbd88d..fb4db7c3258 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -270,6 +270,7 @@ typedef struct rz_str_stringify_opt_t { bool escape_nl; ///< When enabled escapes new lines (\n). bool json; ///< Encodes the output as a JSON string. bool stop_at_nil; ///< When enabled stops printing when '\0' is found. + bool stop_at_unprintable; ///< When enabled stops printing at first non-printable character. bool urlencode; ///< Encodes the output following RFC 3986. } RzStrStringifyOpt; diff --git a/librz/util/str.c b/librz/util/str.c index 5a891478aa9..8cad9eed502 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4177,7 +4177,9 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU rsize = rz_utf8_decode(&buf[i], buflen - i, &code_point); } - if (rsize == 0) { + if (rsize == 0 && option->stop_at_unprintable) { + break; + } else if (rsize == 0) { switch (enc) { case RZ_STRING_ENC_UTF32LE: rsize = RZ_MIN(4, buflen - i); @@ -4265,7 +4267,7 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU char tmp[5] = { 0 }; rz_utf8_encode((ut8 *)tmp, code_point); rz_strbuf_appendf(&sb, "%s", tmp); - } else { + } else if (!option->stop_at_unprintable) { ut8 tmp[4]; int n_enc = rz_utf8_encode((ut8 *)tmp, code_point); for (int j = 0; j < n_enc; ++j) { @@ -4278,7 +4280,9 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU line_runes = 0; } } - if (!option->json) { + if (!option->json && n_runes > 0) { + // Only add a newline, if a string was decoded. + // Otherwise, people might think there was a "newline" string. rz_strbuf_appendf(&sb, "\n"); } if (length) { diff --git a/test/db/cmd/print b/test/db/cmd/print index c0104e5efe9..9ed622bdea6 100644 --- a/test/db/cmd/print +++ b/test/db/cmd/print @@ -312,3 +312,25 @@ EXPECT=< Date: Thu, 23 Jan 2025 13:41:40 -0500 Subject: [PATCH 031/157] Add test for UTF8 to check offset of string. --- test/db/cmd/cmd_search_z | 224 ++++++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 100 deletions(-) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index a57e12cf756..722c2a9cf91 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -42,9 +42,12 @@ FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ascii CMDS=< Date: Thu, 23 Jan 2025 13:43:43 -0500 Subject: [PATCH 032/157] Mover error case test to the top --- test/db/cmd/cmd_search_z | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 722c2a9cf91..f4d9804146e 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -37,28 +37,28 @@ ERROR: core: invalid encoding 'aa'. EOF RUN -NAME=String Search - match all - Encoding: ascii - Latin +NAME=String Search - larger than file - Encoding: ascii - Latin FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ascii CMDS=< Date: Thu, 23 Jan 2025 16:57:41 -0500 Subject: [PATCH 033/157] Fix offsets and length of detected strings. --- librz/include/rz_util/rz_str_search.h | 12 +- librz/search/string_search.c | 35 +++- librz/util/str_search.c | 5 + test/db/cmd/cmd_search_z | 252 ++++++++++++-------------- 4 files changed, 167 insertions(+), 137 deletions(-) diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index b63bf043356..b17abf123fc 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -28,10 +29,19 @@ typedef struct { */ typedef struct { size_t buf_size; ///< Maximum size of a detected string - size_t max_uni_blocks; ///< Maximum number of unicode blocks + size_t max_uni_blocks; ///< Maximum number of Unicode blocks size_t min_str_length; ///< Minimum string length bool prefer_big_endian; ///< True if the preferred endianess for UTF strings is big-endian bool check_ascii_freq; ///< If true, perform check on ASCII frequencies when looking for false positives + /** + * \brief Map UTF-8 byte offsets to memory offsets. + * The scan function always returns UTF-8 strings. + * Independent what encoding the strings are in memory. + * Sometimes it is necessary to know the offsets of the real encoding. + * This maps a UTF-8 code point offset to the original code point offset (possibly of another encoding). + * Indices are always aligned to code points. + */ + RZ_NULLABLE HtUU *utf8_to_mem_offset_map; } RzUtilStrScanOptions; RZ_API void rz_detected_string_free(RzDetectedString *str); diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 748936a1c54..7bb80b85549 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "search_internal.h" typedef struct string_search { @@ -14,6 +16,29 @@ typedef struct string_search { RzPVector /**/ *strings; ///< Strings to search } StringSearch; +/** + * \brief UTF-8 and the encoding of the real string (in memory) must not match. + * For example, if the real string is UTF-16 or UTF-32. + * Here we set the real (in memory encoded) string offsets and string length. + */ +static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len) { + bool offset_found = false; + *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start, &offset_found); + if (!offset_found) { + RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); + *str_mem_offset = detected->addr + group0->start; + } + if (detected->size != group0->len) { + *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start + group0->len, &offset_found) - *str_mem_offset; + } else { + *str_mem_len = group0->len; + } + if (!offset_found) { + RZ_LOG_WARN("Could not determine length of string in memory. String length will be off.\n"); + *str_mem_len = group0->len; + } +} + static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offset, const RzBuffer *buffer, RZ_OUT RzThreadQueue *hits) { StringSearch *ss = (StringSearch *)user; RzDetectedString *detected = NULL; @@ -25,9 +50,11 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs return false; } + ss->options.utf8_to_mem_offset_map = ht_uu_new(); int n_str_in_buf = rz_scan_strings_whole_buf(buffer, found, &ss->options, ss->encoding); if (n_str_in_buf < 0) { RZ_LOG_ERROR("Failed to scan buffer for strings.\n"); + ht_uu_free(ss->options.utf8_to_mem_offset_map); rz_list_free(found); return false; } @@ -43,12 +70,17 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs RzRegexMatch *group0 = rz_pvector_at(match, 0); if (!group0) { RZ_LOG_ERROR("search: Failed to get group of match.\n"); + ht_uu_free(ss->options.utf8_to_mem_offset_map); rz_list_free(found); return false; } - RzSearchHit *hit = rz_search_hit_new("string", detected->addr + group0->start, group0->len); + ut64 str_mem_len; + ut64 str_mem_offset; + align_offsets(ss, detected, group0, &str_mem_offset, &str_mem_len); + RzSearchHit *hit = rz_search_hit_new("string", str_mem_offset, str_mem_len); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); + ht_uu_free(ss->options.utf8_to_mem_offset_map); rz_list_free(found); return false; } @@ -57,6 +89,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs } } + ht_uu_free(ss->options.utf8_to_mem_offset_map); rz_list_free(found); return true; } diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 19f218c09a9..4f93a7ff157 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -280,6 +281,10 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 break; } + if (opt->utf8_to_mem_offset_map) { + ht_uu_insert(opt->utf8_to_mem_offset_map, i, needle); + } + needle += rc; if (rz_code_point_is_printable(r) && r != '\\') { diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index f4d9804146e..7326ef634e4 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -153,7 +153,7 @@ EOF EXPECT_ERR= RUN -NAME=String Search - Encoding: utf8 - Hebrew II +NAME=String Search - Encoding: utf8 - Hebrew I FILE=bins/cmd/search/string_encodings/Hebrew-Lipsum.utf8 CMDS=< Date: Thu, 23 Jan 2025 16:57:59 -0500 Subject: [PATCH 034/157] Some clean ups of doxygen --- librz/util/str_search.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 4f93a7ff157..0dcf7de49eb 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -405,14 +405,14 @@ RZ_API bool rz_scan_strings_single_raw(RZ_NONNULL const ut8 *buf, ut64 size, RZ_ /** * \brief Look for strings in a byte array. * - * \param buf Pointer to a raw buffer to scan - * \param list Pointer to a list that will be populated with the found strings - * \param opt Pointer to a RzUtilStrScanOptions that specifies search parameters - * \param from Minimum address to scan - * \param to Maximum address to scan - * \param type Type of strings to search + * \param buf Pointer to a raw buffer to scan. + * \param list Pointer to a list that will be populated with the found strings. + * \param opt Pointer to an RzUtilStrScanOptions that specifies search parameters. + * \param from Minimum address to scan. + * \param to Maximum address to scan. + * \param type Type of strings to search. * - * \return Number of strings found + * \return Number of strings found. Or -1 in case of failure. * * Used to look for strings in a give RzBuffer. The function can also automatically detect string types. */ @@ -607,9 +607,9 @@ RZ_API int rz_scan_strings(RZ_NONNULL RzBuffer *buf_to_scan, RZ_NONNULL RzList / * This function is suited for usage on hot paths. * * \param buf_to_scan Pointer to an RzBuffer to scan. - * \param list Pointer to a list that will be populated with the found strings - * \param opt Pointer to an RzUtilStrScanOptions that specifies search parameters - * \param type Type of strings to search + * \param list Pointer to a list that will be populated with the found strings. The strings are always cinverted as UTF-8. + * \param opt Pointer to an RzUtilStrScanOptions that specifies search parameters. + * \param type Type of strings to search. * * \return Number of strings found or -1 in case of failure. */ From ca1aa2a94de345d6331a175ce47f8478b44e2cd9 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 24 Jan 2025 01:02:03 -0500 Subject: [PATCH 035/157] Add dots to doxygen --- librz/util/str_search.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 0dcf7de49eb..c940fc4401d 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -564,13 +564,13 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* Date: Fri, 24 Jan 2025 01:37:34 -0500 Subject: [PATCH 036/157] Add test for ibm037 string --- test/db/cmd/cmd_search_z | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 7326ef634e4..212f616bb70 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -63,6 +63,20 @@ EOF EXPECT_ERR= RUN +NAME=String Search - search - Encoding: ibm037 - Latin +FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ibm037 +CMDS=< Date: Fri, 24 Jan 2025 01:50:03 -0500 Subject: [PATCH 037/157] Add test for very small string search. --- test/db/cmd/cmd_search_z | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 212f616bb70..cfa9a54268d 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -48,6 +48,46 @@ EOF EXPECT_ERR= RUN +NAME=String Search - minimal string - Encoding: ascii - Latin +FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ascii +CMDS=< Date: Mon, 27 Jan 2025 08:49:32 -0500 Subject: [PATCH 038/157] Fix rebase mistakes. --- librz/search/bytes_search.c | 2 +- librz/search/string_search.c | 2 +- test/unit/test_encodings.c | 44 ------------------------------------ 3 files changed, 2 insertions(+), 46 deletions(-) diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index 9dfc31c6b2c..d9fa07a288b 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -124,7 +124,7 @@ RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byt RZ_LOG_ERROR("Pattern contains forbitten characters. Allowed is only '0x', '0-9', 'a-f', 'A-F', '.' and ':'.\n"); goto error; } - RzRegex *regex = rz_regex_new("^(0x)?([a-fA-F.0-9]+)(:(0x)?([a-fA-F0-9.]+))?", RZ_REGEX_DEFAULT, RZ_REGEX_DEFAULT); + RzRegex *regex = rz_regex_new("^(0x)?([a-fA-F.0-9]+)(:(0x)?([a-fA-F0-9.]+))?", RZ_REGEX_DEFAULT, RZ_REGEX_DEFAULT, NULL); matches = rz_regex_match_all_not_grouped(regex, byte_pattern, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT); rz_regex_free(regex); diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 7bb80b85549..0df774cd313 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -145,7 +145,7 @@ static RzDetectedString *setup_str_regex(const char *re_pattern, RzRegexFlags fl RZ_LOG_ERROR("Failed to clone regex pattern\n"); return NULL; } - RzRegex *re = rz_regex_new(re_pattern, flags, RZ_REGEX_DEFAULT); + RzRegex *re = rz_regex_new(re_pattern, flags, RZ_REGEX_DEFAULT, NULL); if (!re) { RZ_LOG_ERROR("Failed to compile regex pattern: '%s'\n", re_pattern); free(re_pattern_clone); diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 3d52db27d7c..6cebd6364d6 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -159,50 +159,6 @@ bool test_rz_utf16_encode(void) { mu_end; } -/** - * \brief Examples partially taken from: https://en.wikipedia.org/wiki/UTF-16#Examples - */ -bool test_rz_utf16_encode(void) { - ut8 utf16_out[5] = { 0 }; - - const ut8 utf16le[] = { 0xAC, 0x20 }; - RzRune codepoint = 0x20AC; - int nbytes = rz_utf16le_encode(utf16_out, codepoint); - mu_assert_eq(nbytes, 2, "Decoded number of bytes mismatch."); - mu_assert_memeq(utf16_out, utf16le, sizeof(utf16le), "Encode failed."); - memset(utf16_out, 0, sizeof(utf16_out)); - - // With surrogate - const ut8 utf16le_surr[] = { 0x01, 0xD8, 0x37, 0xDC }; - codepoint = 0x10437; - nbytes = rz_utf16le_encode(utf16_out, codepoint); - mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_memeq(utf16_out, utf16le_surr, sizeof(utf16le), "Encode failed."); - memset(utf16_out, 0, sizeof(utf16_out)); - - const ut8 utf16le_first_surr[] = { 0x00, 0xD8, 0x00, 0xDC }; - codepoint = 0x10000; - nbytes = rz_utf16le_encode(utf16_out, codepoint); - mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_memeq(utf16_out, utf16le_first_surr, sizeof(utf16le), "Encode failed."); - memset(utf16_out, 0, sizeof(utf16_out)); - - const ut8 utf16le_last_surr[] = { 0xFF, 0xDB, 0xFF, 0xDF }; - codepoint = 0x10FFFF; - nbytes = rz_utf16le_encode(utf16_out, codepoint); - mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_memeq(utf16_out, utf16le_last_surr, sizeof(utf16le), "Encode failed."); - memset(utf16_out, 0, sizeof(utf16_out)); - - ut8 zero[5] = { 0 }; - codepoint = 0x110000; - nbytes = rz_utf16le_encode(utf16_out, codepoint); - mu_assert_eq(nbytes, 0, "Decoded number of bytes mismatch."); - mu_assert_memeq(utf16_out, zero, sizeof(utf16le), "Encode failed."); - - mu_end; -} - bool all_tests() { mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); From fb23d865b63ec950215d7e73cb8445e118de5682 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 27 Jan 2025 13:13:40 -0500 Subject: [PATCH 039/157] Add psu command to force UTF-8 string printing. --- librz/core/cmd/cmd_print.c | 15 +++++++++++++++ librz/core/cmd_descs/cmd_descs.c | 11 +++++++++++ librz/core/cmd_descs/cmd_descs.h | 2 ++ librz/core/cmd_descs/cmd_print.yaml | 7 +++++++ 4 files changed, 35 insertions(+) diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 56c009c8524..55cd5eba2d7 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -2662,6 +2662,21 @@ RZ_API void rz_print_offset(RzPrint *p, ut64 off, int invert, int offseg, int of rz_print_offset_sg(p, off, invert, offseg, 4, offdec, delta, label); } +RZ_IPI RzCmdStatus rz_print_utf8_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + if (mode == RZ_OUTPUT_MODE_JSON) { + print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF8, true, true); + } else { + RzStrStringifyOpt opt = { 0 }; + opt.buffer = core->block; + opt.length = core->blocksize; + opt.encoding = RZ_STRING_ENC_UTF8; + opt.stop_at_nil = true; + opt.stop_at_unprintable = true; + core_print_raw_buffer(&opt); + } + return RZ_CMD_STATUS_OK; +} + RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { if (mode == RZ_OUTPUT_MODE_JSON) { print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16LE, true, true); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 525b258e362..cc642e612c1 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -15343,6 +15343,14 @@ static const RzCmdDescHelp print_string_wrap_width_help = { .args = print_string_wrap_width_args, }; +static const RzCmdDescArg print_utf8_args[] = { + { 0 }, +}; +static const RzCmdDescHelp print_utf8_help = { + .summary = "Print buffer as a utf8 string", + .args = print_utf8_args, +}; + static const RzCmdDescArg print_utf16be_args[] = { { 0 }, }; @@ -23160,6 +23168,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *print_string_wrap_width_cd = rz_cmd_desc_argv_modes_new(core->rcmd, ps_cd, "pss", RZ_OUTPUT_MODE_STANDARD, rz_print_string_wrap_width_handler, &print_string_wrap_width_help); rz_warn_if_fail(print_string_wrap_width_cd); + RzCmdDesc *print_utf8_cd = rz_cmd_desc_argv_modes_new(core->rcmd, ps_cd, "psu", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_print_utf8_handler, &print_utf8_help); + rz_warn_if_fail(print_utf8_cd); + RzCmdDesc *print_utf16be_cd = rz_cmd_desc_argv_modes_new(core->rcmd, ps_cd, "psm", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_print_utf16be_handler, &print_utf16be_help); rz_warn_if_fail(print_utf16be_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 2f77bd6592b..2d8cc5877d0 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -2080,6 +2080,8 @@ RZ_IPI RzCmdStatus rz_print_first_string_current_block_handler(RzCore *core, int RZ_IPI RzCmdStatus rz_print_pascal_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "pss" RZ_IPI RzCmdStatus rz_print_string_wrap_width_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); +// "psu" +RZ_IPI RzCmdStatus rz_print_utf8_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "psm" RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "psM" diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index 75c1e3e5bb1..ce31136ddbe 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1150,6 +1150,13 @@ commands: modes: - RZ_OUTPUT_MODE_STANDARD args: [] + - name: psu + summary: Print buffer as a utf8 string + cname: print_utf8 + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + args: [] - name: psm summary: Print buffer as a utf16be string cname: print_utf16be From 2781f1fb0b23ff35c058a7401d0f0ba4f34b407e Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 27 Jan 2025 13:26:16 -0500 Subject: [PATCH 040/157] Add function to check for valid UTF-32 code points. --- librz/include/rz_util/rz_utf32.h | 1 + librz/util/str.c | 4 ++-- librz/util/str_search.c | 22 +++------------------- librz/util/utf32.c | 25 +++++++++++++++++++++++++ test/unit/test_encodings.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 21 deletions(-) diff --git a/librz/include/rz_util/rz_utf32.h b/librz/include/rz_util/rz_utf32.h index aad07d6f931..25923c3dd5f 100644 --- a/librz/include/rz_util/rz_utf32.h +++ b/librz/include/rz_util/rz_utf32.h @@ -7,5 +7,6 @@ RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool bigendian); RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); +RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian); #endif // RZ_UTF32_H diff --git a/librz/util/str.c b/librz/util/str.c index 8cad9eed502..c1fc5e8f323 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4076,7 +4076,7 @@ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, } for (ut32 i = 0, utf32le = 0, utf32be = 0, utf16le = 0, utf16be = 0, ascii = 0; i < length; ++i) { ut32 leftovers = length - i; - if (leftovers > 4 && IS_PRINTABLE(buffer[i]) && buffer[i + 1] == 0 && buffer[i + 2] == 0 && buffer[i + 3] == 0) { + if (rz_utf32_valid_cp(buffer, leftovers, false)) { utf32le++; // `i > ascii + 1` means at least one non-ascii byte // `utf32le == i / 4 + 1` means neatly algined like 7700 0000 3000 0000 7700 0000 @@ -4084,7 +4084,7 @@ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, enc = RZ_STRING_ENC_UTF32LE; break; } - } else if (leftovers > 4 && buffer[i] == 0 && buffer[i + 1] == 0 && buffer[i + 2] == 0 && IS_PRINTABLE(buffer[i + 3])) { + } else if (rz_utf32_valid_cp(buffer, leftovers, true)) { utf32be++; if (utf32be > 2 && (i > ascii + 1 || utf32be == i / 4 + 1)) { enc = RZ_STRING_ENC_UTF32BE; diff --git a/librz/util/str_search.c b/librz/util/str_search.c index c940fc4401d..381d11f4917 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -358,22 +358,6 @@ static inline bool can_be_utf16_be(const ut8 *buf, ut64 size) { return !buf[0] && buf[1] && !buf[2] && buf[3] && !buf[4] && buf[5] && !buf[6]; } -static inline bool can_be_utf32_le(const ut8 *buf, ut64 size) { - int rc = rz_utf8_decode(buf, size, NULL); - if (!rc || (size - rc) < 5) { - return false; - } - char *w = (char *)buf + rc; - return !w[0] && !w[1] && !w[2] && w[3] && !w[4]; -} - -static inline bool can_be_utf32_be(const ut8 *buf, ut64 size) { - if (size < 7) { - return false; - } - return !buf[0] && !buf[1] && !buf[2] && buf[3] && !buf[4] && !buf[5] && !buf[6]; -} - static inline bool can_be_ebcdic(const ut8 *buf, ut64 size) { return buf[0] < 0x20 || buf[0] > 0x3f; } @@ -440,12 +424,12 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 3 && can_be_utf32_le(ptr + 3, size - 3)) { + } else if (rz_utf32_valid_cp(ptr, size, true)) { + if (to - needle > 3) { // The string can be either utf32-le or utf32-be RzDetectedString *ds_le = process_one_string(buf, from, needle + 3, to, RZ_STRING_ENC_UTF32LE, false, opt); RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF32BE, false, opt); diff --git a/librz/util/utf32.c b/librz/util/utf32.c index 1cccbcd7dfa..266c3ce2619 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -44,3 +44,28 @@ RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { return rz_utf32_decode(ptr, ptrlen, ch, true); } + +/** + * \brief Checks if there is a valid UTF-32 code point at \p buf. + * This function does not check if the code point is defined. + * It just checks it is in a valid range according to RFC 3629. + * + * \param buf The buffer to check the bytes from. + * \param buf_len The buffer length. + * \param big_endian Should be set if the bytes in the buffer are in big endian order. + * + * \return True if the first four bytes are in the valid UTF-32 code point range. + * \return False otherwise. + */ +RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian) { + // At least 4 bytes must be given. + if (buf_len < 4) { + return false; + } + RzCodePoint cp = rz_read_ble32(buf, big_endian); + // UTF-16 surrogates are forbitten code points as of RFC 3629. + bool is_utf16_surregate = cp >= 0xd800 && cp <= 0xdfff; + // Largest Unicode code point is 0x10ffff, also limited in RFC 3629. + bool above_max_code_point = cp > 0x10ffff; + return !is_utf16_surregate && !above_max_code_point; +} diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 6cebd6364d6..b2c48801ea3 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -159,9 +159,40 @@ bool test_rz_utf16_encode(void) { mu_end; } +bool test_rz_utf32_valid(void) { + const ut8 utf32le_invalid_size[] = { 0xAC, 0xAC, 0x20 }; + + const ut8 utf32be_valid_max_cp[] = { 0x00, 0x10, 0xff, 0xff }; + const ut8 utf32be_invalid_max_cp[] = { 0x00, 0x11, 0x00, 0x00 }; + + const ut8 utf32le_valid_max_cp[] = { 0xff, 0xff, 0x10, 0x00 }; + const ut8 utf32le_invalid_max_cp[] = { 0x00, 0x00, 0x11, 0x00 }; + + const ut8 utf32be_invalid_surrogate_I[] = { 0x00, 0x00, 0xd8, 0x00 }; + const ut8 utf32be_invalid_surrogate_II[] = { 0x00, 0x00, 0xdf, 0xff }; + const ut8 utf32be_invalid_surrogate_III[] = { 0x00, 0x00, 0xd7, 0xff }; + const ut8 utf32be_invalid_surrogate_IV[] = { 0x00, 0x00, 0xe0, 0x00 }; + + mu_assert_false(rz_utf32_valid_cp(utf32le_invalid_size, sizeof(utf32le_invalid_size), false), "Length check failed"); + + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_max_cp, sizeof(utf32be_invalid_max_cp), true), "Invalid max failed"); + mu_assert_true(rz_utf32_valid_cp(utf32be_valid_max_cp, sizeof(utf32be_valid_max_cp), true), "Valid max failed"); + + mu_assert_false(rz_utf32_valid_cp(utf32le_invalid_max_cp, sizeof(utf32le_invalid_max_cp), false), "Invalid max failed"); + mu_assert_true(rz_utf32_valid_cp(utf32le_valid_max_cp, sizeof(utf32le_valid_max_cp), false), "Valid max failed"); + + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_I, sizeof(utf32be_invalid_surrogate_I), true), "Surrogate failed"); + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_II, sizeof(utf32be_invalid_surrogate_II), true), "Surrogate failed"); + mu_assert_true(rz_utf32_valid_cp(utf32be_invalid_surrogate_III, sizeof(utf32be_invalid_surrogate_III), true), "Surrogate failed"); + mu_assert_true(rz_utf32_valid_cp(utf32be_invalid_surrogate_IV, sizeof(utf32be_invalid_surrogate_IV), true), "Surrogate failed"); + + mu_end; +} + bool all_tests() { mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); + mu_run_test(test_rz_utf32_valid); return tests_passed != tests_run; } From 2ad24f263c177c6de09b77c39c308d6932321583 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 27 Jan 2025 15:08:16 -0500 Subject: [PATCH 041/157] Add test for case insensitive UTF8. --- librz/search/string_search.c | 30 ++++++++++++++++++++++++------ test/db/cmd/cmd_search_z | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 0df774cd313..9047fe22b78 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -22,17 +22,35 @@ typedef struct string_search { * Here we set the real (in memory encoded) string offsets and string length. */ static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len) { + bool is_utf8_type = detected->type == RZ_STRING_ENC_UTF8 || detected->type == RZ_STRING_ENC_8BIT; + if (is_utf8_type) { + // The memory is aligned. + *str_mem_offset = detected->addr + group0->start; + *str_mem_len = group0->len; + // For UTF-8 types we have to free the offset map and set it to an empty one. + // Because the string scan does multiple attempts to parse the same offset in the memory + // with multiple encodings (although it already found a valid string). + // This messes up this naive offset map (index 0 is overwritten + // multiple times with an invalid index). + // Until the string parsing is cleared up, this work-around hopefully does + // its job. + // If you need to debug it, just remove this condition and + // run the cmd_search_z tests. You will see the warnings. + if (ss->options.utf8_to_mem_offset_map) { + ht_uu_free(ss->options.utf8_to_mem_offset_map); + ss->options.utf8_to_mem_offset_map = ht_uu_new(); + } + return; + } + bool offset_found = false; + *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start, &offset_found); - if (!offset_found) { + if (!offset_found && is_utf8_type) { RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); *str_mem_offset = detected->addr + group0->start; } - if (detected->size != group0->len) { - *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start + group0->len, &offset_found) - *str_mem_offset; - } else { - *str_mem_len = group0->len; - } + *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start + group0->len, &offset_found) - *str_mem_offset; if (!offset_found) { RZ_LOG_WARN("Could not determine length of string in memory. String length will be off.\n"); *str_mem_len = group0->len; diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index cfa9a54268d..ee1d20a4b75 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -881,3 +881,22 @@ EXPECT=< Date: Tue, 28 Jan 2025 13:33:05 -0500 Subject: [PATCH 042/157] Add EBCDIC code point validator. --- librz/include/rz_util/rz_ebcdic.h | 2 ++ librz/util/ebcdic.c | 35 +++++++++++++++++++++++++++++++ librz/util/str_search.c | 6 +----- test/unit/test_encodings.c | 26 ++++++++++++++++++++++- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/librz/include/rz_util/rz_ebcdic.h b/librz/include/rz_util/rz_ebcdic.h index 576bb542cd3..685c38f0c64 100644 --- a/librz/include/rz_util/rz_ebcdic.h +++ b/librz/include/rz_util/rz_ebcdic.h @@ -42,6 +42,8 @@ RZ_API int rz_str_ebcdic_us_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCod RZ_API int rz_str_ebcdic_es_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint *dst); RZ_API int rz_str_ebcdic_es_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src); +RZ_API bool rz_str_ebcdic_valid_cp(const RzCodePoint code_point); + #ifdef __cplusplus } #endif diff --git a/librz/util/ebcdic.c b/librz/util/ebcdic.c index 4364f0d7892..504707ec979 100644 --- a/librz/util/ebcdic.c +++ b/librz/util/ebcdic.c @@ -684,4 +684,39 @@ RZ_API int rz_str_ebcdic_es_from_ascii(RZ_NONNULL RZ_OUT ut8 *dst, const ut8 src return 1; } +/** + * \brief Check if \p code_point is a supported EBCDIC character. + * + * \return True, if the \p code_point is a supported EBCDIC character. False otherwise. + */ +RZ_API bool rz_str_ebcdic_valid_cp(const RzCodePoint code_point) { + if (code_point == 0) { + // ASCII NUL byte is the same. + return true; + } + + ut8 dst = 0; + rz_str_ibm037_from_unicode(&dst, code_point); + if (dst != 0) { + return true; + } + rz_str_ebcdic_us_from_unicode(&dst, code_point); + if (dst != 0) { + return true; + } + rz_str_ebcdic_uk_from_unicode(&dst, code_point); + if (dst != 0) { + return true; + } + rz_str_ibm290_from_unicode(&dst, code_point); + if (dst != 0) { + return true; + } + rz_str_ebcdic_es_from_unicode(&dst, code_point); + if (dst != 0) { + return true; + } + return false; +} + /// @} diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 381d11f4917..34f62ea64d0 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -358,10 +358,6 @@ static inline bool can_be_utf16_be(const ut8 *buf, ut64 size) { return !buf[0] && buf[1] && !buf[2] && buf[3] && !buf[4] && buf[5] && !buf[6]; } -static inline bool can_be_ebcdic(const ut8 *buf, ut64 size) { - return buf[0] < 0x20 || buf[0] > 0x3f; -} - /** * \brief Look for strings in a byte array, but returns only the first result. * @@ -500,7 +496,7 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* #include "minunit.h" -#include "rz_util/rz_utf8.h" +#include +#include /** * \brief Examples partially taken from: https://en.wikipedia.org/wiki/UTF-16#Examples @@ -189,10 +190,33 @@ bool test_rz_utf32_valid(void) { mu_end; } + +bool test_rz_ebcdic_valid(void) { + // General + mu_assert_true(rz_str_ebcdic_valid_cp(0x41), "A should be valid."); + mu_assert_true(rz_str_ebcdic_valid_cp(0), "\\0 should be valid."); + // EBCDIC-ES + mu_assert_true(rz_str_ebcdic_valid_cp(0xf1), "ñ should be valid."); + // EBCDIC-US + mu_assert_true(rz_str_ebcdic_valid_cp(0xa2), "¢ should be valid."); + // EBCDIC-UK + mu_assert_true(rz_str_ebcdic_valid_cp(0xa3), "£ should be valid."); + // IBM037 + mu_assert_true(rz_str_ebcdic_valid_cp(0xe4), "ä should be valid."); + // IBM290 + mu_assert_true(rz_str_ebcdic_valid_cp(0x30a5), "ゥshould be valid."); + + // An unsopported one. + mu_assert_false(rz_str_ebcdic_valid_cp(0x1E4E), "Ṏ should not be valid."); + + mu_end; +} + bool all_tests() { mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); mu_run_test(test_rz_utf32_valid); + mu_run_test(test_rz_ebcdic_valid); return tests_passed != tests_run; } From 6ade20051ecc3bde3db596507b368adf9355c891 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 09:27:13 -0500 Subject: [PATCH 043/157] Add look ahead ability to utf32 check. --- librz/include/rz_util/rz_utf32.h | 2 +- librz/util/str.c | 4 ++-- librz/util/str_search.c | 4 ++-- librz/util/utf32.c | 36 +++++++++++++++++++++----------- test/unit/test_encodings.c | 26 +++++++++++++++-------- 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/librz/include/rz_util/rz_utf32.h b/librz/include/rz_util/rz_utf32.h index 25923c3dd5f..9eee1d4c210 100644 --- a/librz/include/rz_util/rz_utf32.h +++ b/librz/include/rz_util/rz_utf32.h @@ -7,6 +7,6 @@ RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool bigendian); RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); -RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian); +RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); #endif // RZ_UTF32_H diff --git a/librz/util/str.c b/librz/util/str.c index c1fc5e8f323..a56f4f90c8f 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4076,7 +4076,7 @@ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, } for (ut32 i = 0, utf32le = 0, utf32be = 0, utf16le = 0, utf16be = 0, ascii = 0; i < length; ++i) { ut32 leftovers = length - i; - if (rz_utf32_valid_cp(buffer, leftovers, false)) { + if (rz_utf32_valid_cp(buffer, leftovers, false, 1)) { utf32le++; // `i > ascii + 1` means at least one non-ascii byte // `utf32le == i / 4 + 1` means neatly algined like 7700 0000 3000 0000 7700 0000 @@ -4084,7 +4084,7 @@ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, enc = RZ_STRING_ENC_UTF32LE; break; } - } else if (rz_utf32_valid_cp(buffer, leftovers, true)) { + } else if (rz_utf32_valid_cp(buffer, leftovers, true, 1)) { utf32be++; if (utf32be > 2 && (i > ascii + 1 || utf32be == i / 4 + 1)) { enc = RZ_STRING_ENC_UTF32BE; diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 34f62ea64d0..326a52975d5 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -420,11 +420,11 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 3) { // The string can be either utf32-le or utf32-be RzDetectedString *ds_le = process_one_string(buf, from, needle + 3, to, RZ_STRING_ENC_UTF32LE, false, opt); diff --git a/librz/util/utf32.c b/librz/util/utf32.c index 266c3ce2619..725a7c9abab 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -46,26 +46,38 @@ RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { } /** - * \brief Checks if there is a valid UTF-32 code point at \p buf. - * This function does not check if the code point is defined. - * It just checks it is in a valid range according to RFC 3629. + * \brief Checks if there are valid UTF-32 code points at \p buf. + * This function does not check if the code points are defined. + * It just checks they are in a valid range according to RFC 3629. * * \param buf The buffer to check the bytes from. * \param buf_len The buffer length. * \param big_endian Should be set if the bytes in the buffer are in big endian order. + * \param lookahead Number of code points to check. + * Note: if the buffer can't cover all \p lookahead code points, this returns false. * - * \return True if the first four bytes are in the valid UTF-32 code point range. + * \return True if the buffer \p lookahead valid UTF-32 code points. * \return False otherwise. */ -RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian) { +RZ_API bool rz_utf32_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { + rz_return_val_if_fail(buf && buf_len > 0, false); // At least 4 bytes must be given. - if (buf_len < 4) { + // Buffer must cover all look aheads. + if (buf_len < 4 || buf_len < (lookahead * 4) || lookahead == 0) { return false; } - RzCodePoint cp = rz_read_ble32(buf, big_endian); - // UTF-16 surrogates are forbitten code points as of RFC 3629. - bool is_utf16_surregate = cp >= 0xd800 && cp <= 0xdfff; - // Largest Unicode code point is 0x10ffff, also limited in RFC 3629. - bool above_max_code_point = cp > 0x10ffff; - return !is_utf16_surregate && !above_max_code_point; + size_t offset = 0; + while (lookahead > 0) { + RzCodePoint cp = rz_read_ble32(buf + offset, big_endian); + // UTF-16 surrogates are forbitten code points as of RFC 3629. + bool is_utf16_surregate = cp >= 0xd800 && cp <= 0xdfff; + // Largest Unicode code point is 0x10ffff, also limited in RFC 3629. + bool above_max_code_point = cp > 0x10ffff; + if (is_utf16_surregate || above_max_code_point) { + return false; + } + lookahead--; + offset += 4; + } + return true; } diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index be83f972e26..55486082b10 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -174,18 +174,26 @@ bool test_rz_utf32_valid(void) { const ut8 utf32be_invalid_surrogate_III[] = { 0x00, 0x00, 0xd7, 0xff }; const ut8 utf32be_invalid_surrogate_IV[] = { 0x00, 0x00, 0xe0, 0x00 }; - mu_assert_false(rz_utf32_valid_cp(utf32le_invalid_size, sizeof(utf32le_invalid_size), false), "Length check failed"); + const ut8 utf32be_valid_invalid[] = { 0x00, 0x10, 0xff, 0xff, 0x00, 0x11, 0x00, 0x00 }; - mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_max_cp, sizeof(utf32be_invalid_max_cp), true), "Invalid max failed"); - mu_assert_true(rz_utf32_valid_cp(utf32be_valid_max_cp, sizeof(utf32be_valid_max_cp), true), "Valid max failed"); + mu_assert_false(rz_utf32_valid_cp(utf32le_invalid_size, sizeof(utf32le_invalid_size), false, 1), "Length check failed"); - mu_assert_false(rz_utf32_valid_cp(utf32le_invalid_max_cp, sizeof(utf32le_invalid_max_cp), false), "Invalid max failed"); - mu_assert_true(rz_utf32_valid_cp(utf32le_valid_max_cp, sizeof(utf32le_valid_max_cp), false), "Valid max failed"); + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_max_cp, sizeof(utf32be_invalid_max_cp), true, 1), "Invalid max failed"); + mu_assert_true(rz_utf32_valid_cp(utf32be_valid_max_cp, sizeof(utf32be_valid_max_cp), true, 1), "Valid max failed"); - mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_I, sizeof(utf32be_invalid_surrogate_I), true), "Surrogate failed"); - mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_II, sizeof(utf32be_invalid_surrogate_II), true), "Surrogate failed"); - mu_assert_true(rz_utf32_valid_cp(utf32be_invalid_surrogate_III, sizeof(utf32be_invalid_surrogate_III), true), "Surrogate failed"); - mu_assert_true(rz_utf32_valid_cp(utf32be_invalid_surrogate_IV, sizeof(utf32be_invalid_surrogate_IV), true), "Surrogate failed"); + mu_assert_false(rz_utf32_valid_cp(utf32le_invalid_max_cp, sizeof(utf32le_invalid_max_cp), false, 1), "Invalid max failed"); + mu_assert_true(rz_utf32_valid_cp(utf32le_valid_max_cp, sizeof(utf32le_valid_max_cp), false, 1), "Valid max failed"); + + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_I, sizeof(utf32be_invalid_surrogate_I), true, 1), "Surrogate failed"); + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_II, sizeof(utf32be_invalid_surrogate_II), true, 1), "Surrogate failed"); + mu_assert_true(rz_utf32_valid_cp(utf32be_invalid_surrogate_III, sizeof(utf32be_invalid_surrogate_III), true, 1), "Surrogate failed"); + mu_assert_true(rz_utf32_valid_cp(utf32be_invalid_surrogate_IV, sizeof(utf32be_invalid_surrogate_IV), true, 1), "Surrogate failed"); + + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_IV, sizeof(utf32be_invalid_surrogate_IV), true, 2), "Look ahead is not covered by buffer."); + mu_assert_false(rz_utf32_valid_cp(utf32be_invalid_surrogate_IV, sizeof(utf32be_invalid_surrogate_IV), true, 0), "Look ahead is 0."); + + mu_assert_true(rz_utf32_valid_cp(utf32be_valid_invalid, sizeof(utf32be_valid_invalid), true, 1), "First is ok."); + mu_assert_false(rz_utf32_valid_cp(utf32be_valid_invalid, sizeof(utf32be_valid_invalid), true, 2), "But last one is not ok."); mu_end; } From 72792159087bd7e309d2d3f49a6d3a66ac7e653f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 10:55:59 -0500 Subject: [PATCH 044/157] Add a validator function for UTF-16 chars. --- librz/include/rz_util/rz_utf16.h | 1 + librz/util/utf16.c | 44 ++++++++++++++++++++- test/unit/test_encodings.c | 66 +++++++++++++++++++++++++++++++- 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/librz/include/rz_util/rz_utf16.h b/librz/include/rz_util/rz_utf16.h index 57f34bb9af0..36615a05c08 100644 --- a/librz/include/rz_util/rz_utf16.h +++ b/librz/include/rz_util/rz_utf16.h @@ -8,5 +8,6 @@ RZ_API size_t rz_utf16_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONN RZ_API size_t rz_utf16le_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch); RZ_API size_t rz_utf16be_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch); RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint ch); +RZ_API bool rz_utf16_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); #endif // RZ_UTF16_H diff --git a/librz/util/utf16.c b/librz/util/utf16.c index ee5708f43da..57ff092f735 100644 --- a/librz/util/utf16.c +++ b/librz/util/utf16.c @@ -46,7 +46,7 @@ RZ_API size_t rz_utf16_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONN return 2; } *ch = (ut32)buf[low]; - return 1; + return 2; } /** @@ -104,3 +104,45 @@ RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint codepoin buf[3] = low >> 8 & 0xff; return 4; } + +/** + * \brief Checks if there are valid UTF-16 code points at \p buf. + * This function does not check if the code points are defined. + * It just checks they are in a valid range according to RFC 3629. + * + * NOTE: Almost any byte sequence can be a valid UTF-16 code point. + * It is advisable to first check for UTF-32 and other encodings. + * + * \param buf The buffer to check the bytes from. + * \param buf_len The buffer length. + * \param big_endian Should be set if the bytes in the buffer are in big endian order. + * \param lookahead Number of code points to check. + * Note: if the buffer can't cover all \p lookahead code points, this returns false. + * + * \return True if the buffer \p lookahead valid UTF-32 code points. + * \return False otherwise. + */ +RZ_API bool rz_utf16_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { + rz_return_val_if_fail(buf && buf_len > 0, false); + // At least 2 bytes must be given. + // Buffer must cover all look aheads. + if (buf_len < 2 || buf_len < (lookahead * 2) || lookahead == 0) { + return false; + } + size_t offset = 0; + RzCodePoint cp = 0; + while (lookahead > 0) { + size_t dec_bytes = rz_utf16_decode(buf + offset, buf_len - offset, &cp, big_endian); + // Largest Unicode code point is 0x10ffff, limited in RFC 3629. + bool above_max_code_point = cp > 0x10ffff; + if (above_max_code_point || dec_bytes == 0) { + return false; + } + lookahead--; + offset += dec_bytes; + if (offset >= buf_len && lookahead > 0) { + return false; + } + } + return true; +} diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 55486082b10..cdec8e477d5 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -12,10 +12,27 @@ bool test_rz_utf16_decode(void) { char utf8_out[5] = { 0 }; RzCodePoint codepoint = 0; + const ut8 utf16le_A[] = { 0x41, 0x00 }; + const ut8 utf16be_A[] = { 0x00, 0x41 }; + + int nbytes = rz_utf16_decode(utf16le_A, 2, &codepoint, false); + mu_assert_eq(nbytes, 2, "Decoded number of bytes mismatch."); + mu_assert_eq_fmt(codepoint, 0x0041, "Character decode failed.", "0x%" PFMT64x); + rz_utf8_encode((ut8 *)utf8_out, codepoint); + mu_assert_streq(utf8_out, "A", "Encode failed."); + memset(utf8_out, 0, sizeof(utf8_out)); + + nbytes = rz_utf16_decode(utf16be_A, 2, &codepoint, true); + mu_assert_eq(nbytes, 2, "Decoded number of bytes mismatch."); + mu_assert_eq_fmt(codepoint, 0x0041, "Character decode failed.", "0x%" PFMT64x); + rz_utf8_encode((ut8 *)utf8_out, codepoint); + mu_assert_streq(utf8_out, "A", "Encode failed."); + memset(utf8_out, 0, sizeof(utf8_out)); + const ut8 utf16le[] = { 0xAC, 0x20 }; const ut8 utf16be[] = { 0x20, 0xAC }; - int nbytes = rz_utf16_decode(utf16le, 2, &codepoint, false); + nbytes = rz_utf16_decode(utf16le, 2, &codepoint, false); mu_assert_eq(nbytes, 2, "Decoded number of bytes mismatch."); mu_assert_eq_fmt(codepoint, 0x20AC, "Character decode failed.", "0x%" PFMT64x); rz_utf8_encode((ut8 *)utf8_out, codepoint); @@ -198,7 +215,6 @@ bool test_rz_utf32_valid(void) { mu_end; } - bool test_rz_ebcdic_valid(void) { // General mu_assert_true(rz_str_ebcdic_valid_cp(0x41), "A should be valid."); @@ -220,10 +236,56 @@ bool test_rz_ebcdic_valid(void) { mu_end; } + +bool test_rz_utf16_valid(void) { + const ut8 utf16be_one_byte[] = { 0x00 }; + const ut8 utf16be_A[] = { 0x00, 0x41 }; + const ut8 utf16be_EUR[] = { 0x20, 0xAC }; + const ut8 utf16be_complex[] = { 0xD8, 0x01, 0xDC, 0x37 }; + const ut8 utf16be_A_A[] = { 0x00, 0x41, 0x00, 0x41 }; + const ut8 utf16be_complex_EUR_A[] = { 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC, 0x00, 0x41 }; + const ut8 utf16be_complex_A_EUR[] = { 0xD8, 0x01, 0xDC, 0x37, 0x00, 0x41, 0x20, 0xAC }; + const ut8 utf16be_A_complex_EUR[] = { 0x00, 0x41, 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC }; + + // Simple error cases + mu_assert_false(rz_utf16_valid_cp(utf16be_A, sizeof(utf16be_A), false, 0), "lookahead == 0 is not valid."); + mu_assert_false(rz_utf16_valid_cp(utf16be_one_byte, sizeof(utf16be_one_byte), false, 1), "Buffer too small."); + + // Simple cases. One character in buffer. + mu_assert_true(rz_utf16_valid_cp(utf16be_A, sizeof(utf16be_A), true, 1), "Should be valid"); + mu_assert_true(rz_utf16_valid_cp(utf16be_EUR, sizeof(utf16be_EUR), true, 1), "Should be valid"); + mu_assert_true(rz_utf16_valid_cp(utf16be_complex, sizeof(utf16be_complex), true, 1), "Should be valid"); + + // Different width UTF-16 characters + mu_assert_true(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 3), "Should true with 3 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 3), "Should true with 3 different characters."); + mu_assert_true(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 3), "Should true with 3 different characters."); + + // Look ahead goes past buffer. + mu_assert_false(rz_utf16_valid_cp(utf16be_A, sizeof(utf16be_A), true, 2), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_valid_cp(utf16be_EUR, sizeof(utf16be_EUR), true, 2), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_valid_cp(utf16be_complex, sizeof(utf16be_complex), true, 2), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_valid_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 3), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 4), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 4), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 4), "Too many code point checks for buffer."); + + mu_end; +} + bool all_tests() { mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); mu_run_test(test_rz_utf32_valid); + mu_run_test(test_rz_utf16_valid); mu_run_test(test_rz_ebcdic_valid); return tests_passed != tests_run; From ff91a443d6c2b2ffa8ccc8b67e9c084f8c6ce5f8 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 10:58:19 -0500 Subject: [PATCH 045/157] Fix check --- librz/search/string_search.c | 2 +- librz/util/utf16.c | 2 +- librz/util/utf32.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 9047fe22b78..a8f1aea3bc8 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -46,7 +46,7 @@ static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexM bool offset_found = false; *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start, &offset_found); - if (!offset_found && is_utf8_type) { + if (!offset_found) { RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); *str_mem_offset = detected->addr + group0->start; } diff --git a/librz/util/utf16.c b/librz/util/utf16.c index 57ff092f735..4b57253e4d0 100644 --- a/librz/util/utf16.c +++ b/librz/util/utf16.c @@ -119,7 +119,7 @@ RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint codepoin * \param lookahead Number of code points to check. * Note: if the buffer can't cover all \p lookahead code points, this returns false. * - * \return True if the buffer \p lookahead valid UTF-32 code points. + * \return True if the buffer has \p lookahead valid UTF-32 code points. * \return False otherwise. */ RZ_API bool rz_utf16_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { diff --git a/librz/util/utf32.c b/librz/util/utf32.c index 725a7c9abab..4f5d254b791 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -56,7 +56,7 @@ RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { * \param lookahead Number of code points to check. * Note: if the buffer can't cover all \p lookahead code points, this returns false. * - * \return True if the buffer \p lookahead valid UTF-32 code points. + * \return True if the buffer has \p lookahead valid UTF-32 code points. * \return False otherwise. */ RZ_API bool rz_utf32_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { From 39efb542193e4e11ac4b33c9725de9a407dc5130 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 12:37:54 -0500 Subject: [PATCH 046/157] Change UTF-16 code point check to printable check. --- librz/include/rz_util/rz_utf16.h | 2 +- librz/util/utf16.c | 19 +++++----- test/unit/test_encodings.c | 60 ++++++++++++++++++++------------ 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/librz/include/rz_util/rz_utf16.h b/librz/include/rz_util/rz_utf16.h index 36615a05c08..808c4213914 100644 --- a/librz/include/rz_util/rz_utf16.h +++ b/librz/include/rz_util/rz_utf16.h @@ -8,6 +8,6 @@ RZ_API size_t rz_utf16_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONN RZ_API size_t rz_utf16le_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch); RZ_API size_t rz_utf16be_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch); RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint ch); -RZ_API bool rz_utf16_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); +RZ_API bool rz_utf16_is_printable_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); #endif // RZ_UTF16_H diff --git a/librz/util/utf16.c b/librz/util/utf16.c index 4b57253e4d0..8c906461723 100644 --- a/librz/util/utf16.c +++ b/librz/util/utf16.c @@ -106,12 +106,13 @@ RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint codepoin } /** - * \brief Checks if there are valid UTF-16 code points at \p buf. - * This function does not check if the code points are defined. - * It just checks they are in a valid range according to RFC 3629. + * \brief Checks if there are \p lookahead number of printable UTF-16 code points in \p buf. * - * NOTE: Almost any byte sequence can be a valid UTF-16 code point. - * It is advisable to first check for UTF-32 and other encodings. + * NOTE: Any byte sequence >=2 bytes can be a valid UTF-16 code point. + * Hence this function checks if each code point is also printable. + * + * This takes O(lookahead * log(|Unicode Code Points|)) steps. + * It is advisable to first check for other encodings for this reason. * * \param buf The buffer to check the bytes from. * \param buf_len The buffer length. @@ -119,10 +120,10 @@ RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint codepoin * \param lookahead Number of code points to check. * Note: if the buffer can't cover all \p lookahead code points, this returns false. * - * \return True if the buffer has \p lookahead valid UTF-32 code points. + * \return True if the buffer has \p lookahead number of printable UTF-16 characters. * \return False otherwise. */ -RZ_API bool rz_utf16_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { +RZ_API bool rz_utf16_is_printable_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { rz_return_val_if_fail(buf && buf_len > 0, false); // At least 2 bytes must be given. // Buffer must cover all look aheads. @@ -133,9 +134,7 @@ RZ_API bool rz_utf16_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool bi RzCodePoint cp = 0; while (lookahead > 0) { size_t dec_bytes = rz_utf16_decode(buf + offset, buf_len - offset, &cp, big_endian); - // Largest Unicode code point is 0x10ffff, limited in RFC 3629. - bool above_max_code_point = cp > 0x10ffff; - if (above_max_code_point || dec_bytes == 0) { + if (!rz_code_point_is_printable(cp) || dec_bytes == 0) { return false; } lookahead--; diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index cdec8e477d5..4a286ca08c2 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -240,43 +240,57 @@ bool test_rz_ebcdic_valid(void) { bool test_rz_utf16_valid(void) { const ut8 utf16be_one_byte[] = { 0x00 }; const ut8 utf16be_A[] = { 0x00, 0x41 }; + const ut8 utf16be_ff[] = { 0x00, 0x00 }; const ut8 utf16be_EUR[] = { 0x20, 0xAC }; const ut8 utf16be_complex[] = { 0xD8, 0x01, 0xDC, 0x37 }; const ut8 utf16be_A_A[] = { 0x00, 0x41, 0x00, 0x41 }; const ut8 utf16be_complex_EUR_A[] = { 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC, 0x00, 0x41 }; const ut8 utf16be_complex_A_EUR[] = { 0xD8, 0x01, 0xDC, 0x37, 0x00, 0x41, 0x20, 0xAC }; const ut8 utf16be_A_complex_EUR[] = { 0x00, 0x41, 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC }; + const ut8 utf16be_invalid_complex_EUR[] = { 0x00, 0x00, 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC }; + const ut8 utf16be_complex_invalid_EUR[] = { 0xD8, 0x01, 0xDC, 0x37, 0x00, 0x00, 0x20, 0xAC }; + const ut8 utf16be_complex_EUR_invalid[] = { 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC, 0xD8, 0xff, 0xDC, 0xff }; // Simple error cases - mu_assert_false(rz_utf16_valid_cp(utf16be_A, sizeof(utf16be_A), false, 0), "lookahead == 0 is not valid."); - mu_assert_false(rz_utf16_valid_cp(utf16be_one_byte, sizeof(utf16be_one_byte), false, 1), "Buffer too small."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_A, sizeof(utf16be_A), true, 0), "lookahead == 0 is not valid."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_one_byte, sizeof(utf16be_one_byte), false, 1), "Buffer too small."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_ff, sizeof(utf16be_ff), true, 1), "Not printable."); // Simple cases. One character in buffer. - mu_assert_true(rz_utf16_valid_cp(utf16be_A, sizeof(utf16be_A), true, 1), "Should be valid"); - mu_assert_true(rz_utf16_valid_cp(utf16be_EUR, sizeof(utf16be_EUR), true, 1), "Should be valid"); - mu_assert_true(rz_utf16_valid_cp(utf16be_complex, sizeof(utf16be_complex), true, 1), "Should be valid"); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_A, sizeof(utf16be_A), true, 1), "Should be valid"); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_EUR, sizeof(utf16be_EUR), true, 1), "Should be valid"); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex, sizeof(utf16be_complex), true, 1), "Should be valid"); // Different width UTF-16 characters - mu_assert_true(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 1), "Should true with 1 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 1), "Should true with 1 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 1), "Should true with 1 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 1), "Should true with 1 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 2), "Should true with 2 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 2), "Should true with 2 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 2), "Should true with 2 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 2), "Should true with 2 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 3), "Should true with 3 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 3), "Should true with 3 different characters."); - mu_assert_true(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 3), "Should true with 3 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 1), "Should true with 1 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 2), "Should true with 2 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 3), "Should true with 3 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 3), "Should true with 3 different characters."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 3), "Should true with 3 different characters."); // Look ahead goes past buffer. - mu_assert_false(rz_utf16_valid_cp(utf16be_A, sizeof(utf16be_A), true, 2), "Too many code point checks for buffer."); - mu_assert_false(rz_utf16_valid_cp(utf16be_EUR, sizeof(utf16be_EUR), true, 2), "Too many code point checks for buffer."); - mu_assert_false(rz_utf16_valid_cp(utf16be_complex, sizeof(utf16be_complex), true, 2), "Too many code point checks for buffer."); - mu_assert_false(rz_utf16_valid_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 3), "Too many code point checks for buffer."); - mu_assert_false(rz_utf16_valid_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 4), "Too many code point checks for buffer."); - mu_assert_false(rz_utf16_valid_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 4), "Too many code point checks for buffer."); - mu_assert_false(rz_utf16_valid_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 4), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_A, sizeof(utf16be_A), true, 2), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_EUR, sizeof(utf16be_EUR), true, 2), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_complex, sizeof(utf16be_complex), true, 2), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_A_A, sizeof(utf16be_A_A), true, 3), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_complex_EUR_A, sizeof(utf16be_complex_EUR_A), true, 4), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_complex_A_EUR, sizeof(utf16be_complex_A_EUR), true, 4), "Too many code point checks for buffer."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_A_complex_EUR, sizeof(utf16be_A_complex_EUR), true, 4), "Too many code point checks for buffer."); + + mu_assert_false(rz_utf16_is_printable_cp(utf16be_invalid_complex_EUR, sizeof(utf16be_invalid_complex_EUR), true, 3), "Should fail at first."); + + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_invalid_EUR, sizeof(utf16be_complex_invalid_EUR), true, 1), "The first is still valid."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_complex_invalid_EUR, sizeof(utf16be_complex_invalid_EUR), true, 3), "Should fail before EUR."); + + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_EUR_invalid, sizeof(utf16be_complex_EUR_invalid), true, 1), "The first is still valid."); + mu_assert_true(rz_utf16_is_printable_cp(utf16be_complex_EUR_invalid, sizeof(utf16be_complex_EUR_invalid), true, 2), "The second is still valid."); + mu_assert_false(rz_utf16_is_printable_cp(utf16be_complex_EUR_invalid, sizeof(utf16be_complex_EUR_invalid), true, 3), "Should be false."); mu_end; } From 98f432d7704162779de7ff7826807ac9fc827110 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 12:48:00 -0500 Subject: [PATCH 047/157] Change UTF-16 detection method to check at least 2 characters. --- librz/util/str_search.c | 56 +++-------------------------------------- 1 file changed, 3 insertions(+), 53 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 326a52975d5..9716a768ff0 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -342,22 +342,6 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 return NULL; } -static inline bool can_be_utf16_le(const ut8 *buf, ut64 size) { - int rc = rz_utf8_decode(buf, size, NULL); - if (!rc || (size - rc) < 5) { - return false; - } - char *w = (char *)buf + rc; - return !w[0] && w[1] && !w[2] && w[3] && !w[4]; -} - -static inline bool can_be_utf16_be(const ut8 *buf, ut64 size) { - if (size < 7) { - return false; - } - return !buf[0] && buf[1] && !buf[2] && buf[3] && !buf[4] && buf[5] && !buf[6]; -} - /** * \brief Look for strings in a byte array, but returns only the first result. * @@ -422,8 +406,6 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 3) { // The string can be either utf32-le or utf32-be @@ -460,41 +442,9 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 1 && can_be_utf16_le(ptr + 1, size - 1)) { - // The string can be either utf16-le or utf16-be - RzDetectedString *ds_le = process_one_string(buf, from, needle + 1, to, RZ_STRING_ENC_UTF16LE, false, opt); - RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF16BE, false, opt); - - RzDetectedString *to_add = NULL; - RzDetectedString *to_delete = NULL; - ut64 needle_offset = 0; - - if (!ds_le && !ds_be) { - needle++; - continue; - } else if (!ds_be) { - to_add = ds_le; - needle_offset = ds_le->size + 1; - } else if (!ds_le) { - to_add = ds_be; - needle_offset = ds_be->size; - } else if (!opt->prefer_big_endian) { - to_add = ds_le; - to_delete = ds_be; - needle_offset = ds_le->size + 1; - } else { - to_add = ds_be; - to_delete = ds_le; - needle_offset = ds_le->size; - } - - count++; - needle += needle_offset; - rz_list_append(list, to_add); - rz_detected_string_free(to_delete); - continue; - } + } else if (rz_utf16_is_printable_cp(ptr, size, false, 2)) { + str_type = RZ_STRING_ENC_UTF16LE; + } else if (rz_utf16_is_printable_cp(ptr, size, true, 2)) { str_type = RZ_STRING_ENC_UTF16BE; } else if (rz_str_ebcdic_valid_cp(ptr[0]) && skip_ibm037 < 0) { ut8 sz = RZ_MIN(size, 15); From 39df4278c076a70f55ccf768f3b34c19814a5e08 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 12:57:38 -0500 Subject: [PATCH 048/157] Remove unecessary code after string detection is now more precise. --- librz/util/str_search.c | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 9716a768ff0..e566120aae9 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -407,46 +407,12 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 3) { - // The string can be either utf32-le or utf32-be - RzDetectedString *ds_le = process_one_string(buf, from, needle + 3, to, RZ_STRING_ENC_UTF32LE, false, opt); - RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF32BE, false, opt); - - RzDetectedString *to_add = NULL; - RzDetectedString *to_delete = NULL; - ut64 needle_offset = 0; - - if (!ds_le && !ds_be) { - needle++; - continue; - } else if (!ds_be) { - to_add = ds_le; - needle_offset = ds_le->size + 3; - } else if (!ds_le) { - to_add = ds_be; - needle_offset = ds_be->size; - } else if (!opt->prefer_big_endian) { - to_add = ds_le; - to_delete = ds_be; - needle_offset = ds_le->size + 3; - } else { - to_add = ds_be; - to_delete = ds_le; - needle_offset = ds_le->size; - } - - count++; - needle += needle_offset; - rz_list_append(list, to_add); - rz_detected_string_free(to_delete); - continue; - } str_type = RZ_STRING_ENC_UTF32BE; } else if (rz_utf16_is_printable_cp(ptr, size, false, 2)) { str_type = RZ_STRING_ENC_UTF16LE; } else if (rz_utf16_is_printable_cp(ptr, size, true, 2)) { str_type = RZ_STRING_ENC_UTF16BE; - } else if (rz_str_ebcdic_valid_cp(ptr[0]) && skip_ibm037 < 0) { + } else if (skip_ibm037 < 0 && rz_str_ebcdic_valid_cp(ptr[0])) { ut8 sz = RZ_MIN(size, 15); RzCodePoint code_points[15] = { 0 }; int i = 0; From b0561cd92d40222daef67dc98a9fd966af90b6c6 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 13:03:45 -0500 Subject: [PATCH 049/157] Add macro for last unicode code point. --- librz/include/rz_util/rz_utf8.h | 2 ++ librz/util/utf32.c | 2 +- librz/util/utf8.c | 2 +- test/unit/test_encodings.c | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/librz/include/rz_util/rz_utf8.h b/librz/include/rz_util/rz_utf8.h index d005bf599e0..d4ce805edd5 100644 --- a/librz/include/rz_util/rz_utf8.h +++ b/librz/include/rz_util/rz_utf8.h @@ -9,6 +9,8 @@ typedef struct { const char *name; } RUtfBlock; +#define LAST_UNICODE_CODE_POINT 0x10ffff + /** * \brief An Unicode code point. */ diff --git a/librz/util/utf32.c b/librz/util/utf32.c index 4f5d254b791..b53b91ee590 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -72,7 +72,7 @@ RZ_API bool rz_utf32_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool bi // UTF-16 surrogates are forbitten code points as of RFC 3629. bool is_utf16_surregate = cp >= 0xd800 && cp <= 0xdfff; // Largest Unicode code point is 0x10ffff, also limited in RFC 3629. - bool above_max_code_point = cp > 0x10ffff; + bool above_max_code_point = cp > LAST_UNICODE_CODE_POINT; if (is_utf16_surregate || above_max_code_point) { return false; } diff --git a/librz/util/utf8.c b/librz/util/utf8.c index ff5ead9fb02..4f1d114763f 100644 --- a/librz/util/utf8.c +++ b/librz/util/utf8.c @@ -517,7 +517,7 @@ RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { if (ch) { *ch = code_point; } - return code_point < 0x10000 ? 0 : 4; + return code_point > LAST_UNICODE_CODE_POINT ? 0 : 4; } return 0; } diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 4a286ca08c2..d6d322088ac 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -86,14 +86,14 @@ bool test_rz_utf16_decode(void) { nbytes = rz_utf16_decode(utf16le_last_surr, 4, &codepoint, false); mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_eq_fmt(codepoint, 0x10FFFF, "Character decode failed.", "0x%" PFMT64x); + mu_assert_eq_fmt(codepoint, LAST_UNICODE_CODE_POINT, "Character decode failed.", "0x%" PFMT64x); rz_utf8_encode((ut8 *)utf8_out, codepoint); mu_assert_streq(utf8_out, "􏿿", "Encode failed."); memset(utf8_out, 0, sizeof(utf8_out)); nbytes = rz_utf16_decode(utf16be_last_surr, 4, &codepoint, true); mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_eq_fmt(codepoint, 0x10FFFF, "Character decode failed.", "0x%" PFMT64x); + mu_assert_eq_fmt(codepoint, LAST_UNICODE_CODE_POINT, "Character decode failed.", "0x%" PFMT64x); rz_utf8_encode((ut8 *)utf8_out, codepoint); mu_assert_streq(utf8_out, "􏿿", "Encode failed."); memset(utf8_out, 0, sizeof(utf8_out)); @@ -162,7 +162,7 @@ bool test_rz_utf16_encode(void) { memset(utf16_out, 0, sizeof(utf16_out)); const ut8 utf16le_last_surr[] = { 0xFF, 0xDB, 0xFF, 0xDF }; - codepoint = 0x10FFFF; + codepoint = LAST_UNICODE_CODE_POINT; nbytes = rz_utf16le_encode(utf16_out, codepoint); mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); mu_assert_memeq(utf16_out, utf16le_last_surr, sizeof(utf16le), "Encode failed."); From 030ae28f0b4fce35f718cca807450f52330b81a9 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 14:22:37 -0500 Subject: [PATCH 050/157] Fix alignment of UTF-8 strings to their memory representation. Add a distinction between strings added to the list and save their offsets separately. --- librz/include/rz_util/rz_str_search.h | 23 ++++++++++++++++---- librz/search/string_search.c | 31 ++++++--------------------- librz/util/str_search.c | 9 ++++---- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index b17abf123fc..f0f99c18d18 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -35,11 +35,26 @@ typedef struct { bool check_ascii_freq; ///< If true, perform check on ASCII frequencies when looking for false positives /** * \brief Map UTF-8 byte offsets to memory offsets. - * The scan function always returns UTF-8 strings. - * Independent what encoding the strings are in memory. + * The string scan function always returns UTF-8 strings. + * Independent what encoding the strings have in memory. * Sometimes it is necessary to know the offsets of the real encoding. - * This maps a UTF-8 code point offset to the original code point offset (possibly of another encoding). - * Indices are always aligned to code points. + * This maps an UTF-8 code point offset to the original code point offset in memory. + * The keys are ut64 values. With the upper 32bits holding the index into the + * "detected string list" returned by rz_scan_strings_whole_buf(). + * The lower 32bits are the offset into the UTF-8 string. + * The value is the offset into the memory. Relevant to the buffer + * The string was found in. + * + * Example: + * + * Buffer (UTF-16): 0x00, 0x41, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x42 + * Found strings (UTF-8): [ "AA", "BB" ] + * Map: { + * 0x0000000000000000: 0, + * 0x0000000000000001: 2, + * 0x0000000100000000: 6, + * 0x0000000100000001: 8 + * } */ RZ_NULLABLE HtUU *utf8_to_mem_offset_map; } RzUtilStrScanOptions; diff --git a/librz/search/string_search.c b/librz/search/string_search.c index a8f1aea3bc8..8fa13b6c566 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -21,36 +21,15 @@ typedef struct string_search { * For example, if the real string is UTF-16 or UTF-32. * Here we set the real (in memory encoded) string offsets and string length. */ -static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len) { - bool is_utf8_type = detected->type == RZ_STRING_ENC_UTF8 || detected->type == RZ_STRING_ENC_8BIT; - if (is_utf8_type) { - // The memory is aligned. - *str_mem_offset = detected->addr + group0->start; - *str_mem_len = group0->len; - // For UTF-8 types we have to free the offset map and set it to an empty one. - // Because the string scan does multiple attempts to parse the same offset in the memory - // with multiple encodings (although it already found a valid string). - // This messes up this naive offset map (index 0 is overwritten - // multiple times with an invalid index). - // Until the string parsing is cleared up, this work-around hopefully does - // its job. - // If you need to debug it, just remove this condition and - // run the cmd_search_z tests. You will see the warnings. - if (ss->options.utf8_to_mem_offset_map) { - ht_uu_free(ss->options.utf8_to_mem_offset_map); - ss->options.utf8_to_mem_offset_map = ht_uu_new(); - } - return; - } - +static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len, ut64 found_idx) { bool offset_found = false; - *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start, &offset_found); + *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start), &offset_found); if (!offset_found) { RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); *str_mem_offset = detected->addr + group0->start; } - *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, detected->addr + group0->start + group0->len, &offset_found) - *str_mem_offset; + *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &offset_found) - *str_mem_offset; if (!offset_found) { RZ_LOG_WARN("Could not determine length of string in memory. String length will be off.\n"); *str_mem_len = group0->len; @@ -77,6 +56,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs return false; } + ut64 found_idx = 0; rz_list_foreach (found, it_s, detected) { void **it_m = NULL; rz_pvector_foreach (ss->strings, it_m) { @@ -94,7 +74,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs } ut64 str_mem_len; ut64 str_mem_offset; - align_offsets(ss, detected, group0, &str_mem_offset, &str_mem_len); + align_offsets(ss, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); RzSearchHit *hit = rz_search_hit_new("string", str_mem_offset, str_mem_len); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); @@ -105,6 +85,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs } rz_pvector_free(matches); } + found_idx++; } ht_uu_free(ss->options.utf8_to_mem_offset_map); diff --git a/librz/util/str_search.c b/librz/util/str_search.c index e566120aae9..9e5fc4777a7 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -208,7 +208,7 @@ static ut64 adjust_offset(RzStrEnc str_type, const ut8 *buf, const ut64 str_star } static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut64 needle, const ut64 to, - RzStrEnc str_type, bool ascii_only, const RzUtilStrScanOptions *opt) { + RzStrEnc str_type, bool ascii_only, const RzUtilStrScanOptions *opt, ut64 str_list_idx) { rz_return_val_if_fail(str_type != RZ_STRING_ENC_GUESS, NULL); if (opt->buf_size < 5) { RZ_LOG_ERROR("This function assumes a buffer size of at least 5 bytes."); @@ -282,7 +282,8 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 } if (opt->utf8_to_mem_offset_map) { - ht_uu_insert(opt->utf8_to_mem_offset_map, i, needle); + ut64 offset_id = ((str_list_idx) << 32) | i; + ht_uu_insert(opt->utf8_to_mem_offset_map, offset_id, needle); } needle += rc; @@ -316,7 +317,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 goto error; } else if (false_positive_result == RETRY_ASCII) { free(strbuf); - return process_one_string(buf, from, str_addr, to, str_type, true, opt); + return process_one_string(buf, from, str_addr, to, str_type, true, opt, str_list_idx); } RzDetectedString *ds = RZ_NEW0(RzDetectedString); @@ -442,7 +443,7 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* Date: Wed, 29 Jan 2025 14:23:03 -0500 Subject: [PATCH 051/157] Add extended regex string search on UTF-32LE strings. --- test/db/cmd/cmd_search_z | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index ee1d20a4b75..9776c4acae7 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -900,3 +900,21 @@ EXPECT=< Date: Wed, 29 Jan 2025 14:31:30 -0500 Subject: [PATCH 052/157] Make process_on_string independent on buffer size. --- librz/util/str_search.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 9e5fc4777a7..d8b4f001960 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -207,11 +207,27 @@ static ut64 adjust_offset(RzStrEnc str_type, const ut8 *buf, const ut64 str_star return 0; } +static inline size_t buf_look_ahead(const RzUtilStrScanOptions *opt, RzStrEnc enc) { + if (opt->buf_size < opt->min_str_length) { + return 0; + } + switch (enc) { + default: + return 1; + case RZ_STRING_ENC_UTF16BE: + case RZ_STRING_ENC_UTF16LE: + return 2; + case RZ_STRING_ENC_UTF32BE: + case RZ_STRING_ENC_UTF32LE: + return 4; + } +} + static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut64 needle, const ut64 to, RzStrEnc str_type, bool ascii_only, const RzUtilStrScanOptions *opt, ut64 str_list_idx) { rz_return_val_if_fail(str_type != RZ_STRING_ENC_GUESS, NULL); - if (opt->buf_size < 5) { - RZ_LOG_ERROR("This function assumes a buffer size of at least 5 bytes."); + size_t look_ahead = buf_look_ahead(opt, str_type); + if (look_ahead == 0) { return NULL; } @@ -224,7 +240,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 int rc = 0, i = 0, runes = 0; /* Eat a whole C string */ - for (i = 0; i < opt->buf_size - 4 && needle < to; i += rc) { + for (i = 0; i < opt->buf_size - look_ahead && needle < to; i += rc) { RzCodePoint r = 0; switch(str_type) { From 35461e9080b3818cfa317c90a9253c83326a012a Mon Sep 17 00:00:00 2001 From: Rot127 Date: Wed, 29 Jan 2025 14:57:39 -0500 Subject: [PATCH 053/157] Skip offset map if strings are expected to be UTF-8 anyways. --- librz/include/rz_util/rz_str.h | 4 ++++ librz/search/string_search.c | 18 +++++++++++++++--- librz/util/str_search.c | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index fb4db7c3258..511c0bf0c09 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -279,6 +279,10 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU RZ_API const char *rz_str_indent(int indent); +static inline bool rz_string_enc_is_utf8_compatible(RzStrEnc enc) { + return enc == RZ_STRING_ENC_UTF8 || enc == RZ_STRING_ENC_8BIT; +} + #ifdef __cplusplus } #endif diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 8fa13b6c566..dabad62120d 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -22,16 +22,28 @@ typedef struct string_search { * Here we set the real (in memory encoded) string offsets and string length. */ static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len, ut64 found_idx) { + if (rz_string_enc_is_utf8_compatible(ss->encoding)) { + *str_mem_offset = detected->addr + group0->start; + *str_mem_len = group0->len; + return; + } + bool offset_found = false; + bool len_found = false; *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start), &offset_found); if (!offset_found) { RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); *str_mem_offset = detected->addr + group0->start; } - *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &offset_found) - *str_mem_offset; - if (!offset_found) { - RZ_LOG_WARN("Could not determine length of string in memory. String length will be off.\n"); + *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &len_found) - *str_mem_offset; + if (!len_found) { + if (!offset_found) { + // If the previous offset was not found, we know something is broken. + // If it was found on the ohter hand, the string is exactly as long as the whole buffer. + // So `start + len` is OOB and hence not in the hash table. + RZ_LOG_WARN("Could not determine length of string in memory. String length will be off.\n"); + } *str_mem_len = group0->len; } } diff --git a/librz/util/str_search.c b/librz/util/str_search.c index d8b4f001960..26e889147e1 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -297,7 +297,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 break; } - if (opt->utf8_to_mem_offset_map) { + if (opt->utf8_to_mem_offset_map && !rz_string_enc_is_utf8_compatible(str_type)) { ut64 offset_id = ((str_list_idx) << 32) | i; ht_uu_insert(opt->utf8_to_mem_offset_map, offset_id, needle); } From 66f7ea6601dadcffb1d8556dc174c3ee664685a2 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 30 Jan 2025 08:59:19 -0500 Subject: [PATCH 054/157] Set thread number to maximum CPU cores, not threads. --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index e7e924ecc5d..bdba09c2fca 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1132,7 +1132,7 @@ static bool cb_str_search_max_threads(void *user, void *data) { static bool cb_search_max_threads(void *user, void *data) { RzConfigNode *node = (RzConfigNode *)data; - RzThreadNCores max_threads = rz_th_max_threads(node->i_value); + RzThreadNCores max_threads = rz_th_physical_core_number();; if (node->value[0] == '?') { rz_cons_printf("%d\n", max_threads); return false; From 725af0d07d6231f8b63bb1d4f7c70b7353837055 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 30 Jan 2025 09:01:00 -0500 Subject: [PATCH 055/157] Remove duplicate if condition. --- librz/util/str.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/librz/util/str.c b/librz/util/str.c index a56f4f90c8f..9bce3d0f188 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4177,9 +4177,10 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU rsize = rz_utf8_decode(&buf[i], buflen - i, &code_point); } - if (rsize == 0 && option->stop_at_unprintable) { - break; - } else if (rsize == 0) { + if (rsize == 0) { + if (option->stop_at_unprintable) { + break; + } switch (enc) { case RZ_STRING_ENC_UTF32LE: rsize = RZ_MIN(4, buflen - i); From 817554e897015703be3926154fcc9c1264203c19 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 30 Jan 2025 09:09:37 -0500 Subject: [PATCH 056/157] Remove unused str.search.max_threads all together. --- librz/core/cconfig.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index bdba09c2fca..d22e5ad2353 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1118,23 +1118,10 @@ static bool cb_str_escbslash(void *user, void *data) { return true; } -static bool cb_str_search_max_threads(void *user, void *data) { - RzCore *core = (RzCore *)user; - RzConfigNode *node = (RzConfigNode *)data; - RzThreadNCores max_threads = rz_th_max_threads(node->i_value); - if (node->value[0] == '?') { - rz_cons_printf("%d\n", max_threads); - return false; - } - core->bin->str_search_cfg.max_threads = max_threads; - return true; -} - static bool cb_search_max_threads(void *user, void *data) { RzConfigNode *node = (RzConfigNode *)data; - RzThreadNCores max_threads = rz_th_physical_core_number();; if (node->value[0] == '?') { - rz_cons_printf("%d\n", max_threads); + rz_cons_printf("Available cores: %d\n", rz_th_physical_core_number()); return false; } return true; @@ -3762,7 +3749,6 @@ RZ_API int rz_core_config_init(RzCore *core) { /* string search options */ SETB("str.search.reload", true, "When enabled, any change to any option `str.search.*` will reload the bin strings."); - SETICB("str.search.max_threads", RZ_THREAD_N_CORES_ALL_AVAILABLE, &cb_str_search_max_threads, "Maximum core number (0 for all cores)."); SETICB("str.search.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_str_search_min_length, "Smallest string length that is possible to find."); SETICB("str.search.buffer_size", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_str_search_buffer_size, "Maximum buffer size, which will also determine the maximum string length."); SETICB("str.search.max_uni_blocks", RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS, &cb_str_search_max_uni_blocks, "Maximum number of unicode blocks."); From d8414376961a22fc56da26f2e4b2a777aaad53ed Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 30 Jan 2025 10:47:31 -0500 Subject: [PATCH 057/157] Fix OOB write for UTF8 strings. --- librz/util/str_search.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 26e889147e1..a580fafee9a 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -212,13 +212,14 @@ static inline size_t buf_look_ahead(const RzUtilStrScanOptions *opt, RzStrEnc en return 0; } switch (enc) { - default: + case RZ_STRING_ENC_8BIT: return 1; case RZ_STRING_ENC_UTF16BE: case RZ_STRING_ENC_UTF16LE: return 2; case RZ_STRING_ENC_UTF32BE: case RZ_STRING_ENC_UTF32LE: + default: return 4; } } From baaf7c7afbe6a62477e627fe5929ca354fb95613 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 30 Jan 2025 11:20:20 -0500 Subject: [PATCH 058/157] Add ability to print any supported string encoding with 'ps'. By default it prints the one set in str.search.encoding. --- librz/core/cconfig.c | 6 ++- librz/core/cmd/cmd_print.c | 81 +++++------------------------ librz/core/cmd_descs/cmd_descs.c | 47 ++++++++++++----- librz/core/cmd_descs/cmd_descs.h | 2 +- librz/core/cmd_descs/cmd_print.yaml | 40 +++++++++++--- librz/include/rz_util/rz_str.h | 1 + librz/util/str.c | 7 ++- librz/util/str_search.c | 6 +++ test/db/cmd/cmd_ps | 49 ++++++++++++++--- test/db/cmd/cmd_wox | 8 +-- 10 files changed, 143 insertions(+), 104 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index d22e5ad2353..974df61e6c2 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "core_private.h" @@ -1252,13 +1253,14 @@ static bool cb_str_search_encoding(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; RzStrEnc encoding = RZ_STRING_ENC_GUESS; + bool found_enc = find_encoding(node, &encoding); if (node->value[0] == '?') { print_node_options(node); rz_cons_printf(" -- if string's 2nd & 4th bytes are 0 then utf16le else " "if 2nd - 4th & 6th bytes are 0 & no char > 0x10ffff then utf32le else " "if utf8 char detected then utf8 else 8bit\n"); return false; - } else if (rz_str_casecmp("guess", node->value) && !find_encoding(node, &encoding)) { + } else if (RZ_STR_EQ("settings", node->value) || (rz_str_casecmp("guess", node->value) && !found_enc)) { RZ_LOG_ERROR("Invalid value for str.search.encoding (%s).\n", node->value); return false; } @@ -3757,7 +3759,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETICB("str.search.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_str_search_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); n = NODECB("str.search.encoding", "guess", &cb_str_search_encoding); SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); - SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "guess", NULL); + SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); n = NODECB("str.search.mode", "auto", &cb_str_search_mode); SETDESC(n, "String search mode which can override how strings are found (auto, rosections or raw)"); SETOPTIONS(n, "auto", "rosections", "raw", NULL); diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 55cd5eba2d7..4b4148f5659 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -9,7 +9,6 @@ #include #include "../core_private.h" -#include #define PF_USAGE_STR "pf[.k[.f[=v]]|[v]]|[n]|[0|cnt][fmt] [a0 a1 ...]" @@ -2084,10 +2083,10 @@ static void core_print_raw_buffer(RzStrStringifyOpt *opt) { } } -static RzCmdStatus core_auto_detect_and_print_string(RzCore *core, bool stop_at_nil, ut32 offset, RzOutputMode mode) { +static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, ut32 offset, RzOutputMode mode, RzStrEnc str_encoding) { const ut8 *buffer = core->block + offset; const ut32 length = core->blocksize - offset; - RzStrEnc encoding = core->bin->str_search_cfg.string_encoding; + RzStrEnc encoding = str_encoding == RZ_STRING_ENC_SETTINGS ? core->bin->str_search_cfg.string_encoding : str_encoding; RzStrStringifyOpt opt = { 0 }; if (encoding == RZ_STRING_ENC_GUESS) { @@ -2113,9 +2112,10 @@ static RzCmdStatus core_auto_detect_and_print_string(RzCore *core, bool stop_at_ return RZ_CMD_STATUS_OK; } -RZ_IPI RzCmdStatus rz_print_string_auto_detect_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - bool stop_at_nil = !strcmp(argv[1], "null"); - return core_auto_detect_and_print_string(core, stop_at_nil, 0, mode); +RZ_IPI RzCmdStatus rz_print_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + bool stop_at_nil = !strcmp(argv[2], "null"); + RzStrEnc enc = rz_str_enc_string_as_type(argv[1]); + return core_print_string_in_block(core, stop_at_nil, 0, mode, enc); } RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { @@ -2147,12 +2147,12 @@ RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int ar rz_core_seek(core, new_offset, SEEK_SET); rz_core_block_read(core); - status = core_auto_detect_and_print_string(core, true, 0, mode); + status = core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_SETTINGS); rz_core_seek(core, old_offset, SEEK_SET); rz_core_block_read(core); } else { - status = core_auto_detect_and_print_string(core, true, 1, mode); + status = core_print_string_in_block(core, true, 1, mode, RZ_STRING_ENC_SETTINGS); } return status; @@ -2663,78 +2663,23 @@ RZ_API void rz_print_offset(RzPrint *p, ut64 off, int invert, int offseg, int of } RZ_IPI RzCmdStatus rz_print_utf8_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF8, true, true); - } else { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = RZ_STRING_ENC_UTF8; - opt.stop_at_nil = true; - opt.stop_at_unprintable = true; - core_print_raw_buffer(&opt); - } - return RZ_CMD_STATUS_OK; + return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF8); } RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16LE, true, true); - } else { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = RZ_STRING_ENC_UTF16LE; - opt.stop_at_nil = true; - opt.stop_at_unprintable = true; - core_print_raw_buffer(&opt); - } - return RZ_CMD_STATUS_OK; + return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF16LE); } RZ_IPI RzCmdStatus rz_print_utf32le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF32LE, true, true); - } else { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = RZ_STRING_ENC_UTF32LE; - opt.stop_at_nil = true; - opt.stop_at_unprintable = true; - core_print_raw_buffer(&opt); - } - return RZ_CMD_STATUS_OK; + return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF32LE); } RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF16BE, true, true); - } else { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = RZ_STRING_ENC_UTF16BE; - opt.stop_at_nil = true; - opt.stop_at_unprintable = true; - core_print_raw_buffer(&opt); - } - return RZ_CMD_STATUS_OK; + return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF16BE); } RZ_IPI RzCmdStatus rz_print_utf32be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - if (mode == RZ_OUTPUT_MODE_JSON) { - print_json_string(core, core->block, core->blocksize, RZ_STRING_ENC_UTF32BE, true, true); - } else { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = RZ_STRING_ENC_UTF32BE; - opt.stop_at_nil = true; - opt.stop_at_unprintable = true; - core_print_raw_buffer(&opt); - } - return RZ_CMD_STATUS_OK; + return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF32BE); } RZ_IPI RzCmdStatus rz_print_hexdump_annotated_handler(RzCore *core, int argc, const char **argv) { diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index cc642e612c1..4d74aaae787 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -70,6 +70,7 @@ static const RzCmdDescDetail cmd_info_query_details[2]; static const RzCmdDescDetail query_sdb_get_set_details[2]; static const RzCmdDescDetail cmd_print_byte_array_details[3]; static const RzCmdDescDetail pf_details[3]; +static const RzCmdDescDetail print_string_details[2]; static const RzCmdDescDetail print_rising_and_falling_entropy_details[2]; static const RzCmdDescDetail interactive_visual_details[2]; static const RzCmdDescDetail write_details[3]; @@ -696,7 +697,7 @@ static const RzCmdDescArg print_operation_xor_args[2]; static const RzCmdDescArg cmd_print_raw_args[2]; static const RzCmdDescArg cmd_print_raw_colors_args[2]; static const RzCmdDescArg cmd_print_raw_string_args[2]; -static const RzCmdDescArg print_string_auto_detect_args[2]; +static const RzCmdDescArg print_string_args[3]; static const RzCmdDescArg print_pascal_string_args[2]; static const RzCmdDescArg print_value_args[2]; static const RzCmdDescArg print_value1_args[2]; @@ -15271,20 +15272,40 @@ static const RzCmdDescHelp cmd_print_raw_string_help = { static const RzCmdDescHelp ps_help = { .summary = "Print string at the current offset", }; -static const char *print_string_auto_detect_delimiter_choices[] = { "null", "block", NULL }; -static const RzCmdDescArg print_string_auto_detect_args[] = { +static const RzCmdDescDetailEntry print_string_Value_space_details_detail_entries[] = { + { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'str.search.encoding' option." }, + { .text = "delimeter=null", .arg_str = NULL, .comment = "String is NUL terminated." }, + { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string." }, + { 0 }, +}; +static const RzCmdDescDetail print_string_details[] = { + { .name = "Value details", .entries = print_string_Value_space_details_detail_entries }, + { 0 }, +}; +static const char *print_string_encoding_choices[] = { "settings", "guess", "ascii", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; + +static const char *print_string_delimiter_choices[] = { "null", "block", NULL }; +static const RzCmdDescArg print_string_args[] = { + { + .name = "encoding", + .type = RZ_CMD_ARG_TYPE_CHOICES, + .default_value = "settings", + .choices.choices = print_string_encoding_choices, + + }, { .name = "delimiter", .type = RZ_CMD_ARG_TYPE_CHOICES, .default_value = "null", - .choices.choices = print_string_auto_detect_delimiter_choices, + .choices.choices = print_string_delimiter_choices, }, { 0 }, }; -static const RzCmdDescHelp print_string_auto_detect_help = { - .summary = "Print the autodetected string at the current offset (null->zero-terminated, block->block-terminated)", - .args = print_string_auto_detect_args, +static const RzCmdDescHelp print_string_help = { + .summary = "Print the string at the current offset (null->zero-terminated, block->block-terminated).", + .details = print_string_details, + .args = print_string_args, }; static const RzCmdDescArg print_string_as_libcpp_string_args[] = { @@ -15347,7 +15368,7 @@ static const RzCmdDescArg print_utf8_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf8_help = { - .summary = "Print buffer as a utf8 string", + .summary = "Print buffer as a utf8 string (alias for 'ps utf8 null').", .args = print_utf8_args, }; @@ -15355,7 +15376,7 @@ static const RzCmdDescArg print_utf16be_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf16be_help = { - .summary = "Print buffer as a utf16be string", + .summary = "Print buffer as a utf16be string (alias for 'ps utf16le null').", .args = print_utf16be_args, }; @@ -15363,7 +15384,7 @@ static const RzCmdDescArg print_utf32be_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf32be_help = { - .summary = "Print buffer as a utf32be string", + .summary = "Print buffer as a utf32be string (alias for 'ps utf32be null').", .args = print_utf32be_args, }; @@ -15379,7 +15400,7 @@ static const RzCmdDescArg print_utf16le_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf16le_help = { - .summary = "Print buffer as a utf16le string", + .summary = "Print buffer as a utf16le string (alias for 'ps utf32le null').", .args = print_utf16le_args, }; @@ -15387,7 +15408,7 @@ static const RzCmdDescArg print_utf32le_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf32le_help = { - .summary = "Print buffer as a utf32le string", + .summary = "Print buffer as a utf32le string (alias for 'ps utf32le null').", .args = print_utf32le_args, }; @@ -23148,7 +23169,7 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_print_raw_string_cd = rz_cmd_desc_argv_new(core->rcmd, pr_cd, "prz", rz_cmd_print_raw_string_handler, &cmd_print_raw_string_help); rz_warn_if_fail(cmd_print_raw_string_cd); - RzCmdDesc *ps_cd = rz_cmd_desc_group_modes_new(core->rcmd, cmd_print_cd, "ps", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_print_string_auto_detect_handler, &print_string_auto_detect_help, &ps_help); + RzCmdDesc *ps_cd = rz_cmd_desc_group_modes_new(core->rcmd, cmd_print_cd, "ps", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_print_string_handler, &print_string_help, &ps_help); rz_warn_if_fail(ps_cd); RzCmdDesc *print_string_as_libcpp_string_cd = rz_cmd_desc_argv_modes_new(core->rcmd, ps_cd, "ps+", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_print_string_as_libcpp_string_handler, &print_string_as_libcpp_string_help); rz_warn_if_fail(print_string_as_libcpp_string_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 2d8cc5877d0..257709ba498 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -2067,7 +2067,7 @@ RZ_IPI RzCmdStatus rz_cmd_print_raw_printable_handler(RzCore *core, int argc, co // "prz" RZ_IPI RzCmdStatus rz_cmd_print_raw_string_handler(RzCore *core, int argc, const char **argv); // "ps" -RZ_IPI RzCmdStatus rz_print_string_auto_detect_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); +RZ_IPI RzCmdStatus rz_print_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "ps+" RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "psb" diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index ce31136ddbe..6ceda50b8d8 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1097,16 +1097,42 @@ commands: summary: Print string at the current offset subcommands: - name: ps - summary: Print the autodetected string at the current offset (null->zero-terminated, block->block-terminated) - cname: print_string_auto_detect + summary: Print the string at the current offset (null->zero-terminated, block->block-terminated). + cname: print_string modes: - RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_JSON args: + - name: encoding + type: RZ_CMD_ARG_TYPE_CHOICES + default_value: "settings" + choices: + - "settings" + - "guess" + - "ascii" + - "utf8" + - "utf16le" + - "utf32le" + - "utf16be" + - "utf32be" + - "ibm037" + - "ibm290" + - "ebcdices" + - "ebcdicuk" + - "ebcdicus" - name: delimiter type: RZ_CMD_ARG_TYPE_CHOICES default_value: "null" choices: ["null", "block"] + details: + - name: Value details + entries: + - text: "encoding=settings" + comment: "Use encoding from 'str.search.encoding' option." + - text: "delimeter=null" + comment: "String is NUL terminated." + - text: "delimeter=block" + comment: "Print whole block as string." - name: ps+ summary: Print libc++ std::string (same-endian, ascii, zero-terminated) cname: print_string_as_libcpp_string @@ -1151,21 +1177,21 @@ commands: - RZ_OUTPUT_MODE_STANDARD args: [] - name: psu - summary: Print buffer as a utf8 string + summary: Print buffer as a utf8 string (alias for 'ps utf8 null'). cname: print_utf8 modes: - RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_JSON args: [] - name: psm - summary: Print buffer as a utf16be string + summary: Print buffer as a utf16be string (alias for 'ps utf16le null'). cname: print_utf16be modes: - RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_JSON args: [] - name: psM - summary: Print buffer as a utf32be string + summary: Print buffer as a utf32be string (alias for 'ps utf32be null'). cname: print_utf32be modes: - RZ_OUTPUT_MODE_STANDARD @@ -1179,14 +1205,14 @@ commands: - RZ_OUTPUT_MODE_JSON args: [] - name: psw - summary: Print buffer as a utf16le string + summary: Print buffer as a utf16le string (alias for 'ps utf32le null'). cname: print_utf16le modes: - RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_JSON args: [] - name: psW - summary: Print buffer as a utf32le string + summary: Print buffer as a utf32le string (alias for 'ps utf32le null'). cname: print_utf32le modes: - RZ_OUTPUT_MODE_STANDARD diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index 511c0bf0c09..c88dcbbca15 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -31,6 +31,7 @@ typedef enum { RZ_STRING_ENC_EBCDIC_US = 's', RZ_STRING_ENC_EBCDIC_ES = 't', RZ_STRING_ENC_GUESS = 'g', + RZ_STRING_ENC_SETTINGS = 'S', ///< Use str.search.encoding. } RzStrEnc; /** diff --git a/librz/util/str.c b/librz/util/str.c index 9bce3d0f188..bc187222327 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4,10 +4,9 @@ #include #include "rz_list.h" #include "rz_types.h" -#include "rz_util.h" +#include #include "rz_cons.h" #include "rz_bin.h" -#include "rz_util/rz_assert.h" #include #include #include @@ -72,6 +71,8 @@ RZ_API const char *rz_str_enc_as_string(RzStrEnc enc) { return "ebcdicus"; case RZ_STRING_ENC_GUESS: return "guessed"; + case RZ_STRING_ENC_SETTINGS: + return "str.search.encoding"; default: rz_warn_if_reached(); return "unknown"; @@ -111,6 +112,8 @@ RZ_API RzStrEnc rz_str_enc_string_as_type(RZ_NULLABLE const char *encoding) { return RZ_STRING_ENC_EBCDIC_UK; } else if (!strcmp(encoding, "ebcdicus")) { return RZ_STRING_ENC_EBCDIC_US; + } else if (!strcmp(encoding, "settings")) { + return RZ_STRING_ENC_SETTINGS; } else if (!strcmp(encoding, "base64")) { return RZ_STRING_ENC_BASE64; } diff --git a/librz/util/str_search.c b/librz/util/str_search.c index a580fafee9a..33a44b48fc1 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2021 borzacchiello // SPDX-License-Identifier: LGPL-3.0-only +#include +#include #include #include #include @@ -284,6 +286,10 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 case RZ_STRING_ENC_EBCDIC_US: rc = rz_str_ebcdic_us_to_unicode(*(buf + needle - from), &r); break; + case RZ_STRING_ENC_SETTINGS: + rz_warn_if_reached(); + RZ_LOG_ERROR("Illegal state reached. 'settings' encoding is not a valid value here.\n"); + return NULL; default: rc = rz_utf8_decode(buf + needle - from, to - needle, &r); if (rc > 1) { diff --git a/test/db/cmd/cmd_ps b/test/db/cmd/cmd_ps index f097a6418cb..a8247c9c900 100644 --- a/test/db/cmd/cmd_ps +++ b/test/db/cmd/cmd_ps @@ -66,11 +66,11 @@ RUN NAME=ps N and initial nulls (#10037) FILE== CMDS=< Date: Thu, 30 Jan 2025 12:29:01 -0500 Subject: [PATCH 059/157] Fix: Rename last RzRune occurrances. --- librz/include/rz_util/rz_utf16.h | 2 +- librz/include/rz_util/rz_utf32.h | 2 +- librz/util/ebcdic.c | 24 ++++++++++++------------ librz/util/utf32.c | 6 +++--- librz/util/utf8.c | 14 +++++++------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/librz/include/rz_util/rz_utf16.h b/librz/include/rz_util/rz_utf16.h index 808c4213914..cd708d0c2b8 100644 --- a/librz/include/rz_util/rz_utf16.h +++ b/librz/include/rz_util/rz_utf16.h @@ -1,7 +1,7 @@ #ifndef RZ_UTF16_H #define RZ_UTF16_H -/* For RzRune definition */ +/* For RzCodePoint definition */ #include "rz_utf8.h" RZ_API size_t rz_utf16_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch, bool bigendian); diff --git a/librz/include/rz_util/rz_utf32.h b/librz/include/rz_util/rz_utf32.h index 9eee1d4c210..43689d450b7 100644 --- a/librz/include/rz_util/rz_utf32.h +++ b/librz/include/rz_util/rz_utf32.h @@ -1,7 +1,7 @@ #ifndef RZ_UTF32_H #define RZ_UTF32_H -/* For RzRune definition */ +/* For RzCodePoint definition */ #include "rz_utf8.h" RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool bigendian); diff --git a/librz/util/ebcdic.c b/librz/util/ebcdic.c index 504707ec979..f53dca046b2 100644 --- a/librz/util/ebcdic.c +++ b/librz/util/ebcdic.c @@ -447,10 +447,10 @@ static const ut8 ebcdic_es_page20[256] = { /// @{ /** - * \brief Convert an ibm037 char into an unicode RzRune + * \brief Convert an ibm037 char into an unicode RzCodePoint * * \param src ibm037 char - * \param dst unicode RzRune + * \param dst unicode RzCodePoint * \retval 0 if \p dst is null * \retval 1 if convert successful */ @@ -461,10 +461,10 @@ RZ_API int rz_str_ibm037_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint } /** - * \brief Convert an unicode RzRune into an ibm037 char + * \brief Convert an unicode RzCodePoint into an ibm037 char * * \param dst ibm037 char - * \param src unicode RzRune + * \param src unicode RzCodePoint */ RZ_API int rz_str_ibm037_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src) { rz_return_val_if_fail(dst, 0); @@ -512,14 +512,14 @@ RZ_API int rz_str_ibm037_from_ascii(RZ_NONNULL RZ_OUT ut8 *dst, const ut8 src) { /// @{ -/// Convert an ibm290 char into an unicode RzRune +/// Convert an ibm290 char into an unicode RzCodePoint RZ_API int rz_str_ibm290_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint *dst) { rz_return_val_if_fail(dst, 0); *dst = ibm290_to_uni[src]; return 1; } -/// Convert an unicode RzRune into an ibm290 char +/// Convert an unicode RzCodePoint into an ibm290 char RZ_API int rz_str_ibm290_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src) { rz_return_val_if_fail(dst, 0); if (src <= 0xff) { @@ -559,14 +559,14 @@ RZ_API int rz_str_ibm290_from_ascii(RZ_NONNULL RZ_OUT ut8 *dst, const ut8 src) { /// @{ -/// Convert an ebcdic_uk char into an unicode RzRune +/// Convert an ebcdic_uk char into an unicode RzCodePoint RZ_API int rz_str_ebcdic_uk_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint *dst) { rz_return_val_if_fail(dst, 0); *dst = ebcdic_uk_to_uni[src]; return 1; } -/// Convert an unicode RzRune into an ebcdic_uk char +/// Convert an unicode RzCodePoint into an ebcdic_uk char RZ_API int rz_str_ebcdic_uk_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src) { rz_return_val_if_fail(dst, 0); if (src <= 0xff) { @@ -603,14 +603,14 @@ RZ_API int rz_str_ebcdic_uk_from_ascii(RZ_NONNULL RZ_OUT ut8 *dst, const ut8 src /// @{ -/// Convert an ebcdic_us char into an unicode RzRune +/// Convert an ebcdic_us char into an unicode RzCodePoint RZ_API int rz_str_ebcdic_us_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint *dst) { rz_return_val_if_fail(dst, 0); *dst = ebcdic_us_to_uni[src]; return 1; } -/// Convert an unicode RzRune into an ebcdic_us char +/// Convert an unicode RzCodePoint into an ebcdic_us char RZ_API int rz_str_ebcdic_us_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src) { rz_return_val_if_fail(dst, 0); if (src <= 0xff) { @@ -646,14 +646,14 @@ RZ_API int rz_str_ebcdic_us_from_ascii(RZ_NONNULL RZ_OUT ut8 *dst, const ut8 src */ /// @{ -/// Convert an ebcdic_es char into an unicode RzRune +/// Convert an ebcdic_es char into an unicode RzCodePoint RZ_API int rz_str_ebcdic_es_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint *dst) { rz_return_val_if_fail(dst, 0); *dst = ebcdic_es_to_uni[src]; return 1; } -/// Convert an unicode RzRune into an ebcdic_es char +/// Convert an unicode RzCodePoint into an ebcdic_es char RZ_API int rz_str_ebcdic_es_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src) { rz_return_val_if_fail(dst, 0); if (src <= 0xff) { diff --git a/librz/util/utf32.c b/librz/util/utf32.c index b53b91ee590..7cefa07c56a 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -4,7 +4,7 @@ #include #include -/* Convert an UTF-32 buf into a unicode RzRune */ +/* Convert an UTF-32 buf into a unicode RzCodePoint */ RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool bigendian) { if (ptrlen < 1) { return 0; @@ -35,12 +35,12 @@ RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool big return 0; } -/* Convert an UTF-32LE buf into a unicode RzRune */ +/* Convert an UTF-32LE buf into a unicode RzCodePoint */ RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { return rz_utf32_decode(ptr, ptrlen, ch, false); } -/* Convert an UTF-32BE buf into a unicode RzRune */ +/* Convert an UTF-32BE buf into a unicode RzCodePoint */ RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { return rz_utf32_decode(ptr, ptrlen, ch, true); } diff --git a/librz/util/utf8.c b/librz/util/utf8.c index 4f1d114763f..da21a996902 100644 --- a/librz/util/utf8.c +++ b/librz/util/utf8.c @@ -490,7 +490,7 @@ RZ_API const char *rz_utf_block_name(int idx) { return utf_blocks[idx].name; } -/* Convert an UTF-8 buf into a unicode RzRune */ +/* Convert an UTF-8 buf into a unicode RzCodePoint */ RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { if (ptrlen < 1) { return 0; @@ -522,7 +522,7 @@ RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { return 0; } -/* Convert an MUTF-8 buf into a unicode RzRune */ +/* Convert an MUTF-8 buf into a unicode RzCodePoint */ RZ_API int rz_mutf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { if (ptrlen > 1 && ptr[0] == 0xc0 && ptr[1] == 0x80) { if (ch) { @@ -533,7 +533,7 @@ RZ_API int rz_mutf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { return rz_utf8_decode(ptr, ptrlen, ch); } -/* Convert a unicode RzRune into an UTF-8 buf */ +/* Convert a unicode RzCodePoint into an UTF-8 buf */ RZ_API int rz_utf8_encode(ut8 *ptr, const RzCodePoint ch) { if (ch < 0x80) { ptr[0] = (ut8)ch; @@ -557,7 +557,7 @@ RZ_API int rz_utf8_encode(ut8 *ptr, const RzCodePoint ch) { return 0; } -/* Convert a unicode RzRune string into an utf-8 one */ +/* Convert a unicode RzCodePoint string into an utf-8 one */ RZ_API int rz_utf8_encode_str(const RzCodePoint *str, ut8 *dst, const int dst_length) { if (!str || !dst) { return -1; @@ -600,13 +600,13 @@ RZ_API int rz_utf8_strlen(const ut8 *str) { } /** - * \brief Returns true when the RzRune is a printable symbol + * \brief Returns true when the RzCodePoint is a printable symbol * - * \param c RzRune value to test + * \param c RzCodePoint value to test * \return true if the rune is printable, otherwise false */ RZ_API bool rz_code_point_is_printable(const RzCodePoint c) { - // RzRunes are most commonly single byte... We can early out with this common case. + // RzCodePoints are most commonly single byte... We can early out with this common case. if (c < 0x34F) { /* manually copied from top, please update if this ever changes From 6f6198a730adf9bdd993620d2c46dc236d9d56b2 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 30 Jan 2025 12:48:47 -0500 Subject: [PATCH 060/157] Print whole block buffer, if the user wants it. --- librz/core/cmd/cmd_print.c | 4 ++-- librz/core/cmd_descs/cmd_descs.c | 4 ++-- librz/core/cmd_descs/cmd_print.yaml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 4b4148f5659..75a84301701 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -2099,11 +2099,11 @@ static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, ut opt.length = length; opt.encoding = encoding; opt.stop_at_nil = stop_at_nil; - opt.stop_at_unprintable = true; + opt.stop_at_unprintable = stop_at_nil; core_print_raw_buffer(&opt); break; case RZ_OUTPUT_MODE_JSON: - print_json_string(core, buffer, length, encoding, stop_at_nil, true); + print_json_string(core, buffer, length, encoding, stop_at_nil, stop_at_nil); break; default: RZ_LOG_ERROR("core: unsupported output mode\n"); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 4d74aaae787..bcb1be665aa 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -15275,7 +15275,7 @@ static const RzCmdDescHelp ps_help = { static const RzCmdDescDetailEntry print_string_Value_space_details_detail_entries[] = { { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'str.search.encoding' option." }, { .text = "delimeter=null", .arg_str = NULL, .comment = "String is NUL terminated." }, - { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string." }, + { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (dosn't stop at non-printable character)." }, { 0 }, }; static const RzCmdDescDetail print_string_details[] = { @@ -15303,7 +15303,7 @@ static const RzCmdDescArg print_string_args[] = { { 0 }, }; static const RzCmdDescHelp print_string_help = { - .summary = "Print the string at the current offset (null->zero-terminated, block->block-terminated).", + .summary = "Print the string at the current offset.", .details = print_string_details, .args = print_string_args, }; diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index 6ceda50b8d8..f1e3281272b 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1097,7 +1097,7 @@ commands: summary: Print string at the current offset subcommands: - name: ps - summary: Print the string at the current offset (null->zero-terminated, block->block-terminated). + summary: Print the string at the current offset. cname: print_string modes: - RZ_OUTPUT_MODE_STANDARD @@ -1132,7 +1132,7 @@ commands: - text: "delimeter=null" comment: "String is NUL terminated." - text: "delimeter=block" - comment: "Print whole block as string." + comment: "Print whole block as string (dosn't stop at non-printable character)." - name: ps+ summary: Print libc++ std::string (same-endian, ascii, zero-terminated) cname: print_string_as_libcpp_string From 2806a33803090b1be912b916a3411b66662bd3ad Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 31 Jan 2025 08:57:30 -0500 Subject: [PATCH 061/157] Fix leaks --- test/unit/test_str_search.c | 39 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/test/unit/test_str_search.c b/test/unit/test_str_search.c index 0dd30b1a6d2..056c6d3c4c5 100644 --- a/test/unit/test_str_search.c +++ b/test/unit/test_str_search.c @@ -16,7 +16,7 @@ bool test_rz_scan_strings_detect_ascii(void) { static const unsigned char str[] = "\xff\xff\xffI am an ASCII string\xff\xff"; RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); mu_assert_eq(n, 1, "rz_scan_strings ascii, number of strings"); @@ -25,7 +25,6 @@ bool test_rz_scan_strings_detect_ascii(void) { mu_assert_eq(s->addr, 3, "rz_scan_strings ascii, address"); mu_assert_eq(s->type, RZ_STRING_ENC_8BIT, "rz_scan_strings ascii, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -36,7 +35,7 @@ bool test_rz_scan_strings_detect_ibm037(void) { static const unsigned char str[] = "\xc9\x40\x81\x94\x40\x81\x95\x40\xc9\xc2\xd4\xf0\xf3\xf7\x40\xa2\xa3\x99\x89\x95\x87\x25"; RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); mu_assert_eq(n, 1, "rz_scan_strings ibm037, number of strings"); @@ -44,7 +43,6 @@ bool test_rz_scan_strings_detect_ibm037(void) { mu_assert_streq(s->string, "I am an IBM037 string", "rz_scan_strings ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_IBM037, "rz_scan_strings ibm037, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -63,12 +61,10 @@ bool test_rz_scan_strings_detect_ibm037(void) { s = rz_list_get_n(str_list, 0); mu_assert_streq(s->string, "Ber. Who's there.?", "rz_scan_strings ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_IBM037, "rz_scan_strings ibm037, string type"); - rz_detected_string_free(s); s = rz_list_get_n(str_list, 1); mu_assert_streq(s->string, "Fran. Nay, answer me. Stand and unfold yourself", "rz_scan_strings ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_IBM037, "rz_scan_strings ibm037, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -86,12 +82,10 @@ bool test_rz_scan_strings_detect_ibm037(void) { s = rz_list_get_n(str_list, 0); mu_assert_streq(s->string, "I am an IBM037 string", "rz_scan_strings mix utf8 and ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_IBM037, "rz_scan_strings mix utf8 and ibm037, string type"); - rz_detected_string_free(s); s = rz_list_get_n(str_list, 1); mu_assert_streq(s->string, "I am a \xc3\x99TF-8 string", "rz_scan_strings mix utf8 and ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF8, "rz_scan_strings mix utf8 and ibm037, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -109,12 +103,10 @@ bool test_rz_scan_strings_detect_ibm037(void) { s = rz_list_get_n(str_list, 0); mu_assert_streq(s->string, "I am an IBM037 string", "rz_scan_strings mix utf8 and ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_IBM037, "rz_scan_strings mix utf8 and ibm037, string type"); - rz_detected_string_free(s); s = rz_list_get_n(str_list, 1); mu_assert_streq(s->string, "I am a \xc3\x99TF-8 string", "rz_scan_strings mix utf8 and ibm037, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF8, "rz_scan_strings mix utf8 and ibm037, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -126,7 +118,7 @@ bool test_rz_scan_strings_detect_utf8(void) { static const unsigned char str[] = "\xff\xff\xff\xffI am a \xc3\x99TF-8 string\xff\xff\xff\xff"; RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); mu_assert_eq(n, 1, "rz_scan_strings utf8, number of strings"); @@ -135,7 +127,6 @@ bool test_rz_scan_strings_detect_utf8(void) { mu_assert_eq(s->addr, 4, "rz_scan_strings utf8, address"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF8, "rz_scan_strings utf8, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -151,7 +142,7 @@ bool test_rz_scan_strings_detect_utf16_le(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); g_opt.prefer_big_endian = false; int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); @@ -162,7 +153,6 @@ bool test_rz_scan_strings_detect_utf16_le(void) { mu_assert_eq(s->addr, 3, "rz_scan_strings utf16le, address"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF16LE, "rz_scan_strings utf16le, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -178,7 +168,7 @@ bool test_rz_scan_strings_detect_utf16_le_special_chars(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); g_opt.prefer_big_endian = false; int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); @@ -189,7 +179,6 @@ bool test_rz_scan_strings_detect_utf16_le_special_chars(void) { mu_assert_eq(s->addr, 0, "rz_scan_strings utf16le, address"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF16LE, "rz_scan_strings utf16le, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -205,7 +194,7 @@ bool test_rz_scan_strings_detect_utf16_be(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); g_opt.prefer_big_endian = true; int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); @@ -216,7 +205,6 @@ bool test_rz_scan_strings_detect_utf16_be(void) { mu_assert_eq(s->addr, 3, "rz_scan_strings utf16be, address"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF16BE, "rz_scan_strings utf16be, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -235,7 +223,7 @@ bool test_rz_scan_strings_detect_utf32_le(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); g_opt.prefer_big_endian = false; int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); @@ -246,7 +234,6 @@ bool test_rz_scan_strings_detect_utf32_le(void) { mu_assert_eq(s->addr, 2, "rz_scan_strings utf32le, address"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF32LE, "rz_scan_strings utf32le, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -265,7 +252,7 @@ bool test_rz_scan_strings_detect_utf32_be(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); g_opt.prefer_big_endian = true; int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); @@ -276,7 +263,6 @@ bool test_rz_scan_strings_detect_utf32_be(void) { mu_assert_eq(s->addr, 2, "rz_scan_strings utf32be, address"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF32BE, "rz_scan_strings utf32be, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -289,7 +275,7 @@ bool test_rz_scan_strings_utf16_be(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); g_opt.prefer_big_endian = true; int n = rz_scan_strings(buf, str_list, &g_opt, 16, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_UTF16BE); @@ -302,7 +288,6 @@ bool test_rz_scan_strings_utf16_be(void) { "rz_scan_strings utf16be, different string"); mu_assert_eq(s->type, RZ_STRING_ENC_UTF16BE, "rz_scan_strings utf16be, string type"); - rz_detected_string_free(s); rz_list_free(str_list); rz_buf_free(buf); @@ -317,7 +302,7 @@ bool test_rz_scan_strings_extended_ascii(void) { RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); - RzList *str_list = rz_list_new(); + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); int n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_UTF8); mu_assert_eq(n, 3, "rz_scan_strings extended_ascii, number of strings"); @@ -333,10 +318,6 @@ bool test_rz_scan_strings_extended_ascii(void) { mu_assert_streq(s_fr->string, "Dans l'éblouissante clarté de leur premier amour.", "rz_scan_strings extended_ascii, different strings FR"); - rz_detected_string_free(s_it); - rz_detected_string_free(s_de); - rz_detected_string_free(s_fr); - rz_list_free(str_list); rz_buf_free(buf); From bd22020117e5ab0595865f5ff2d0d0b3e6b7778b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 31 Jan 2025 12:36:18 -0500 Subject: [PATCH 062/157] Check empty condition before sorting vectors. This fixes reachable asserts because vec->a is NULL. --- librz/util/vector.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/librz/util/vector.c b/librz/util/vector.c index addc707075c..abbff0115be 100644 --- a/librz/util/vector.c +++ b/librz/util/vector.c @@ -360,6 +360,9 @@ static void vector_quick_sort(void *a, size_t elem_size, size_t len, RzVectorCom */ RZ_API void rz_vector_sort(RzVector *vec, RzVectorComparator cmp, bool reverse, void *user) { rz_return_if_fail(vec && cmp); + if (rz_vector_empty(vec)) { + return; + } vector_quick_sort(vec->a, vec->elem_size, vec->len, cmp, reverse, user); } @@ -546,5 +549,8 @@ static void quick_sort(void **a, size_t n, RzPVectorComparator cmp, void *user) RZ_API void rz_pvector_sort(RzPVector *vec, RzPVectorComparator cmp, void *user) { rz_return_if_fail(vec && cmp); + if (rz_pvector_empty(vec)) { + return; + } quick_sort(vec->v.a, vec->v.len, cmp, user); } From e30943d8f5bdf50dcfe92634bc5d25082052f557 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sat, 1 Feb 2025 11:32:51 -0500 Subject: [PATCH 063/157] Fix UTF-32 decoding. --- librz/include/rz_util/rz_utf32.h | 9 ++++- librz/util/utf32.c | 43 ++++++++++------------- test/unit/test_encodings.c | 58 ++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/librz/include/rz_util/rz_utf32.h b/librz/include/rz_util/rz_utf32.h index 43689d450b7..5c514bd9fab 100644 --- a/librz/include/rz_util/rz_utf32.h +++ b/librz/include/rz_util/rz_utf32.h @@ -4,7 +4,14 @@ /* For RzCodePoint definition */ #include "rz_utf8.h" -RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool bigendian); +/** + * \brief Unicode byte order markings (BOM) + * according to https://www.unicode.org/faq/utf_bom.html#BOM + */ +#define RZ_UTF32_UNICODE_BOM_LE 0xFFFE0000 +#define RZ_UTF32_UNICODE_BOM_BE 0x0000FFFE + +RZ_API size_t rz_utf32_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NULLABLE RZ_OUT RzCodePoint *ch, bool big_endian); RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); diff --git a/librz/util/utf32.c b/librz/util/utf32.c index 7cefa07c56a..95111f24e78 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -4,35 +4,26 @@ #include #include -/* Convert an UTF-32 buf into a unicode RzCodePoint */ -RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch, bool bigendian) { - if (ptrlen < 1) { +/** + * \brief Decode bytes from the buffer \p buf into a code point. + * + * \param buf The buffer to read from. + * \param buf_len The buffer size in bytes. + * \param ch The code point to write the value to. + * \param big_endian If the buffer bytes have big endian order. + * + * \return The number of bytes converted. For UTF-32 this is always 0 or 4. + */ +RZ_API size_t rz_utf32_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NULLABLE RZ_OUT RzCodePoint *ch, bool big_endian) { + rz_return_val_if_fail(buf, 0); + if (buf_len < 4) { return 0; } - int low = 0; - int high = 3; - if (bigendian) { - low = 3; - high = 0; - } - if (ptrlen > 3) { - int sign = bigendian ? -1 : 1; - if (ch) { - int i; - *ch = (ut32)ptr[low]; - for (i = 1; i < 4; i++) { - *ch |= (ut32)ptr[3 - high + i * sign] << 8 * i; - } - } - if (ptr[high] || ptr[high - 1 * sign]) { - return 4; - } - if (ptr[low + 1 * sign]) { - return 2; - } - return 1; + if (!ch) { + return 4; } - return 0; + *ch = rz_read_ble32(buf, big_endian); + return 4; } /* Convert an UTF-32LE buf into a unicode RzCodePoint */ diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index d6d322088ac..3c5edb5013e 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -3,6 +3,7 @@ #include #include "minunit.h" +#include "rz_util/rz_utf32.h" #include #include @@ -177,6 +178,62 @@ bool test_rz_utf16_encode(void) { mu_end; } + +bool test_rz_utf32_decode(void) { + const ut8 utf32_size_0[] = { }; + const ut8 utf32_size_1[] = { 0xAC }; + const ut8 utf32_size_2[] = { 0xAC, 0xAC }; + const ut8 utf32_size_3[] = { 0xAC, 0xAC, 0x20 }; + + const ut8 utf32be_A[] = { 0x00, 0x00, 0x00, 0x41 }; + const ut8 utf32le_A[] = { 0x41, 0x00, 0x00, 0x00 }; + + // The non-ascii small a + const ut8 utf32be_a[] = { 0x00, 0x00, 0xff, 0x41 }; + const ut8 utf32le_a[] = { 0x41, 0xff, 0x00, 0x00 }; + + // Chess tower symbol Red General: 🩠 + const ut8 utf32be_red_general[] = { 0x00, 0x01, 0xFA, 0x60 }; + const ut8 utf32le_red_general[] = { 0x60, 0xfa, 0x01, 0x00 }; + + // Chess tower symbol Red General: 🩠 🩁 + const ut8 utf32be_red_general_black_tower[] = { 0x00, 0x01, 0xFA, 0x60, 0x00, 0x01, 0xFA, 0x41 }; + const ut8 utf32le_red_general_black_tower[] = { 0x60, 0xFA, 0x01, 0x00, 0x41, 0xFA, 0x01, 0x00 }; + + RzCodePoint cp; + mu_assert_eq(rz_utf32_decode(utf32_size_0, 0, &cp, false), 0, "Length check failed"); + mu_assert_eq(rz_utf32_decode(utf32_size_1, sizeof(utf32_size_1), &cp, false), 0, "Length check failed"); + mu_assert_eq(rz_utf32_decode(utf32_size_2, sizeof(utf32_size_2), &cp, false), 0, "Length check failed"); + mu_assert_eq(rz_utf32_decode(utf32_size_3, sizeof(utf32_size_3), &cp, false), 0, "Length check failed"); + + mu_assert_eq(rz_utf32_decode(utf32be_A, sizeof(utf32be_A), &cp, true), 4, "Length check failed"); + mu_assert_eq(cp, 0x41, "Incorrect decoding."); + mu_assert_eq(rz_utf32_decode(utf32le_A, sizeof(utf32le_A), &cp, false), 4, "Length check failed"); + mu_assert_eq(cp, 0x41, "Incorrect decoding."); + + mu_assert_eq(rz_utf32_decode(utf32be_a, sizeof(utf32be_a), &cp, true), 4, "Length check failed"); + mu_assert_eq(cp, 0xff41, "Incorrect decoding."); + mu_assert_eq(rz_utf32_decode(utf32le_a, sizeof(utf32le_a), &cp, false), 4, "Length check failed"); + mu_assert_eq(cp, 0xff41, "Incorrect decoding."); + + mu_assert_eq(rz_utf32_decode(utf32be_red_general, sizeof(utf32be_red_general), &cp, true), 4, "Length check failed"); + mu_assert_eq(cp, 0x01fa60, "Incorrect decoding."); + mu_assert_eq(rz_utf32_decode(utf32le_red_general, sizeof(utf32le_red_general), &cp, false), 4, "Length check failed"); + mu_assert_eq(cp, 0x01fa60, "Incorrect decoding."); + + mu_assert_eq(rz_utf32_decode(utf32be_red_general_black_tower, sizeof(utf32be_red_general_black_tower), &cp, true), 4, "Length check failed"); + mu_assert_eq(cp, 0x01fa60, "Incorrect decoding."); + mu_assert_eq(rz_utf32_decode(utf32le_red_general_black_tower, sizeof(utf32le_red_general_black_tower), &cp, false), 4, "Length check failed"); + mu_assert_eq(cp, 0x01fa60, "Incorrect decoding."); + + mu_assert_eq(rz_utf32_decode(utf32be_red_general_black_tower + 4, sizeof(utf32be_red_general_black_tower) - 4, &cp, true), 4, "Length check failed"); + mu_assert_eq(cp, 0x01fa41, "Incorrect decoding."); + mu_assert_eq(rz_utf32_decode(utf32le_red_general_black_tower + 4, sizeof(utf32le_red_general_black_tower) - 4, &cp, false), 4, "Length check failed"); + mu_assert_eq(cp, 0x01fa41, "Incorrect decoding."); + + mu_end; +} + bool test_rz_utf32_valid(void) { const ut8 utf32le_invalid_size[] = { 0xAC, 0xAC, 0x20 }; @@ -298,6 +355,7 @@ bool test_rz_utf16_valid(void) { bool all_tests() { mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); + mu_run_test(test_rz_utf32_decode); mu_run_test(test_rz_utf32_valid); mu_run_test(test_rz_utf16_valid); mu_run_test(test_rz_ebcdic_valid); From 698b14065920c19e3044e355cbcab3c2f0e01810 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 2 Feb 2025 09:33:39 -0500 Subject: [PATCH 064/157] Rename cp -> code_point --- librz/include/rz_util/rz_ebcdic.h | 2 +- librz/include/rz_util/rz_utf16.h | 2 +- librz/include/rz_util/rz_utf32.h | 2 +- librz/util/ebcdic.c | 2 +- librz/util/str.c | 4 +- librz/util/str_search.c | 10 +-- librz/util/utf16.c | 2 +- librz/util/utf32.c | 2 +- test/db/cmd/cmd_search_z | 3 +- test/unit/test_encodings.c | 108 +++++++++++++++--------------- 10 files changed, 68 insertions(+), 69 deletions(-) diff --git a/librz/include/rz_util/rz_ebcdic.h b/librz/include/rz_util/rz_ebcdic.h index 685c38f0c64..4e4ef611061 100644 --- a/librz/include/rz_util/rz_ebcdic.h +++ b/librz/include/rz_util/rz_ebcdic.h @@ -42,7 +42,7 @@ RZ_API int rz_str_ebcdic_us_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCod RZ_API int rz_str_ebcdic_es_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzCodePoint *dst); RZ_API int rz_str_ebcdic_es_from_unicode(RZ_NONNULL RZ_OUT ut8 *dst, const RzCodePoint src); -RZ_API bool rz_str_ebcdic_valid_cp(const RzCodePoint code_point); +RZ_API bool rz_str_ebcdic_valid_code_point(const RzCodePoint code_point); #ifdef __cplusplus } diff --git a/librz/include/rz_util/rz_utf16.h b/librz/include/rz_util/rz_utf16.h index cd708d0c2b8..263661c5e0a 100644 --- a/librz/include/rz_util/rz_utf16.h +++ b/librz/include/rz_util/rz_utf16.h @@ -8,6 +8,6 @@ RZ_API size_t rz_utf16_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONN RZ_API size_t rz_utf16le_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch); RZ_API size_t rz_utf16be_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NONNULL RZ_OUT RzCodePoint *ch); RZ_API size_t rz_utf16le_encode(RZ_NONNULL RZ_OUT ut8 *buf, RzCodePoint ch); -RZ_API bool rz_utf16_is_printable_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); +RZ_API bool rz_utf16_is_printable_code_point(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); #endif // RZ_UTF16_H diff --git a/librz/include/rz_util/rz_utf32.h b/librz/include/rz_util/rz_utf32.h index 5c514bd9fab..3605e5699a6 100644 --- a/librz/include/rz_util/rz_utf32.h +++ b/librz/include/rz_util/rz_utf32.h @@ -14,6 +14,6 @@ RZ_API size_t rz_utf32_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NULLABLE RZ_OUT RzCodePoint *ch, bool big_endian); RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); -RZ_API bool rz_utf32_valid_cp(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); +RZ_API bool rz_utf32_valid_code_point(const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead); #endif // RZ_UTF32_H diff --git a/librz/util/ebcdic.c b/librz/util/ebcdic.c index f53dca046b2..f116eccda86 100644 --- a/librz/util/ebcdic.c +++ b/librz/util/ebcdic.c @@ -689,7 +689,7 @@ RZ_API int rz_str_ebcdic_es_from_ascii(RZ_NONNULL RZ_OUT ut8 *dst, const ut8 src * * \return True, if the \p code_point is a supported EBCDIC character. False otherwise. */ -RZ_API bool rz_str_ebcdic_valid_cp(const RzCodePoint code_point) { +RZ_API bool rz_str_ebcdic_valid_code_point(const RzCodePoint code_point) { if (code_point == 0) { // ASCII NUL byte is the same. return true; diff --git a/librz/util/str.c b/librz/util/str.c index bc187222327..a866b62bd5a 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4079,7 +4079,7 @@ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, } for (ut32 i = 0, utf32le = 0, utf32be = 0, utf16le = 0, utf16be = 0, ascii = 0; i < length; ++i) { ut32 leftovers = length - i; - if (rz_utf32_valid_cp(buffer, leftovers, false, 1)) { + if (rz_utf32_valid_code_point(buffer, leftovers, false, 1)) { utf32le++; // `i > ascii + 1` means at least one non-ascii byte // `utf32le == i / 4 + 1` means neatly algined like 7700 0000 3000 0000 7700 0000 @@ -4087,7 +4087,7 @@ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, enc = RZ_STRING_ENC_UTF32LE; break; } - } else if (rz_utf32_valid_cp(buffer, leftovers, true, 1)) { + } else if (rz_utf32_valid_code_point(buffer, leftovers, true, 1)) { utf32be++; if (utf32be > 2 && (i > ascii + 1 || utf32be == i / 4 + 1)) { enc = RZ_STRING_ENC_UTF32BE; diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 33a44b48fc1..919373a96bc 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -428,15 +428,15 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 0, false); // At least 2 bytes must be given. // Buffer must cover all look aheads. diff --git a/librz/util/utf32.c b/librz/util/utf32.c index 95111f24e78..ea39112ea45 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -50,7 +50,7 @@ RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { * \return True if the buffer has \p lookahead valid UTF-32 code points. * \return False otherwise. */ -RZ_API bool rz_utf32_valid_cp(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { +RZ_API bool rz_utf32_valid_code_point(RZ_NONNULL const ut8 *buf, size_t buf_len, bool big_endian, size_t lookahead) { rz_return_val_if_fail(buf && buf_len > 0, false); // At least 4 bytes must be given. // Buffer must cover all look aheads. diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 9776c4acae7..eb9b4d631a9 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -893,10 +893,9 @@ psu @ hit.string.1 EOF EXPECT=< Date: Sun, 2 Feb 2025 09:50:42 -0500 Subject: [PATCH 065/157] Revert string detection heuristics to use the only ASCII checking ones. --- librz/util/str_search.c | 118 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 919373a96bc..f371764c050 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -366,6 +366,42 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 return NULL; } +static inline bool can_be_utf16_le(const ut8 *buf, ut64 size) { + int rc = rz_utf8_decode(buf, size, NULL); + if (!rc || (size - rc) < 5) { + return false; + } + char *w = (char *)buf + rc; + return !w[0] && w[1] && !w[2] && w[3] && !w[4]; +} + +static inline bool can_be_utf16_be(const ut8 *buf, ut64 size) { + if (size < 7) { + return false; + } + return !buf[0] && buf[1] && !buf[2] && buf[3] && !buf[4] && buf[5] && !buf[6]; +} + +static inline bool can_be_utf32_le(const ut8 *buf, ut64 size) { + int rc = rz_utf8_decode(buf, size, NULL); + if (!rc || (size - rc) < 5) { + return false; + } + char *w = (char *)buf + rc; + return !w[0] && !w[1] && !w[2] && w[3] && !w[4]; +} + +static inline bool can_be_utf32_be(const ut8 *buf, ut64 size) { + if (size < 7) { + return false; + } + return !buf[0] && !buf[1] && !buf[2] && buf[3] && !buf[4] && !buf[5] && !buf[6]; +} + +static inline bool can_be_ebcdic(const ut8 *buf, ut64 size) { + return buf[0] < 0x20 || buf[0] > 0x3f; +} + /** * \brief Look for strings in a byte array, but returns only the first result. * @@ -428,15 +464,83 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* 3 && can_be_utf32_le(ptr + 3, size - 3)) { + // The string can be either utf32-le or utf32-be + RzDetectedString *ds_le = process_one_string(buf, from, needle + 3, to, RZ_STRING_ENC_UTF32LE, false, opt, rz_list_length(list)); + RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF32BE, false, opt, rz_list_length(list)); + + RzDetectedString *to_add = NULL; + RzDetectedString *to_delete = NULL; + ut64 needle_offset = 0; + + if (!ds_le && !ds_be) { + needle++; + continue; + } else if (!ds_be) { + to_add = ds_le; + needle_offset = ds_le->size + 3; + } else if (!ds_le) { + to_add = ds_be; + needle_offset = ds_be->size; + } else if (!opt->prefer_big_endian) { + to_add = ds_le; + to_delete = ds_be; + needle_offset = ds_le->size + 3; + } else { + to_add = ds_be; + to_delete = ds_le; + needle_offset = ds_le->size; + } + + count++; + needle += needle_offset; + rz_list_append(list, to_add); + rz_detected_string_free(to_delete); + continue; + } + str_type = RZ_STRING_ENC_UTF32BE; + } else if (can_be_utf16_be(ptr, size)) { + if (to - needle > 1 && can_be_utf16_le(ptr + 1, size - 1)) { + // The string can be either utf16-le or utf16-be + RzDetectedString *ds_le = process_one_string(buf, from, needle + 1, to, RZ_STRING_ENC_UTF16LE, false, opt, rz_list_length(list)); + RzDetectedString *ds_be = process_one_string(buf, from, needle, to, RZ_STRING_ENC_UTF16BE, false, opt, rz_list_length(list)); + + RzDetectedString *to_add = NULL; + RzDetectedString *to_delete = NULL; + ut64 needle_offset = 0; + + if (!ds_le && !ds_be) { + needle++; + continue; + } else if (!ds_be) { + to_add = ds_le; + needle_offset = ds_le->size + 1; + } else if (!ds_le) { + to_add = ds_be; + needle_offset = ds_be->size; + } else if (!opt->prefer_big_endian) { + to_add = ds_le; + to_delete = ds_be; + needle_offset = ds_le->size + 1; + } else { + to_add = ds_be; + to_delete = ds_le; + needle_offset = ds_le->size; + } + + count++; + needle += needle_offset; + rz_list_append(list, to_add); + rz_detected_string_free(to_delete); + continue; + } str_type = RZ_STRING_ENC_UTF16BE; - } else if (skip_ibm037 < 0 && rz_str_ebcdic_valid_code_point(ptr[0])) { + } else if (can_be_ebcdic(ptr, size) && skip_ibm037 < 0) { ut8 sz = RZ_MIN(size, 15); RzCodePoint code_points[15] = { 0 }; int i = 0; @@ -541,7 +645,7 @@ RZ_API int rz_scan_strings_whole_buf(RZ_NONNULL const RzBuffer *buf_to_scan, RZ_ } ut64 size; - const ut8 *raw_buf = rz_buf_get_whole_hot_paths((RzBuffer *) buf_to_scan, &size); + const ut8 *raw_buf = rz_buf_get_whole_hot_paths((RzBuffer *)buf_to_scan, &size); if (!raw_buf) { RZ_LOG_ERROR("Failed to get whole buffer."); return -1; From 104d69d0124e1ea7d67e88cd65ba11c592627c31 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 2 Feb 2025 09:51:52 -0500 Subject: [PATCH 066/157] Fix leaks --- test/unit/test_str_search.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/test_str_search.c b/test/unit/test_str_search.c index 056c6d3c4c5..6ff0e867085 100644 --- a/test/unit/test_str_search.c +++ b/test/unit/test_str_search.c @@ -54,7 +54,7 @@ bool test_rz_scan_strings_detect_ibm037(void) { static const unsigned char str2[] = "\xff\xff\xff\xC2\x85\x99\x4B\x40\xE6\x88\x96\x7D\xA2\x40\xA3\x88\x85\x99\x85\x4B\x6F\x00\xC6\x99\x81\x95\x4B\x40\xD5\x81\xA8\x6B\x40\x81\x95\xA2\xA6\x85\x99\x40\x94\x85\x4B\x40\xE2\xA3\x81\x95\x84\x40\x81\x95\x84\x40\xA4\x95\x86\x96\x93\x84\x40\xA8\x96\xA4\x99\xA2\x85\x93\x86"; buf = rz_buf_new_with_bytes(str2, sizeof(str2)); - str_list = rz_list_new(); + str_list = rz_list_newf((RzListFree)rz_detected_string_free); n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); mu_assert_eq(n, 2, "rz_scan_strings ibm037, number of strings"); @@ -75,7 +75,7 @@ bool test_rz_scan_strings_detect_ibm037(void) { "\xff\xff\xff\xffI am a \xc3\x99TF-8 string\xff\xff\xff\xff"; buf = rz_buf_new_with_bytes(str3, sizeof(str3)); - str_list = rz_list_new(); + str_list = rz_list_newf((RzListFree)rz_detected_string_free); n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); mu_assert_eq(n, 2, "rz_scan_strings mix utf8 and ibm037, number of strings"); @@ -96,7 +96,7 @@ bool test_rz_scan_strings_detect_ibm037(void) { "I am a \xc3\x99TF-8 string\xff\xff\xff"; buf = rz_buf_new_with_bytes(str4, sizeof(str4)); - str_list = rz_list_new(); + str_list = rz_list_newf((RzListFree)rz_detected_string_free); n = rz_scan_strings(buf, str_list, &g_opt, 0, buf->methods->get_size(buf) - 1, RZ_STRING_ENC_GUESS); mu_assert_eq(n, 2, "rz_scan_strings mix utf8 and ibm037, number of strings"); From 2c2859567c1e5a486d5639d1bc842eec794891b1 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 2 Feb 2025 09:55:01 -0500 Subject: [PATCH 067/157] Remove dead code (after fixing the decode functions.) --- librz/util/str_search.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/librz/util/str_search.c b/librz/util/str_search.c index f371764c050..f3713fc1a34 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -249,27 +249,15 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 switch(str_type) { case RZ_STRING_ENC_UTF32LE: rc = rz_utf32le_decode(buf + needle - from, to - needle, &r); - if (rc) { - rc = 4; - } break; case RZ_STRING_ENC_UTF16LE: rc = rz_utf16le_decode(buf + needle - from, to - needle, &r); - if (rc == 1) { - rc = 2; - } break; case RZ_STRING_ENC_UTF32BE: rc = rz_utf32be_decode(buf + needle - from, to - needle, &r); - if (rc) { - rc = 4; - } break; case RZ_STRING_ENC_UTF16BE: rc = rz_utf16be_decode(buf + needle - from, to - needle, &r); - if (rc == 1) { - rc = 2; - } break; case RZ_STRING_ENC_IBM037: rc = rz_str_ibm037_to_unicode(*(buf + needle - from), &r); From 627e22759ef65f25ae28f38523cd593bed97389d Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 2 Feb 2025 09:57:23 -0500 Subject: [PATCH 068/157] Fix tests with updated binaries --- test/db/cmd/cmd_search_z | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index eb9b4d631a9..afe7aad075d 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -910,8 +910,8 @@ psW @ hit.string.0 psW @ hit.string.1 EOF EXPECT=< Date: Sun, 2 Feb 2025 12:52:17 -0500 Subject: [PATCH 069/157] Move all search command help messages to RzShell. --- librz/core/cmd/cmd.c | 1 - librz/core/cmd/cmd_search.c | 1092 ++++++++++++++++++++++---- librz/core/cmd_descs/cmd_descs.c | 748 +++++++++++++++++- librz/core/cmd_descs/cmd_descs.h | 82 +- librz/core/cmd_descs/cmd_search.yaml | 419 ++++++++-- librz/search/bytepat.c | 135 ++++ librz/search/meson.build | 1 + 7 files changed, 2263 insertions(+), 215 deletions(-) create mode 100644 librz/search/bytepat.c diff --git a/librz/core/cmd/cmd.c b/librz/core/cmd/cmd.c index 7332903deee..976973f19f5 100644 --- a/librz/core/cmd/cmd.c +++ b/librz/core/cmd/cmd.c @@ -5251,7 +5251,6 @@ RZ_API void rz_core_cmd_init(RzCore *core) { const char *description; RzCmdCb cb; } cmds[] = { - { "/", "search kw, pattern aes", rz_cmd_search }, { "p", "print current block", rz_cmd_print }, { "x", "alias for px", rz_cmd_hexdump }, }; diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 4684b41b6cb..b9f72e1e3dd 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -12,6 +12,7 @@ #include "cmd_search_rop.c" #include "rz_cons.h" +#include #include #include #include @@ -20,112 +21,6 @@ #define AES_SEARCH_LENGTH 40 #define PRIVATE_KEY_SEARCH_LENGTH 11 -static const char *help_msg_search_esil[] = { - "/E", " [esil-expr]", "search offsets matching a specific esil expression", - "/Ej", " [esil-expr]", "same as above but using the given magic file", - "/E?", " ", "show this help", - "\nExamples:", "", "", - "", "/E $$,0x100001060,-,!", "hit when address is 0x100001060", - NULL -}; - -static const char *help_msg_slash_m[] = { - "/m", "", "search for known magic patterns", - "/m", " [file]", "same as above but using the given magic file", - "/mb", "", "search recognized RzBin headers", - NULL -}; - -static const char *help_msg_slash[] = { - "Usage:", "/[!bf] [arg]", "Search stuff (see 'e??search' for options)\n" - "|Use io.va for searching in non virtual addressing spaces", - "/", " foo\\x00", "search for string 'foo\\0'", - "/j", " foo\\x00", "search for string 'foo\\0' (json output)", - "/!", " ff", "search for first occurrence not matching, command modifier", - "/!x", " 00", "inverse hexa search (find first byte != 0x00)", - "/+", " /bin/sh", "construct the string with chunks", - "//", "", "repeat last search", - "/a", "[?][1aoditfmsltf] jmp eax", "assemble opcode and search its bytes", - "/b", "", "search backwards, command modifier, followed by other command", - "/c", "[?][adr]", "search for crypto materials", - "/d", " 101112", "search for a deltified sequence of bytes", - "/e", " /pattern/[i]", "match regular expression (beginning-of-string for ^ and $ is '\\0')", - "/E", " esil-expr", "offset matching given esil expressions $$ = here", - "/f", "", "search forwards, (command modifier)", - "/F", " file [off] [sz]", "search contents of file with offset and size", - // TODO: add subcommands to find paths between functions and filter only function names instead of offsets, etc - "/g", "[g] [from]", "find all graph paths A to B (/gg follow jumps, see search.count and analysis.depth)", - "/h", "[t] [hash] [len]", "find block matching this hash. See ph", - "/i", " foo", "search for string 'foo' ignoring case", - "/m", "[?][ebm] magicfile", "search for magic, filesystems or binary headers", - "/o", " [n]", "show offset of n instructions backward", - "/O", " [n]", "same as /o, but with a different fallback if analysis cannot be used", - "/p", " patternsize", "search for pattern of given size", - "/P", " patternsize", "search similar blocks", - "/s", "[*] [threshold]", "find sections by grouping blocks with similar entropy", - "/r[rwx]", "[?] sym.printf", "analyze opcode reference an offset", - "/R", " [grepopcode]", "search for matching ROP gadgets, semicolon-separated", - // moved into /as "/s", "", "search for all syscalls in a region (EXPERIMENTAL)", - "/v", "[1248] value", "look for an `cfg.bigendian` 32bit value", - "/V", "[1248] min max", "look for an `cfg.bigendian` 32bit value in range", - "/w", " foo", "search for wide string 'f\\0o\\0o\\0'", - "/wi", " foo", "search for wide string ignoring case 'f\\0o\\0o\\0'", - "/x", " ff..33", "search for hex string ignoring some nibbles", - "/x", " ff0033", "search for hex string", - "/x", " ff43:ffd0", "search for hexpair with mask", - "/z", " min max", "search for strings of given size", - "/*", " [comment string]", "add multiline comment, end it with '*/'", - NULL -}; - -static const char *help_msg_slash_a[] = { - "Usage:", "/a[?] [arg]", "Search for assembly instructions matching given properties", - "/a", " push rbp", "Assemble given instruction and search the bytes", - "/a1", " [number]", "Find valid assembly generated by changing only the nth byte", - "/aI", "", "Search for infinite loop instructions (jmp $$)", - "/aa", " mov eax", "Linearly find aproximated assembly (case insensitive strstr)", - "/ac", " mov eax", "Same as /aa, but case-sensitive", - "/ad", "[/*j] push;mov", "Match ins1 followed by ins2 in linear disasm", - "/ad/", " ins1;ins2", "Search for regex instruction 'ins1' followed by regex 'ins2'", - "/ad/a", " instr", "Search for every byte instruction that matches regexp 'instr'", - "/ae", " esil", "Search for esil expressions matching substring", - "/af", "[l] family", "Search for instruction of specific family (afl=list", - "/ai", "[j] 0x300 [0x500]", "Find all the instructions using that immediate (in range)", - "/al", "", "Same as aoml, list all opcodes", - "/am", " opcode", "Search for specific instructions of specific mnemonic", - "/ao", " instr", "Search for instruction 'instr' (in all offsets)", - "/as", "[l] ([type])", "Search for syscalls (See /at swi and /af priv)", - "/at", "[l] ([type])", "Search for instructions of given type", - NULL -}; - -static const char *help_msg_slash_c[] = { - "Usage: /c", "", "Search for crypto materials", - "/ca", "", "Search for AES keys expanded in memory", - "/cc", "[algo] [digest]", "Find collisions (bruteforce block length values until given checksum is found)", - "/cd", "", "Search for ASN1/DER certificates", - "/cr", "", "Search for ASN1/DER private keys (RSA and ECC)", - NULL -}; - -static const char *help_msg_slash_r[] = { - "Usage:", "/r[acerwx] [address]", " search references to this specific address", - "/r", " [addr]", "search references to this specific address", - "/ra", "", "search all references", - "/rc", "", "search for call references", - "/rr", "", "Find read references", - "/rw", "", "Find write references", - "/rx", "", "Find exec references", - NULL -}; - -static const char *help_msg_slash_x[] = { - "Usage:", "/x [hexpairs]:[binmask]", "Search in memory", - "/x ", "9090cd80", "search for those bytes", - "/x ", "9090cd80:ffff7ff0", "search with binary mask", - NULL -}; - static int preludecnt = 0; static int searchflags = 0; static int searchshow = 0; @@ -616,10 +511,6 @@ static void do_esil_search(RzCore *core, struct search_parameters *param, const param->outmode = RZ_MODE_JSON; input++; } - if (input[1] != ' ') { // "/E?" - rz_core_cmd_help(core, help_msg_search_esil); - return; - } if (!core->analysis->esil) { // initialize esil vm rz_core_analysis_esil_reinit(core); @@ -971,9 +862,7 @@ static bool do_analysis_search(RzCore *core, struct search_parameters *param, co type = *input; break; case 0: - case '?': default: - rz_core_cmd_help(core, help_msg_slash_a); return false; } input++; @@ -1698,6 +1587,7 @@ static void search_collisions(RzCore *core, const char *hashName, const ut8 *has case 'd': // digits incDigitBuffer(buf, bufsz); break; + case 'b': default: // binary incBuffer(buf, bufsz); break; @@ -1777,8 +1667,763 @@ static void __core_cmd_search_asm_byteswap(RzCore *core, int nth) { } } -RZ_IPI int rz_cmd_search(void *data, const char *input) { - return RZ_CMD_STATUS_ERROR; +static int cmd_search_legacy_handler(void *data, const char *input) { + bool dosearch = false; + int ret = true; + RzCore *core = (RzCore *)data; + struct search_parameters param = { + .core = core, + .cmd_hit = rz_config_get(core->config, "cmd.hit"), + .outmode = 0, + .inverse = false, + .aes_search = false, + .privkey_search = false, + .regex_search = false, + }; + if (!param.cmd_hit) { + param.cmd_hit = ""; + } + RzSearch *search = core->search; + int param_offset = 2; + if (!core || !core->io) { + RZ_LOG_ERROR("core: Can't search if we don't have an open file.\n"); + return false; + } + if (core->in_search) { + RZ_LOG_ERROR("core: Can't search from within a search.\n"); + return false; + } + if (input[0] == '/') { + if (core->lastsearch) { + input = core->lastsearch; + } else { + RZ_LOG_ERROR("core: No previous search done\n"); + return false; + } + } else { + free(core->lastsearch); + core->lastsearch = rz_str_dup(input); + } + + core->in_search = true; + rz_flag_space_push(core->flags, "search"); + const ut64 search_from = rz_config_get_i(core->config, "search.from"), + search_to = rz_config_get_i(core->config, "search.to"); + if (search_from > search_to && search_to) { + RZ_LOG_ERROR("core: search.from > search.to is not supported\n"); + ret = false; + goto beach; + } + // {.addr = UT64_MAX, .size = 0} means search range is unspecified + RzInterval search_itv = { search_from, search_to - search_from }; + bool empty_search_itv = search_from == search_to && search_from != UT64_MAX; + if (empty_search_itv) { + RZ_LOG_ERROR("core: `from` address is equal `to`\n"); + ret = false; + goto beach; + } + // TODO full address cannot be represented, shrink 1 byte to [0, UT64_MAX) + if (search_from == UT64_MAX && search_to == UT64_MAX) { + search_itv.addr = 0; + search_itv.size = UT64_MAX; + } + + c = 0; + + searchshow = rz_config_get_i(core->config, "search.show"); + param.mode = rz_config_get(core->config, "search.in"); + param.boundaries = rz_core_get_boundaries_select(core, "search.from", "search.to", "search.in"); + + core->search->align = rz_config_get_i(core->config, "search.align"); + searchflags = rz_config_get_i(core->config, "search.flags"); + core->search->maxhits = rz_config_get_i(core->config, "search.maxhits"); + searchprefix = rz_config_get(core->config, "search.prefix"); + core->search->overlap = rz_config_get_i(core->config, "search.overlap"); + core->search->bckwrds = false; + + /* Quick & dirty check for json output */ + if (input[0] && (input[1] == 'j') && (input[0] != ' ')) { + param.outmode = RZ_MODE_JSON; + param_offset++; + } + param.pj = pj_new(); + +reread: + switch (*input) { + case '!': + input++; + param.inverse = true; + goto reread; + case 'b': // "/b" backward search + if (*(++input) == '?') { + RZ_LOG_ERROR("core: Usage: /b [value] backward search, see '/?'\n"); + goto beach; + } + search->bckwrds = true; + if (core->offset) { + RzInterval itv = { 0, core->offset }; + if (!rz_itv_overlap(search_itv, itv)) { + ret = false; + goto beach; + } else { + search_itv = rz_itv_intersect(search_itv, itv); + } + } + goto reread; + case 'o': { // "/o" print the offset of the Previous opcode + ut64 addr, n = input[param_offset - 1] ? rz_num_math(core->num, input + param_offset) : 1; + n = RZ_ABS((st64)n); + if (((st64)n) < 1) { + n = 1; + } + if (!rz_core_prevop_addr(core, core->offset, n, &addr)) { + addr = UT64_MAX; + (void)rz_core_asm_bwdis_len(core, NULL, &addr, n); + } + if (param.outmode == RZ_MODE_JSON) { + rz_cons_printf("[%" PFMT64u "]", addr); + } else { + rz_cons_printf("0x%08" PFMT64x "\n", addr); + } + break; + } + case 'O': { // "/O" alternative to "/o" + ut64 addr, n = input[param_offset - 1] ? rz_num_math(core->num, input + param_offset) : 1; + if (!n) { + n = 1; + } + addr = rz_core_prevop_addr_force(core, core->offset, n); + if (param.outmode == RZ_MODE_JSON) { + rz_cons_printf("[%" PFMT64u "]", addr); + } else { + rz_cons_printf("0x%08" PFMT64x "\n", addr); + } + break; + } + case 'r': // "/r" + { + ut64 n = (input[1] == ' ' || (input[1] && input[2] == ' ')) + ? rz_num_math(core->num, input + 2) + : UT64_MAX; + if (n == 0LL) { + RZ_LOG_ERROR("core: Cannot find null references.\n"); + break; + } + switch (input[1]) { + case 'c': // "/rc" + { + RzListIter *iter; + RzIOMap *map; + rz_list_foreach (param.boundaries, iter, map) { + eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); + rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 'c'); + } + } break; + case 'a': // "/ra" + { + RzListIter *iter; + RzIOMap *map; + rz_list_foreach (param.boundaries, iter, map) { + eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); + rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 0); + } + } break; + case 'r': // "/rr" - read refs + { + RzListIter *iter; + RzIOMap *map; + rz_list_foreach (param.boundaries, iter, map) { + eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); + rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 'r'); + } + } break; + case 'w': // "/rw" - write refs + { + RzListIter *iter; + RzIOMap *map; + rz_list_foreach (param.boundaries, iter, map) { + eprintf("-- 0x%" PFMT64x " 0x%" PFMT64x "\n", map->itv.addr, rz_itv_end(map->itv)); + rz_core_analysis_search(core, map->itv.addr, rz_itv_end(map->itv), n, 'w'); + } + } break; + case ' ': // "/r $$" + case 0: // "/r" + { + RzListIter *iter; + RzIOMap *map; + rz_list_foreach (param.boundaries, iter, map) { + ut64 from = map->itv.addr; + ut64 to = rz_itv_end(map->itv); + if (input[param_offset - 1] == ' ') { + rz_core_analysis_search(core, from, to, + rz_num_math(core->num, input + 2), 0); + do_ref_search(core, rz_num_math(core->num, input + 2), from, to, ¶m); + } else { + rz_core_analysis_search(core, from, to, core->offset, 0); + do_ref_search(core, core->offset, from, to, ¶m); + } + if (rz_cons_is_breaked()) { + break; + } + } + } break; + } + } break; + case 'a': // "/a" + if (input[1] == 'd') { // "ad" + dosearch = 0; + do_asm_search(core, ¶m, input + 2, 0, search_itv); + } else if (input[1] == 'e') { // "ae" + dosearch = 0; + do_asm_search(core, ¶m, input + 2, 'e', search_itv); + } else if (input[1] == 'c') { // "/ac" + dosearch = 0; + do_asm_search(core, ¶m, input + 2, 'c', search_itv); + } else if (input[1] == 'o') { // "/ao" + dosearch = 0; + do_asm_search(core, ¶m, input + 2, 'o', search_itv); + } else if (input[1] == 'a') { // "/aa" + dosearch = 0; + do_asm_search(core, ¶m, input + 2, 'a', search_itv); + } else if (input[1] == 'i') { // "/ai" + do_asm_search(core, ¶m, input + 2, 'i', search_itv); + } else if (input[1] == '1') { // "a1" + __core_cmd_search_asm_byteswap(core, (int)rz_num_math(core->num, input + 2)); + } else if (input[1] == 'I') { // "/aI" - infinite + __core_cmd_search_asm_infinite(core, rz_str_trim_head_ro(input + 1)); + } else if (input[1] == ' ') { + if (input[param_offset - 1]) { + char *kwd = rz_core_asm_search(core, input + param_offset); + if (!kwd) { + ret = false; + goto beach; + } + dosearch = true; + rz_search_reset(core->search, RZ_SEARCH_KEYWORD); + rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); + rz_search_kw_add(core->search, + rz_search_keyword_new_hexmask(kwd, NULL)); + free(kwd); + } + } else if (input[1] == 's') { + if (input[2] == 'l') { // "asl" + rz_core_cmd0(core, "asl"); + } else { // "as" + do_syscall_search(core, ¶m); + } + dosearch = false; + } else { + dosearch = do_analysis_search(core, ¶m, input + 1); + } + break; + case 'c': { // "/c" + dosearch = true; + switch (input[1]) { + case 'c': // "/cc" + { + ret = false; + char *space = strchr(input, ' '); + const char *arg = space ? rz_str_trim_head_ro(space + 1) : NULL; + if (!arg || input[2] == '?') { + RZ_LOG_ERROR("core: Usage: /cc[aAdlpb] [hashname] [hexpairhashvalue]\n"); + RZ_LOG_ERROR("core: /cca - lowercase alphabet chars only\n"); + RZ_LOG_ERROR("core: /ccA - uppercase alphabet chars only\n"); + RZ_LOG_ERROR("core: /ccl - letters (lower + upper alphabet chars)\n"); + RZ_LOG_ERROR("core: /ccd - digits (only numbers)\n"); + RZ_LOG_ERROR("core: /ccp - printable (alpha + digit)\n"); + RZ_LOG_ERROR("core: /ccb - binary (any number is valid)\n"); + goto beach; + } + char *s = rz_str_dup(arg); + char *sp = strchr(s, ' '); + int mode = input[2]; + if (sp) { + *sp = 0; + sp++; + char *hashName = s; + ut8 *hashValue = (ut8 *)rz_str_dup(sp); + if (hashValue) { + if (!rz_str_startswith((const char *)hashValue, "0x")) { + // TODO: support bigger hashes + int hashLength = 4; + ut32 n = (ut32)rz_num_get(NULL, (const char *)hashValue); + memcpy(hashValue, (const ut8 *)&n, sizeof(ut32)); + search_collisions(core, hashName, hashValue, hashLength, mode); + } else { + int hashLength = rz_hex_str2bin(sp, hashValue); + if (hashLength > 0) { + search_collisions(core, hashName, hashValue, hashLength, mode); + } else { + RZ_LOG_ERROR("core: Invalid expected hash hexpairs.\n"); + } + } + free(hashValue); + } else { + RZ_LOG_ERROR("core: Cannot allocate memory.\n"); + } + ret = true; + } else { + RZ_LOG_ERROR("core: Usage: /cc [hashname] [hexpairhashvalue]\n"); + RZ_LOG_ERROR("core: Usage: /CC to search ascii collisions\n"); + } + free(s); + goto beach; + } break; + case 'd': // "cd" + { + // Certificate with version number + RzSearchKeyword *kw_1 = rz_search_keyword_new_hex("30820000308100A0030201", "ffff0000fffc00ffffffff", NULL); + RzSearchKeyword *kw_2 = rz_search_keyword_new_hex("3082000030820000A0030201", "ffff0000fffc0000ffffffff", NULL); + // Certificate with serial number + RzSearchKeyword *kw_3 = rz_search_keyword_new_hex("308200003082000002", "ffff0000fffc0000ff", NULL); + rz_search_reset(core->search, RZ_SEARCH_KEYWORD); + if (kw_1 && kw_2 && kw_3) { + rz_search_kw_add(core->search, kw_1); + rz_search_kw_add(core->search, kw_2); + rz_search_kw_add(core->search, kw_3); + rz_search_begin(core->search); + } else { + RZ_LOG_ERROR("core: null pointer on search keyword\n"); + dosearch = false; + } + } break; + case 'a': // "ca" + { + RzSearchKeyword *kw; + kw = rz_search_keyword_new_hexmask("00", NULL); + // AES search is done over 40 bytes + kw->keyword_length = AES_SEARCH_LENGTH; + rz_search_reset(core->search, RZ_SEARCH_AES); + rz_search_kw_add(search, kw); + rz_search_begin(core->search); + param.aes_search = true; + break; + } + case 'r': // "cr" + { + RzSearchKeyword *kw; + kw = rz_search_keyword_new_hexmask("00", NULL); + // Private key search is at least 11 bytes + kw->keyword_length = PRIVATE_KEY_SEARCH_LENGTH; + rz_search_reset(core->search, RZ_SEARCH_PRIV_KEY); + rz_search_kw_add(search, kw); + rz_search_begin(core->search); + param.privkey_search = true; + break; + } + default: { + dosearch = false; + } + } + } break; + case 'm': // "/m" + dosearch = false; + if (input[1] == 'b') { // "/mb" + bool bin_verbose = rz_config_get_i(core->config, "bin.verbose"); + rz_config_set_i(core->config, "bin.verbose", false); + // TODO : iter maps? + cmd_search_bin(core, search_itv); + rz_config_set_i(core->config, "bin.verbose", bin_verbose); + } else if (input[1] == ' ' || input[1] == '\0' || param.outmode == RZ_MODE_JSON) { + int ret; + const char *file = input[param_offset - 1] ? input + param_offset : NULL; + ut64 addr = search_itv.addr; + RzListIter *iter; + RzIOMap *map; + if (param.outmode == RZ_MODE_JSON) { + pj_a(param.pj); + } + rz_core_magic_reset(core); + int maxHits = rz_config_get_i(core->config, "search.maxhits"); + int hits = 0; + rz_list_foreach (param.boundaries, iter, map) { + if (param.outmode != RZ_MODE_JSON) { + eprintf("-- %llx %llx\n", map->itv.addr, rz_itv_end(map->itv)); + } + rz_cons_break_push(NULL, NULL); + for (addr = map->itv.addr; addr < rz_itv_end(map->itv); addr++) { + if (rz_cons_is_breaked()) { + break; + } + ret = rz_core_magic_at(core, file, addr, 99, false, param.outmode == RZ_MODE_JSON ? param.pj : NULL, &hits); + if (ret == -1) { + // something went terribly wrong. + break; + } + if (maxHits && hits >= maxHits) { + break; + } + addr += ret - 1; + } + rz_cons_clear_line(1); + rz_cons_break_pop(); + } + if (param.outmode == RZ_MODE_JSON) { + pj_end(param.pj); + } + } else { + RZ_LOG_ERROR("core: Usage: /m [file]\n"); + } + rz_cons_clear_line(1); + break; + case 'p': // "/p" + { + if (input[param_offset - 1]) { + int ps = atoi(input + param_offset); + if (ps > 1) { + RzListIter *iter; + RzIOMap *map; + rz_list_foreach (param.boundaries, iter, map) { + eprintf("-- %llx %llx\n", map->itv.addr, rz_itv_end(map->itv)); + rz_cons_break_push(NULL, NULL); + rz_search_pattern_size(core->search, ps); + rz_search_pattern(core->search, map->itv.addr, rz_itv_end(map->itv)); + rz_cons_break_pop(); + } + break; + } + } + RZ_LOG_ERROR("core: Invalid pattern size (must be > 0)\n"); + } break; + case 'P': // "/P" + search_similar_pattern(core, atoi(input + 1), ¶m); + break; + case 'V': // "/V" + { + if (input[2] == 'j') { + param.outmode = RZ_MODE_JSON; + param_offset++; + } else if (strchr(input + 1, '*')) { + param.outmode = RZ_MODE_RIZINCMD; + } + int err = 1, vsize = atoi(input + 1); + const char *num_str = input + param_offset + 1; + if (vsize && input[2] && num_str) { + if (param.outmode == RZ_MODE_JSON) { + pj_a(param.pj); + } + char *w = strchr(num_str, ' '); + if (w) { + *w++ = 0; + ut64 vmin = rz_num_math(core->num, num_str); + ut64 vmax = rz_num_math(core->num, w); + if (vsize > 0) { + RzIOMap *map; + RzListIter *iter; + rz_list_foreach (param.boundaries, iter, map) { + err = 0; + int hits = rz_core_search_value_in_range(core, map->itv, + vmin, vmax, vsize, + _CbInRangeSearchV, ¶m); + if (param.outmode != RZ_MODE_JSON) { + eprintf("hits: %d\n", hits); + } + } + } + } + if (param.outmode == RZ_MODE_JSON) { + pj_end(param.pj); + } + } + if (err) { + RZ_LOG_ERROR("core: Usage: /V[1|2|4|8] [minval] [maxval]\n"); + } + } + dosearch = false; + break; + case 'v': // "/v" + if (input[1]) { + if (input[1] == '?') { + rz_cons_print("Usage: /v[1|2|4|8] [value]\n"); + break; + } + if (input[2] == 'j') { + param.outmode = RZ_MODE_JSON; + param_offset++; + } + } + rz_search_reset(core->search, RZ_SEARCH_KEYWORD); + rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); + char *v_str = (char *)rz_str_trim_head_ro(input + param_offset); + RzList *nums = rz_num_str_split_list(v_str); + int len = rz_list_length(nums); + int bsize = 0; + ut8 *v_buf = NULL; + switch (input[1]) { + case '8': + if (input[param_offset]) { + bsize = sizeof(ut64) * len; + v_buf = v_writebuf(core, nums, len, '8', bsize); + } else { + RZ_LOG_ERROR("core: Usage: /v8 value\n"); + } + break; + case '1': + if (input[param_offset]) { + bsize = sizeof(ut8) * len; + v_buf = v_writebuf(core, nums, len, '1', bsize); + } else { + RZ_LOG_ERROR("core: Usage: /v1 value\n"); + } + break; + case '2': + if (input[param_offset]) { + bsize = sizeof(ut16) * len; + v_buf = v_writebuf(core, nums, len, '2', bsize); + } else { + RZ_LOG_ERROR("core: Usage: /v2 value\n"); + } + break; + default: // default size + case '4': + if (input[param_offset - 1]) { + if (input[param_offset]) { + bsize = sizeof(ut32) * len; + v_buf = v_writebuf(core, nums, len, '4', bsize); + } + } else { + RZ_LOG_ERROR("core: Usage: /v4 value\n"); + } + break; + } + if (v_buf) { + rz_search_kw_add(core->search, + rz_search_keyword_new((const ut8 *)v_buf, bsize, NULL, 0, NULL)); + free(v_buf); + } + rz_search_begin(core->search); + dosearch = true; + break; + case 'e': // "/e" match regexp + if (input[1] == '?') { + RZ_LOG_ERROR("core: Usage: /e /foo/i or /e/foo/i\n"); + } else if (input[1]) { + RzSearchKeyword *kw; + kw = rz_search_keyword_new_regexp(input + 1, NULL); + if (!kw) { + RZ_LOG_ERROR("core: Invalid regexp specified\n"); + break; + } + rz_search_reset(core->search, RZ_SEARCH_REGEXP); + // TODO distance is unused + rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); + rz_search_kw_add(core->search, kw); + rz_search_begin(core->search); + dosearch = true; + param.regex_search = true; + } else { + RZ_LOG_ERROR("core: Missing regex\n"); + } + break; + case 'E': // "/E" + if (core->bin && core->bin->is_debugger) { + rz_debug_map_sync(core->dbg); + } + do_esil_search(core, ¶m, input); + goto beach; + case 'd': // "/d" search delta key + if (input[1]) { + rz_search_reset(core->search, RZ_SEARCH_DELTAKEY); + rz_search_kw_add(core->search, + rz_search_keyword_new_hexmask(input + param_offset, NULL)); + rz_search_begin(core->search); + dosearch = true; + } else { + RZ_LOG_ERROR("core: Missing delta\n"); + } + break; + case 'h': // "/h" + { + char *p, *arg = rz_str_trim_dup(input + 1); + p = strchr(arg, ' '); + if (p) { + *p++ = 0; + if (*arg == '?') { + RZ_LOG_ERROR("core: Usage: /h md5 [hash] [datalen]\n"); + } else { + ut32 min = UT32_MAX; + ut32 max = UT32_MAX; + char *pmax, *pmin = strchr(p, ' '); + if (pmin) { + *pmin++ = 0; + pmax = strchr(pmin, ' '); + if (pmax) { + *pmax++ = 0; + max = rz_num_math(core->num, pmax); + } + min = rz_num_math(core->num, pmin); + } + search_hash(core, arg, p, min, max, ¶m); + } + } else { + RZ_LOG_ERROR("core: Missing hash. See ph?\n"); + } + free(arg); + } break; + case 'f': // "/f" forward search + if (core->offset) { + RzInterval itv = { core->offset, -core->offset }; + if (!rz_itv_overlap(search_itv, itv)) { + ret = false; + goto beach; + } else { + search_itv = rz_itv_intersect(search_itv, itv); + } + } + break; + case 'g': // "/g" graph search + if (input[1] == '?') { + rz_cons_printf("Usage: /g[g] [fromaddr] @ [toaddr]\n"); + rz_cons_printf("(find all graph paths A to B (/gg follow jumps, see search.count and analysis.depth)"); + } else { + ut64 addr = UT64_MAX; + if (input[1]) { + addr = rz_num_math(core->num, input + 2); + } else { + RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); + if (fcn) { + addr = fcn->addr; + } else { + addr = core->offset; + } + } + const int depth = rz_config_get_i(core->config, "analysis.depth"); + // Va;ifate input length + if (input[1] != '\0') { + rz_core_analysis_paths(core, addr, core->offset, input[1] == 'g', depth, (input[1] == 'j' || input[2] == 'j')); + } + } + break; + case 'F': // "/F" search file /F [file] ([offset] ([sz])) + if (input[param_offset - 1] == ' ') { + int n_args; + char **args = rz_str_argv(input + param_offset, &n_args); + ut8 *buf = NULL; + ut64 offset = 0; + size_t size; + buf = (ut8 *)rz_file_slurp(args[0], &size); + if (!buf) { + RZ_LOG_ERROR("core: Cannot open '%s'\n", args[0]); + rz_str_argv_free(args); + break; + } + if (n_args > 1) { + offset = rz_num_math(core->num, args[1]); + if (size <= offset) { + RZ_LOG_ERROR("core: size <= offset\n"); + rz_str_argv_free(args); + free(buf); + break; + } + } + if (n_args > 2) { + len = rz_num_math(core->num, args[2]); + if (len > size - offset) { + RZ_LOG_ERROR("core: len too large\n"); + rz_str_argv_free(args); + free(buf); + break; + } + } else { + len = size - offset; + } + RzSearchKeyword *kw; + rz_search_reset(core->search, RZ_SEARCH_KEYWORD); + rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); + kw = rz_search_keyword_new(buf + offset, len, NULL, 0, NULL); + if (kw) { + rz_search_kw_add(core->search, kw); + // eprintf ("Searching %d byte(s)...\n", kw->keyword_length); + rz_search_begin(core->search); + dosearch = true; + } else { + RZ_LOG_ERROR("core: no keyword\n"); + } + + rz_str_argv_free(args); + free(buf); + } else { + RZ_LOG_ERROR("core: Usage: /F[j] [file] ([offset] ([sz]))\n"); + } + break; + case 's': // "/s" + do_section_search(core, ¶m, input + 1); + break; + case '+': // "/+" + if (input[1] == ' ') { + // TODO: support /+j + char *buf = malloc(strlen(input) * 2); + char *str = rz_str_dup(input + 2); + int ochunksize; + int i, len, chunksize = rz_config_get_i(core->config, "search.chunk"); + if (chunksize < 1) { + chunksize = core->rasm->bits / 8; + } + len = rz_str_unescape(str); + ochunksize = chunksize = RZ_MIN(len, chunksize); + RZ_LOG_ERROR("core: Using chunksize: %d\n", chunksize); + core->in_search = false; + for (i = 0; i < len; i += chunksize) { + chunksize = ochunksize; + again: + rz_hex_bin2str((ut8 *)str + i, RZ_MIN(chunksize, len - i), buf); + RZ_LOG_ERROR("core: /x %s\n", buf); + rz_core_cmdf(core, "/x %s", buf); + if (core->num->value == 0) { + chunksize--; + if (chunksize < 1) { + RZ_LOG_ERROR("core: Oops\n"); + free(buf); + free(str); + goto beach; + } + RZ_LOG_ERROR("core: Repeat with chunk size %d\n", chunksize); + goto again; + } + } + free(str); + free(buf); + } else { + RZ_LOG_ERROR("core: Usage: /+ [string]\n"); + } + break; + default: + RZ_LOG_ERROR("core: See /? for help.\n"); + break; + } + rz_config_set_i(core->config, "search.kwidx", search->n_kws); + if (dosearch) { + do_string_search(core, search_itv, ¶m); + } +beach: + core->num->value = search->nhits; + core->in_search = false; + rz_flag_space_pop(core->flags); + if (param.outmode == RZ_MODE_JSON) { + rz_cons_println(pj_string(param.pj)); + } + pj_free(param.pj); + rz_list_free(param.boundaries); + rz_search_kw_reset(search); + return ret; +} + +static int pass_to_legacy_api(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + RzStrBuf *legacy_input = rz_strbuf_new(argv[0]); + switch (mode) { + default: + break; + case RZ_OUTPUT_MODE_JSON: + rz_strbuf_append(legacy_input, "j"); + break; + } + // Append arguments + for (size_t i = 1; i < argc; i++) { + rz_strbuf_appendf(legacy_input, " %s", argv[i]); + } + bool succeeded = cmd_search_legacy_handler(core, rz_strbuf_get(legacy_input)); + rz_strbuf_free(legacy_input); + return succeeded ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; } // New search @@ -1889,81 +2534,256 @@ static RzCmdStatus cmd_core_handle_search_hits(RzCore *core, RzCmdStateOutput *s return RZ_CMD_STATUS_OK; } +// "/+" +RZ_IPI RzCmdStatus rz_cmd_search_str_chunk_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + // "/a" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; +RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/a1" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/aI" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/aa" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ac" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ad" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, mode); +} + +// "/ad/" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slash_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ad/a" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slasha_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ae" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/afl" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_fl_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ai" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_i_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, mode); +} + +// "/al" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/am" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ao" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/asl" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_sl_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/atl" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_tl_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/ca" RZ_IPI RzCmdStatus rz_cmd_search_aes_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, state->mode); +} + +// "/cc" +RZ_IPI RzCmdStatus rz_cmd_search_collision_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } -// "/cp" -RZ_IPI RzCmdStatus rz_cmd_search_private_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; +// "/cr" +RZ_IPI RzCmdStatus rz_cmd_search_private_key_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} +// "/cd" +RZ_IPI RzCmdStatus rz_cmd_search_certs_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/d" +RZ_IPI RzCmdStatus rz_cmd_search_deltified_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/e" RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/ei" RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, state->mode); +} + +// "/E" +RZ_IPI RzCmdStatus rz_cmd_search_esil_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, mode); +} + +// "/F" +RZ_IPI RzCmdStatus rz_cmd_search_file_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/g" RZ_IPI RzCmdStatus rz_cmd_search_graph_path_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/gg" RZ_IPI RzCmdStatus rz_cmd_search_graph_path_follow_jumps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/h" RZ_IPI RzCmdStatus rz_cmd_search_hash_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/m" -RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; +RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } -// "/E" -RZ_IPI RzCmdStatus rz_cmd_search_entropy_section_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; +// "/mb" +RZ_IPI RzCmdStatus rz_cmd_search_magic_bin_headers_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/o" +RZ_IPI RzCmdStatus rz_cmd_search_insn_offset_backwards_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/O" +RZ_IPI RzCmdStatus rz_cmd_search_insn_offset_backwards_fallback_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/p" +RZ_IPI RzCmdStatus rz_cmd_search_pattern_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/P" +RZ_IPI RzCmdStatus rz_cmd_search_blocks_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/r" -RZ_IPI RzCmdStatus rz_cmd_search_reference_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; +RZ_IPI RzCmdStatus rz_cmd_search_reference_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/ra" +RZ_IPI RzCmdStatus rz_cmd_search_reference_all_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/rc" +RZ_IPI RzCmdStatus rz_cmd_search_reference_call_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/rr" +RZ_IPI RzCmdStatus rz_cmd_search_reference_read_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/rw" +RZ_IPI RzCmdStatus rz_cmd_search_reference_write_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/rx" +RZ_IPI RzCmdStatus rz_cmd_search_reference_execute_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/s" +RZ_IPI RzCmdStatus rz_cmd_search_sections_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/v1" RZ_IPI RzCmdStatus rz_cmd_search_value_8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/v2" RZ_IPI RzCmdStatus rz_cmd_search_value_16_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/v4" RZ_IPI RzCmdStatus rz_cmd_search_value_32_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/v8" RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return RZ_CMD_STATUS_NONEXISTINGCMD; + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } +// "/V1" +RZ_IPI RzCmdStatus rz_cmd_search_value_8be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/V2" +RZ_IPI RzCmdStatus rz_cmd_search_value_16be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/V4" +RZ_IPI RzCmdStatus rz_cmd_search_value_32be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + +// "/V8" +RZ_IPI RzCmdStatus rz_cmd_search_value_64be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + + static RzSearchOpt *setup_search_options(RzCore *core) { RzSearchOpt *search_opts = rz_search_opt_new(); if (!(rz_search_opt_set_max_hits(search_opts, rz_config_get_i(core->config, "search.maxhits")) && diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index bcb1be665aa..98a9dd813dd 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -14,8 +14,10 @@ static const RzCmdDescDetail alias_details[2]; static const RzCmdDescDetail oparen__details[2]; static const RzCmdDescDetail pointer_details[2]; static const RzCmdDescDetail interpret_macro_multiple_details[2]; +static const RzCmdDescDetail cmd_search_collision_details[2]; static const RzCmdDescDetail cmd_search_hash_block_details[2]; static const RzCmdDescDetail slash_v_details[2]; +static const RzCmdDescDetail slash_V_details[2]; static const RzCmdDescDetail cmd_search_hex_details[2]; static const RzCmdDescDetail slash_z_details[3]; static const RzCmdDescDetail base64_encode_details[2]; @@ -110,13 +112,39 @@ static const RzCmdDescArg interpret_output_args[2]; static const RzCmdDescArg interpret_pipe_args[2]; static const RzCmdDescArg interpret_macro_args[4]; static const RzCmdDescArg interpret_macro_multiple_args[4]; +static const RzCmdDescArg cmd_search_str_chunk_args[2]; static const RzCmdDescArg cmd_search_assemble_args[2]; +static const RzCmdDescArg cmd_search_assemble_1_args[2]; +static const RzCmdDescArg cmd_search_assemble_a_args[2]; +static const RzCmdDescArg cmd_search_assemble_c_args[2]; +static const RzCmdDescArg cmd_search_assemble_d_args[2]; +static const RzCmdDescArg cmd_search_assemble_d_slash_args[2]; +static const RzCmdDescArg cmd_search_assemble_d_slasha_args[2]; +static const RzCmdDescArg cmd_search_assemble_e_args[2]; +static const RzCmdDescArg cmd_search_assemble_fl_args[2]; +static const RzCmdDescArg cmd_search_assemble_f_args[2]; +static const RzCmdDescArg cmd_search_assemble_i_args[3]; +static const RzCmdDescArg cmd_search_assemble_m_args[2]; +static const RzCmdDescArg cmd_search_assemble_o_args[2]; +static const RzCmdDescArg cmd_search_assemble_sl_args[2]; +static const RzCmdDescArg cmd_search_assemble_s_args[2]; +static const RzCmdDescArg cmd_search_assemble_tl_args[2]; +static const RzCmdDescArg cmd_search_assemble_t_args[2]; +static const RzCmdDescArg cmd_search_collision_args[4]; +static const RzCmdDescArg cmd_search_deltified_args[2]; +static const RzCmdDescArg cmd_search_file_args[4]; +static const RzCmdDescArg cmd_search_insn_offset_backwards_args[2]; +static const RzCmdDescArg cmd_search_insn_offset_backwards_fallback_args[2]; +static const RzCmdDescArg cmd_search_pattern_args[2]; +static const RzCmdDescArg cmd_search_blocks_args[2]; +static const RzCmdDescArg cmd_search_sections_args[2]; static const RzCmdDescArg cmd_search_regex_raw_sensitive_args[2]; static const RzCmdDescArg cmd_search_regex_raw_insensitive_args[2]; static const RzCmdDescArg cmd_search_graph_path_args[3]; static const RzCmdDescArg cmd_search_graph_path_follow_jumps_args[3]; static const RzCmdDescArg cmd_search_hash_block_args[3]; -static const RzCmdDescArg cmd_search_entropy_section_args[2]; +static const RzCmdDescArg cmd_search_magic_const_args[2]; +static const RzCmdDescArg cmd_search_esil_args[2]; static const RzCmdDescArg cmd_search_reference_args[2]; static const RzCmdDescArg cmd_info_gadget_args[2]; static const RzCmdDescArg cmd_search_gadget_args[2]; @@ -126,6 +154,10 @@ static const RzCmdDescArg cmd_search_value_8_args[2]; static const RzCmdDescArg cmd_search_value_16_args[2]; static const RzCmdDescArg cmd_search_value_32_args[2]; static const RzCmdDescArg cmd_search_value_64_args[2]; +static const RzCmdDescArg cmd_search_value_8be_args[2]; +static const RzCmdDescArg cmd_search_value_16be_args[2]; +static const RzCmdDescArg cmd_search_value_32be_args[2]; +static const RzCmdDescArg cmd_search_value_64be_args[2]; static const RzCmdDescArg cmd_search_hex_args[2]; static const RzCmdDescArg cmd_search_string_sensitive_args[4]; static const RzCmdDescArg remote_args[3]; @@ -1400,9 +1432,26 @@ static const RzCmdDescHelp interpret_macro_multiple_help = { static const RzCmdDescHelp slash__help = { .summary = "Search for bytes, regexps, patterns, ..", }; +static const RzCmdDescArg cmd_search_str_chunk_args[] = { + { + .name = "/bin/sh", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_str_chunk_help = { + .summary = "Construct the string with chunks.", + .args = cmd_search_str_chunk_args, +}; + +static const RzCmdDescHelp slash_a_help = { + .summary = "Assemble the instruction and search its bytes.", +}; static const RzCmdDescArg cmd_search_assemble_args[] = { { - .name = "opcodes", + .name = "asm-text", .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, @@ -1410,29 +1459,434 @@ static const RzCmdDescArg cmd_search_assemble_args[] = { { 0 }, }; static const RzCmdDescHelp cmd_search_assemble_help = { - .summary = "Assemble the opcodes and search its bytes", + .summary = "Assemble the instruction and search its bytes", .args = cmd_search_assemble_args, }; +static const RzCmdDescArg cmd_search_assemble_1_args[] = { + { + .name = "number", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_1_help = { + .summary = "Find valid assembly generated by changing only the nth byte", + .args = cmd_search_assemble_1_args, +}; + +static const RzCmdDescArg cmd_search_assemble_I_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_I_help = { + .summary = "Search for infinite loop instructions (jmp $$)", + .args = cmd_search_assemble_I_args, +}; + +static const RzCmdDescArg cmd_search_assemble_a_args[] = { + { + .name = "asm-text", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_a_help = { + .summary = "Linearly find aproximated assembly (case insensitive strstr)", + .args = cmd_search_assemble_a_args, +}; + +static const RzCmdDescArg cmd_search_assemble_c_args[] = { + { + .name = "asm-text", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_c_help = { + .summary = "Same as /aa, but case-sensitive", + .args = cmd_search_assemble_c_args, +}; + +static const RzCmdDescArg cmd_search_assemble_d_args[] = { + { + .name = "mnem;mov", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_d_help = { + .summary = "Match ins1 followed by ins2 in linear disasm", + .args = cmd_search_assemble_d_args, +}; + +static const RzCmdDescArg cmd_search_assemble_d_slash_args[] = { + { + .name = "ins1;ins2", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_d_slash_help = { + .summary = "Search for regex instruction 'ins1' followed by regex 'ins2'", + .args = cmd_search_assemble_d_slash_args, +}; + +static const RzCmdDescArg cmd_search_assemble_d_slasha_args[] = { + { + .name = "instr", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_d_slasha_help = { + .summary = "Search for every byte instruction that matches regexp 'instr'", + .args = cmd_search_assemble_d_slasha_args, +}; + +static const RzCmdDescArg cmd_search_assemble_e_args[] = { + { + .name = "esil", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_e_help = { + .summary = "Search for esil expressions matching substring", + .args = cmd_search_assemble_e_args, +}; + +static const RzCmdDescArg cmd_search_assemble_f_args[] = { + { + .name = "family", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_f_help = { + .summary = "Search for instruction of specific family (afl=list", + .args = cmd_search_assemble_f_args, +}; +static const RzCmdDescArg cmd_search_assemble_fl_args[] = { + { + .name = "family", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_fl_help = { + .summary = "Search for instruction of specific family. List mode.", + .args = cmd_search_assemble_fl_args, +}; + +static const RzCmdDescArg cmd_search_assemble_i_args[] = { + { + .name = "0x300", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "0x500", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_i_help = { + .summary = "Find all the instructions using that immediate (in range)", + .args = cmd_search_assemble_i_args, +}; + +static const RzCmdDescArg cmd_search_assemble_l_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_l_help = { + .summary = "Same as aoml, list all opcodes", + .args = cmd_search_assemble_l_args, +}; + +static const RzCmdDescArg cmd_search_assemble_m_args[] = { + { + .name = "opcode", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_m_help = { + .summary = "Search for specific instructions of specific mnemonic", + .args = cmd_search_assemble_m_args, +}; + +static const RzCmdDescArg cmd_search_assemble_o_args[] = { + { + .name = "instr", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_o_help = { + .summary = "Search for instruction 'instr' (in all offsets)", + .args = cmd_search_assemble_o_args, +}; + +static const RzCmdDescArg cmd_search_assemble_s_args[] = { + { + .name = "type", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_s_help = { + .summary = "Search for syscalls (See /at swi and /af priv)", + .args = cmd_search_assemble_s_args, +}; +static const RzCmdDescArg cmd_search_assemble_sl_args[] = { + { + .name = "type", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_sl_help = { + .summary = "Search for syscalls (See /at swi and /af priv). List mode.", + .args = cmd_search_assemble_sl_args, +}; + +static const RzCmdDescArg cmd_search_assemble_t_args[] = { + { + .name = "type", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_t_help = { + .summary = "Search for instructions of given type", + .args = cmd_search_assemble_t_args, +}; +static const RzCmdDescArg cmd_search_assemble_tl_args[] = { + { + .name = "type", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_assemble_tl_help = { + .summary = "Search for instructions of given type. List mode.", + .args = cmd_search_assemble_tl_args, +}; + static const RzCmdDescHelp slash_c_help = { - .summary = "Cryptographic material search", + .summary = "Cryptographic material search.", }; static const RzCmdDescArg cmd_search_aes_key_args[] = { { 0 }, }; static const RzCmdDescHelp cmd_search_aes_key_help = { - .summary = "Search for AES keys", + .summary = "Search for AES keys.", .args = cmd_search_aes_key_args, }; +static const RzCmdDescDetailEntry cmd_search_collision_Modes_detail_entries[] = { + { .text = "a", .arg_str = NULL, .comment = "lowercase alphabet chars only" }, + { .text = "A", .arg_str = NULL, .comment = "uppercase alphabet chars only" }, + { .text = "l", .arg_str = NULL, .comment = "letters (lower + upper alphabet chars)" }, + { .text = "d", .arg_str = NULL, .comment = "digits (only numbers)" }, + { .text = "p", .arg_str = NULL, .comment = "printable (alpha + digit)" }, + { .text = "b", .arg_str = NULL, .comment = "binary (any number is valid)" }, + { 0 }, +}; +static const RzCmdDescDetail cmd_search_collision_details[] = { + { .name = "Modes", .entries = cmd_search_collision_Modes_detail_entries }, + { 0 }, +}; +static const char *cmd_search_collision_mode_choices[] = { "p", "a", "A", "l", "d", "b", NULL }; +static const RzCmdDescArg cmd_search_collision_args[] = { + { + .name = "mode", + .type = RZ_CMD_ARG_TYPE_CHOICES, + .choices.choices = cmd_search_collision_mode_choices, + + }, + { + .name = "algo", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "digest", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_collision_help = { + .summary = "Find collisions (bruteforce block length values until given checksum is found).", + .details = cmd_search_collision_details, + .args = cmd_search_collision_args, +}; + static const RzCmdDescArg cmd_search_private_key_args[] = { { 0 }, }; static const RzCmdDescHelp cmd_search_private_key_help = { - .summary = "Search for private RSA/ECC/EdDSA keys", + .summary = "Search for private RSA/ECC/EdDSA keys.", .args = cmd_search_private_key_args, }; +static const RzCmdDescArg cmd_search_certs_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_certs_help = { + .summary = "Search for ASN1/DER certificates.", + .args = cmd_search_certs_args, +}; + +static const RzCmdDescArg cmd_search_deltified_args[] = { + { + .name = "101112", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_deltified_help = { + .summary = "Search for a deltified sequence of bytes.", + .args = cmd_search_deltified_args, +}; + +static const RzCmdDescArg cmd_search_file_args[] = { + { + .name = "file", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "offset", + .type = RZ_CMD_ARG_TYPE_STRING, + + }, + { + .name = "size", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_file_help = { + .summary = "Search contents of file with offset and size.", + .args = cmd_search_file_args, +}; + +static const RzCmdDescArg cmd_search_insn_offset_backwards_args[] = { + { + .name = "n", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_insn_offset_backwards_help = { + .summary = "Show offset of n instructions backward.", + .args = cmd_search_insn_offset_backwards_args, +}; + +static const RzCmdDescArg cmd_search_insn_offset_backwards_fallback_args[] = { + { + .name = "n", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_insn_offset_backwards_fallback_help = { + .summary = "Same as /o, but with a different fallback if analysis cannot be used.", + .args = cmd_search_insn_offset_backwards_fallback_args, +}; + +static const RzCmdDescArg cmd_search_pattern_args[] = { + { + .name = "patternsize", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_pattern_help = { + .summary = "Search for pattern of given size.", + .args = cmd_search_pattern_args, +}; + +static const RzCmdDescArg cmd_search_blocks_args[] = { + { + .name = "patternsize", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_blocks_help = { + .summary = "Search similar blocks.", + .args = cmd_search_blocks_args, +}; + +static const RzCmdDescArg cmd_search_sections_args[] = { + { + .name = "threshold", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_sections_help = { + .summary = "Search sections by grouping blocks with similar entropy.", + .args = cmd_search_sections_args, +}; + static const RzCmdDescHelp slash_e_help = { .summary = "Raw regular expression search.", }; @@ -1533,7 +1987,17 @@ static const RzCmdDescHelp cmd_search_hash_block_help = { .args = cmd_search_hash_block_args, }; +static const RzCmdDescHelp slash_m_help = { + .summary = "Magic constants search.", +}; static const RzCmdDescArg cmd_search_magic_const_args[] = { + { + .name = "magic-file", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, + + }, { 0 }, }; static const RzCmdDescHelp cmd_search_magic_const_help = { @@ -1541,24 +2005,35 @@ static const RzCmdDescHelp cmd_search_magic_const_help = { .args = cmd_search_magic_const_args, }; -static const RzCmdDescArg cmd_search_entropy_section_args[] = { +static const RzCmdDescArg cmd_search_magic_bin_headers_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_magic_bin_headers_help = { + .summary = "Search recognized RzBin headers.", + .args = cmd_search_magic_bin_headers_args, +}; + +static const RzCmdDescArg cmd_search_esil_args[] = { { - .name = "threshold", + .name = "esil-expr", .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, }, { 0 }, }; -static const RzCmdDescHelp cmd_search_entropy_section_help = { - .summary = "Entropy search on sections by grouping in blocks.", - .args = cmd_search_entropy_section_args, +static const RzCmdDescHelp cmd_search_esil_help = { + .summary = "offset matching given esil expressions $$ = here.", + .args = cmd_search_esil_args, }; +static const RzCmdDescHelp slash_r_help = { + .summary = "Reference search.", +}; static const RzCmdDescArg cmd_search_reference_args[] = { { .name = "address", - .type = RZ_CMD_ARG_TYPE_RZNUM, + .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, }, @@ -1569,6 +2044,46 @@ static const RzCmdDescHelp cmd_search_reference_help = { .args = cmd_search_reference_args, }; +static const RzCmdDescArg cmd_search_reference_all_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_reference_all_help = { + .summary = "Search all references.", + .args = cmd_search_reference_all_args, +}; + +static const RzCmdDescArg cmd_search_reference_call_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_reference_call_help = { + .summary = "Search call references.", + .args = cmd_search_reference_call_args, +}; + +static const RzCmdDescArg cmd_search_reference_read_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_reference_read_help = { + .summary = "Search read references.", + .args = cmd_search_reference_read_args, +}; + +static const RzCmdDescArg cmd_search_reference_write_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_reference_write_help = { + .summary = "Search write references.", + .args = cmd_search_reference_write_args, +}; + +static const RzCmdDescArg cmd_search_reference_execute_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_search_reference_execute_help = { + .summary = "Search execute references.", + .args = cmd_search_reference_execute_args, +}; + static const RzCmdDescHelp slash_R_help = { .summary = "Search, List, Query for ROP Gadgets", }; @@ -1697,6 +2212,70 @@ static const RzCmdDescHelp cmd_search_value_64_help = { .args = cmd_search_value_64_args, }; +static const RzCmdDescDetailEntry slash_V_Usage_space_example_detail_entries[] = { + { .text = "512 value search of its 32-bit representation", .arg_str = NULL, .comment = "/V4 512" }, + { 0 }, +}; +static const RzCmdDescDetail slash_V_details[] = { + { .name = "Usage example", .entries = slash_V_Usage_space_example_detail_entries }, + { 0 }, +}; +static const RzCmdDescHelp slash_V_help = { + .summary = "Value search.", + .details = slash_V_details, +}; +static const RzCmdDescArg cmd_search_value_8be_args[] = { + { + .name = "value8", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_8be_help = { + .summary = "8-bit value search.", + .args = cmd_search_value_8be_args, +}; + +static const RzCmdDescArg cmd_search_value_16be_args[] = { + { + .name = "value16", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_16be_help = { + .summary = "16-bit size value search.", + .args = cmd_search_value_16be_args, +}; + +static const RzCmdDescArg cmd_search_value_32be_args[] = { + { + .name = "value32", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_32be_help = { + .summary = "32-bit size value search.", + .args = cmd_search_value_32be_args, +}; + +static const RzCmdDescArg cmd_search_value_64be_args[] = { + { + .name = "value64", + .type = RZ_CMD_ARG_TYPE_NUM, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_value_64be_help = { + .summary = "64-bit size value search.", + .args = cmd_search_value_64be_args, +}; + static const RzCmdDescDetailEntry cmd_search_hex_Usage_space_example_detail_entries[] = { { .text = "Hexadecimal search for the exact bytes 'ffcc33'.", .arg_str = NULL, .comment = "/x ffcc33" }, { .text = "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits.", .arg_str = NULL, .comment = "/x ff..33.0" }, @@ -20181,9 +20760,62 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *slash__cd = rz_cmd_desc_group_new(core->rcmd, root_cd, "/", NULL, NULL, &slash__help); rz_warn_if_fail(slash__cd); - RzCmdDesc *cmd_search_assemble_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/a", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_assemble_handler, &cmd_search_assemble_help); - rz_warn_if_fail(cmd_search_assemble_cd); - rz_cmd_desc_set_default_mode(cmd_search_assemble_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_str_chunk_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash__cd, "/+", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_str_chunk_handler, &cmd_search_str_chunk_help); + rz_warn_if_fail(cmd_search_str_chunk_cd); + rz_cmd_desc_set_default_mode(cmd_search_str_chunk_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *slash_a_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/a", rz_cmd_search_assemble_handler, &cmd_search_assemble_help, &slash_a_help); + rz_warn_if_fail(slash_a_cd); + RzCmdDesc *cmd_search_assemble_1_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/a1", rz_cmd_search_assemble_1_handler, &cmd_search_assemble_1_help); + rz_warn_if_fail(cmd_search_assemble_1_cd); + + RzCmdDesc *cmd_search_assemble_I_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/aI", rz_cmd_search_assemble_I_handler, &cmd_search_assemble_I_help); + rz_warn_if_fail(cmd_search_assemble_I_cd); + + RzCmdDesc *cmd_search_assemble_a_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/aa", rz_cmd_search_assemble_a_handler, &cmd_search_assemble_a_help); + rz_warn_if_fail(cmd_search_assemble_a_cd); + + RzCmdDesc *cmd_search_assemble_c_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ac", rz_cmd_search_assemble_c_handler, &cmd_search_assemble_c_help); + rz_warn_if_fail(cmd_search_assemble_c_cd); + + RzCmdDesc *cmd_search_assemble_d_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ad", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_d_handler, &cmd_search_assemble_d_help); + rz_warn_if_fail(cmd_search_assemble_d_cd); + + RzCmdDesc *cmd_search_assemble_d_slash_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ad/", rz_cmd_search_assemble_d_slash_handler, &cmd_search_assemble_d_slash_help); + rz_warn_if_fail(cmd_search_assemble_d_slash_cd); + + RzCmdDesc *cmd_search_assemble_d_slasha_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ad/a", rz_cmd_search_assemble_d_slasha_handler, &cmd_search_assemble_d_slasha_help); + rz_warn_if_fail(cmd_search_assemble_d_slasha_cd); + + RzCmdDesc *cmd_search_assemble_e_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ae", rz_cmd_search_assemble_e_handler, &cmd_search_assemble_e_help); + rz_warn_if_fail(cmd_search_assemble_e_cd); + + RzCmdDesc *cmd_search_assemble_f_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/af", NULL, NULL, &cmd_search_assemble_f_help); + rz_warn_if_fail(cmd_search_assemble_f_cd); + RzCmdDesc *cmd_search_assemble_fl_cd = rz_cmd_desc_argv_new(core->rcmd, cmd_search_assemble_f_cd, "/afl", rz_cmd_search_assemble_fl_handler, &cmd_search_assemble_fl_help); + rz_warn_if_fail(cmd_search_assemble_fl_cd); + + RzCmdDesc *cmd_search_assemble_i_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ai", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_i_handler, &cmd_search_assemble_i_help); + rz_warn_if_fail(cmd_search_assemble_i_cd); + + RzCmdDesc *cmd_search_assemble_l_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/al", rz_cmd_search_assemble_l_handler, &cmd_search_assemble_l_help); + rz_warn_if_fail(cmd_search_assemble_l_cd); + + RzCmdDesc *cmd_search_assemble_m_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/am", rz_cmd_search_assemble_m_handler, &cmd_search_assemble_m_help); + rz_warn_if_fail(cmd_search_assemble_m_cd); + + RzCmdDesc *cmd_search_assemble_o_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ao", rz_cmd_search_assemble_o_handler, &cmd_search_assemble_o_help); + rz_warn_if_fail(cmd_search_assemble_o_cd); + + RzCmdDesc *cmd_search_assemble_s_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/as", NULL, NULL, &cmd_search_assemble_s_help); + rz_warn_if_fail(cmd_search_assemble_s_cd); + RzCmdDesc *cmd_search_assemble_sl_cd = rz_cmd_desc_argv_new(core->rcmd, cmd_search_assemble_s_cd, "/asl", rz_cmd_search_assemble_sl_handler, &cmd_search_assemble_sl_help); + rz_warn_if_fail(cmd_search_assemble_sl_cd); + + RzCmdDesc *cmd_search_assemble_t_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/at", NULL, NULL, &cmd_search_assemble_t_help); + rz_warn_if_fail(cmd_search_assemble_t_cd); + RzCmdDesc *cmd_search_assemble_tl_cd = rz_cmd_desc_argv_new(core->rcmd, cmd_search_assemble_t_cd, "/atl", rz_cmd_search_assemble_tl_handler, &cmd_search_assemble_tl_help); + rz_warn_if_fail(cmd_search_assemble_tl_cd); RzCmdDesc *slash_c_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/c", NULL, NULL, &slash_c_help); rz_warn_if_fail(slash_c_cd); @@ -20191,9 +20823,42 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_aes_key_cd); rz_cmd_desc_set_default_mode(cmd_search_aes_key_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *cmd_search_private_key_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_c_cd, "/cp", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_private_key_handler, &cmd_search_private_key_help); + RzCmdDesc *cmd_search_collision_cd = rz_cmd_desc_argv_new(core->rcmd, slash_c_cd, "/cc", rz_cmd_search_collision_handler, &cmd_search_collision_help); + rz_warn_if_fail(cmd_search_collision_cd); + + RzCmdDesc *cmd_search_private_key_cd = rz_cmd_desc_argv_new(core->rcmd, slash_c_cd, "/cr", rz_cmd_search_private_key_handler, &cmd_search_private_key_help); rz_warn_if_fail(cmd_search_private_key_cd); - rz_cmd_desc_set_default_mode(cmd_search_private_key_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_certs_cd = rz_cmd_desc_argv_new(core->rcmd, slash_c_cd, "/cd", rz_cmd_search_certs_handler, &cmd_search_certs_help); + rz_warn_if_fail(cmd_search_certs_cd); + + RzCmdDesc *cmd_search_deltified_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash__cd, "/d", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_deltified_handler, &cmd_search_deltified_help); + rz_warn_if_fail(cmd_search_deltified_cd); + rz_cmd_desc_set_default_mode(cmd_search_deltified_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_file_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash__cd, "/F", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_file_handler, &cmd_search_file_help); + rz_warn_if_fail(cmd_search_file_cd); + rz_cmd_desc_set_default_mode(cmd_search_file_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_insn_offset_backwards_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/o", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_insn_offset_backwards_handler, &cmd_search_insn_offset_backwards_help); + rz_warn_if_fail(cmd_search_insn_offset_backwards_cd); + rz_cmd_desc_set_default_mode(cmd_search_insn_offset_backwards_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_insn_offset_backwards_fallback_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/O", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_insn_offset_backwards_fallback_handler, &cmd_search_insn_offset_backwards_fallback_help); + rz_warn_if_fail(cmd_search_insn_offset_backwards_fallback_cd); + rz_cmd_desc_set_default_mode(cmd_search_insn_offset_backwards_fallback_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_pattern_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/p", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_pattern_handler, &cmd_search_pattern_help); + rz_warn_if_fail(cmd_search_pattern_cd); + rz_cmd_desc_set_default_mode(cmd_search_pattern_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_blocks_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/P", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_blocks_handler, &cmd_search_blocks_help); + rz_warn_if_fail(cmd_search_blocks_cd); + rz_cmd_desc_set_default_mode(cmd_search_blocks_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_sections_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/s", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_sections_handler, &cmd_search_sections_help); + rz_warn_if_fail(cmd_search_sections_cd); + rz_cmd_desc_set_default_mode(cmd_search_sections_cd, RZ_OUTPUT_MODE_STANDARD); RzCmdDesc *slash_e_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/e", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_regex_raw_sensitive_handler, &cmd_search_regex_raw_sensitive_help, &slash_e_help); rz_warn_if_fail(slash_e_cd); @@ -20213,17 +20878,30 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_hash_block_cd); rz_cmd_desc_set_default_mode(cmd_search_hash_block_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *cmd_search_magic_const_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/m", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_magic_const_handler, &cmd_search_magic_const_help); - rz_warn_if_fail(cmd_search_magic_const_cd); - rz_cmd_desc_set_default_mode(cmd_search_magic_const_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *slash_m_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/m", rz_cmd_search_magic_const_handler, &cmd_search_magic_const_help, &slash_m_help); + rz_warn_if_fail(slash_m_cd); + RzCmdDesc *cmd_search_magic_bin_headers_cd = rz_cmd_desc_argv_new(core->rcmd, slash_m_cd, "/mb", rz_cmd_search_magic_bin_headers_handler, &cmd_search_magic_bin_headers_help); + rz_warn_if_fail(cmd_search_magic_bin_headers_cd); + + RzCmdDesc *cmd_search_esil_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash__cd, "/E", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_esil_handler, &cmd_search_esil_help); + rz_warn_if_fail(cmd_search_esil_cd); + + RzCmdDesc *slash_r_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/r", rz_cmd_search_reference_handler, &cmd_search_reference_help, &slash_r_help); + rz_warn_if_fail(slash_r_cd); + RzCmdDesc *cmd_search_reference_all_cd = rz_cmd_desc_argv_new(core->rcmd, slash_r_cd, "/ra", rz_cmd_search_reference_all_handler, &cmd_search_reference_all_help); + rz_warn_if_fail(cmd_search_reference_all_cd); - RzCmdDesc *cmd_search_entropy_section_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/E", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_entropy_section_handler, &cmd_search_entropy_section_help); - rz_warn_if_fail(cmd_search_entropy_section_cd); - rz_cmd_desc_set_default_mode(cmd_search_entropy_section_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_reference_call_cd = rz_cmd_desc_argv_new(core->rcmd, slash_r_cd, "/rc", rz_cmd_search_reference_call_handler, &cmd_search_reference_call_help); + rz_warn_if_fail(cmd_search_reference_call_cd); - RzCmdDesc *cmd_search_reference_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/r", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_reference_handler, &cmd_search_reference_help); - rz_warn_if_fail(cmd_search_reference_cd); - rz_cmd_desc_set_default_mode(cmd_search_reference_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_reference_read_cd = rz_cmd_desc_argv_new(core->rcmd, slash_r_cd, "/rr", rz_cmd_search_reference_read_handler, &cmd_search_reference_read_help); + rz_warn_if_fail(cmd_search_reference_read_cd); + + RzCmdDesc *cmd_search_reference_write_cd = rz_cmd_desc_argv_new(core->rcmd, slash_r_cd, "/rw", rz_cmd_search_reference_write_handler, &cmd_search_reference_write_help); + rz_warn_if_fail(cmd_search_reference_write_cd); + + RzCmdDesc *cmd_search_reference_execute_cd = rz_cmd_desc_argv_new(core->rcmd, slash_r_cd, "/rx", rz_cmd_search_reference_execute_handler, &cmd_search_reference_execute_help); + rz_warn_if_fail(cmd_search_reference_execute_cd); RzCmdDesc *slash_R_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/R", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_info_gadget_handler, &cmd_info_gadget_help, &slash_R_help); rz_warn_if_fail(slash_R_cd); @@ -20258,6 +20936,24 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_value_64_cd); rz_cmd_desc_set_default_mode(cmd_search_value_64_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *slash_V_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/V", NULL, NULL, &slash_V_help); + rz_warn_if_fail(slash_V_cd); + RzCmdDesc *cmd_search_value_8be_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_V_cd, "/V1", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_8be_handler, &cmd_search_value_8be_help); + rz_warn_if_fail(cmd_search_value_8be_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_8be_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_value_16be_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_V_cd, "/V2", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_16be_handler, &cmd_search_value_16be_help); + rz_warn_if_fail(cmd_search_value_16be_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_16be_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_value_32be_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_V_cd, "/V4", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_32be_handler, &cmd_search_value_32be_help); + rz_warn_if_fail(cmd_search_value_32be_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_32be_cd, RZ_OUTPUT_MODE_STANDARD); + + RzCmdDesc *cmd_search_value_64be_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_V_cd, "/V8", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_64be_handler, &cmd_search_value_64be_help); + rz_warn_if_fail(cmd_search_value_64be_cd); + rz_cmd_desc_set_default_mode(cmd_search_value_64be_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_hex_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/x", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_hex_handler, &cmd_search_hex_help); rz_warn_if_fail(cmd_search_hex_cd); rz_cmd_desc_set_default_mode(cmd_search_hex_cd, RZ_OUTPUT_MODE_STANDARD); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 257709ba498..1d0917057c9 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -61,12 +61,62 @@ RZ_IPI RzCmdStatus rz_interpret_pipe_handler(RzCore *core, int argc, const char RZ_IPI RzCmdStatus rz_interpret_macro_handler(RzCore *core, int argc, const char **argv); // "..(" RZ_IPI RzCmdStatus rz_interpret_macro_multiple_handler(RzCore *core, int argc, const char **argv); +// "/+" +RZ_IPI RzCmdStatus rz_cmd_search_str_chunk_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/a" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv); +// "/a1" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, const char **argv); +// "/aI" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv); +// "/aa" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv); +// "/ac" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv); +// "/ad" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); +// "/ad/" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slash_handler(RzCore *core, int argc, const char **argv); +// "/ad/a" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slasha_handler(RzCore *core, int argc, const char **argv); +// "/ae" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv); +// "/afl" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_fl_handler(RzCore *core, int argc, const char **argv); +// "/ai" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_i_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); +// "/al" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, const char **argv); +// "/am" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv); +// "/ao" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv); +// "/asl" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_sl_handler(RzCore *core, int argc, const char **argv); +// "/atl" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_tl_handler(RzCore *core, int argc, const char **argv); // "/ca" RZ_IPI RzCmdStatus rz_cmd_search_aes_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); -// "/cp" -RZ_IPI RzCmdStatus rz_cmd_search_private_key_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/cc" +RZ_IPI RzCmdStatus rz_cmd_search_collision_handler(RzCore *core, int argc, const char **argv); +// "/cr" +RZ_IPI RzCmdStatus rz_cmd_search_private_key_handler(RzCore *core, int argc, const char **argv); +// "/cd" +RZ_IPI RzCmdStatus rz_cmd_search_certs_handler(RzCore *core, int argc, const char **argv); +// "/d" +RZ_IPI RzCmdStatus rz_cmd_search_deltified_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); +// "/F" +RZ_IPI RzCmdStatus rz_cmd_search_file_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); +// "/o" +RZ_IPI RzCmdStatus rz_cmd_search_insn_offset_backwards_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/O" +RZ_IPI RzCmdStatus rz_cmd_search_insn_offset_backwards_fallback_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/p" +RZ_IPI RzCmdStatus rz_cmd_search_pattern_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/P" +RZ_IPI RzCmdStatus rz_cmd_search_blocks_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/s" +RZ_IPI RzCmdStatus rz_cmd_search_sections_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/e" RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/ei" @@ -78,11 +128,23 @@ RZ_IPI RzCmdStatus rz_cmd_search_graph_path_follow_jumps_handler(RzCore *core, i // "/h" RZ_IPI RzCmdStatus rz_cmd_search_hash_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/m" -RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv); +// "/mb" +RZ_IPI RzCmdStatus rz_cmd_search_magic_bin_headers_handler(RzCore *core, int argc, const char **argv); // "/E" -RZ_IPI RzCmdStatus rz_cmd_search_entropy_section_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +RZ_IPI RzCmdStatus rz_cmd_search_esil_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/r" -RZ_IPI RzCmdStatus rz_cmd_search_reference_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +RZ_IPI RzCmdStatus rz_cmd_search_reference_handler(RzCore *core, int argc, const char **argv); +// "/ra" +RZ_IPI RzCmdStatus rz_cmd_search_reference_all_handler(RzCore *core, int argc, const char **argv); +// "/rc" +RZ_IPI RzCmdStatus rz_cmd_search_reference_call_handler(RzCore *core, int argc, const char **argv); +// "/rr" +RZ_IPI RzCmdStatus rz_cmd_search_reference_read_handler(RzCore *core, int argc, const char **argv); +// "/rw" +RZ_IPI RzCmdStatus rz_cmd_search_reference_write_handler(RzCore *core, int argc, const char **argv); +// "/rx" +RZ_IPI RzCmdStatus rz_cmd_search_reference_execute_handler(RzCore *core, int argc, const char **argv); // "/R" RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/R/" @@ -99,6 +161,14 @@ RZ_IPI RzCmdStatus rz_cmd_search_value_16_handler(RzCore *core, int argc, const RZ_IPI RzCmdStatus rz_cmd_search_value_32_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/v8" RZ_IPI RzCmdStatus rz_cmd_search_value_64_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/V1" +RZ_IPI RzCmdStatus rz_cmd_search_value_8be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/V2" +RZ_IPI RzCmdStatus rz_cmd_search_value_16be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/V4" +RZ_IPI RzCmdStatus rz_cmd_search_value_32be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/V8" +RZ_IPI RzCmdStatus rz_cmd_search_value_64be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/x" RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/z" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 663eea74cc1..a7ff1e30709 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -3,10 +3,9 @@ --- name: cmd_search commands: - - name: "/a" - summary: Assemble the opcodes and search its bytes - cname: cmd_search_assemble - type: RZ_CMD_DESC_TYPE_ARGV_STATE + - name: "/+" + summary: Construct the string with chunks. + cname: cmd_search_str_chunk default_mode: RZ_OUTPUT_MODE_STANDARD modes: - RZ_OUTPUT_MODE_STANDARD @@ -14,14 +13,142 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: opcodes + - name: "/bin/sh" type: RZ_CMD_ARG_TYPE_STRING - + - name: "/a" + summary: Assemble the instruction and search its bytes. + subcommands: + - name: "/a" + summary: Assemble the instruction and search its bytes + cname: cmd_search_assemble + args: + - name: asm-text + type: RZ_CMD_ARG_TYPE_STRING + - name: "/a1" + summary: "Find valid assembly generated by changing only the nth byte" + cname: cmd_search_assemble_1 + args: + - name: "number" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/aI" + summary: "Search for infinite loop instructions (jmp $$)" + cname: cmd_search_assemble_I + args: [] + - name: "/aa" + summary: "Linearly find aproximated assembly (case insensitive strstr)" + cname: cmd_search_assemble_a + args: + - name: "asm-text" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ac" + summary: "Same as /aa, but case-sensitive" + cname: cmd_search_assemble_c + args: + - name: "asm-text" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ad" + summary: "Match ins1 followed by ins2 in linear disasm" + cname: cmd_search_assemble_d + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + args: + - name: "mnem;mov" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ad/" + summary: "Search for regex instruction 'ins1' followed by regex 'ins2'" + cname: cmd_search_assemble_d_slash + args: + - name: "ins1;ins2" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ad/a" + summary: "Search for every byte instruction that matches regexp 'instr'" + cname: cmd_search_assemble_d_slasha + args: + - name: "instr" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ae" + summary: "Search for esil expressions matching substring" + cname: cmd_search_assemble_e + args: + - name: "esil" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/af" + summary: "Search for instruction of specific family (afl=list" + cname: cmd_search_assemble_f + args: + - name: "family" + type: RZ_CMD_ARG_TYPE_STRING + subcommands: + - name: "/afl" + summary: "Search for instruction of specific family. List mode." + cname: cmd_search_assemble_fl + args: + - name: "family" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ai" + summary: "Find all the instructions using that immediate (in range)" + cname: cmd_search_assemble_i + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + args: + - name: "0x300" + type: RZ_CMD_ARG_TYPE_STRING + - name: "0x500" + optional: true + type: RZ_CMD_ARG_TYPE_STRING + - name: "/al" + summary: "Same as aoml, list all opcodes" + cname: cmd_search_assemble_l + args: [] + - name: "/am" + summary: "Search for specific instructions of specific mnemonic" + cname: cmd_search_assemble_m + args: + - name: "opcode" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ao" + summary: "Search for instruction 'instr' (in all offsets)" + cname: cmd_search_assemble_o + args: + - name: "instr" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/as" + summary: "Search for syscalls (See /at swi and /af priv)" + cname: cmd_search_assemble_s + args: + - name: "type" + optional: true + type: RZ_CMD_ARG_TYPE_STRING + subcommands: + - name: "/asl" + summary: "Search for syscalls (See /at swi and /af priv). List mode." + cname: cmd_search_assemble_sl + args: + - name: "type" + optional: true + type: RZ_CMD_ARG_TYPE_STRING + - name: "/at" + summary: "Search for instructions of given type" + cname: cmd_search_assemble_t + args: + - name: "type" + optional: true + type: RZ_CMD_ARG_TYPE_STRING + subcommands: + - name: "/atl" + summary: "Search for instructions of given type. List mode." + cname: cmd_search_assemble_tl + args: + - name: "type" + optional: true + type: RZ_CMD_ARG_TYPE_STRING - name: "/c" - summary: Cryptographic material search + summary: Cryptographic material search. subcommands: - name: "/ca" - summary: Search for AES keys + summary: Search for AES keys. cname: cmd_search_aes_key type: RZ_CMD_DESC_TYPE_ARGV_STATE default_mode: RZ_OUTPUT_MODE_STANDARD @@ -31,18 +158,141 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: [] - - name: "/cp" - summary: Search for private RSA/ECC/EdDSA keys + - name: "/cc" + summary: Find collisions (bruteforce block length values until given checksum is found). + cname: cmd_search_collision + args: + - name: "mode" + type: RZ_CMD_ARG_TYPE_CHOICES + choices: + - "p" + - "a" + - "A" + - "l" + - "d" + - "b" + - name: "algo" + type: RZ_CMD_ARG_TYPE_STRING + - name: "digest" + type: RZ_CMD_ARG_TYPE_STRING + details: + - name: Modes + entries: + - text: a + comment: "lowercase alphabet chars only" + - text: A + comment: "uppercase alphabet chars only" + - text: l + comment: "letters (lower + upper alphabet chars)" + - text: d + comment: "digits (only numbers)" + - text: p + comment: "printable (alpha + digit)" + - text: b + comment: "binary (any number is valid)" + - name: "/cr" + summary: Search for private RSA/ECC/EdDSA keys. cname: cmd_search_private_key - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE args: [] - + - name: "/cd" + summary: Search for ASN1/DER certificates. + cname: cmd_search_certs + args: [] + - name: "/d" + summary: Search for a deltified sequence of bytes. + cname: cmd_search_deltified + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "101112" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/F" + summary: Search contents of file with offset and size. + cname: cmd_search_file + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "file" + type: RZ_CMD_ARG_TYPE_STRING + - name: "offset" + type: RZ_CMD_ARG_TYPE_STRING + - name: "size" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/o" + summary: Show offset of n instructions backward. + cname: cmd_search_insn_offset_backwards + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "n" + optional: true + type: RZ_CMD_ARG_TYPE_STRING + - name: "/O" + summary: Same as /o, but with a different fallback if analysis cannot be used. + cname: cmd_search_insn_offset_backwards_fallback + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "n" + optional: true + type: RZ_CMD_ARG_TYPE_STRING + - name: "/p" + summary: Search for pattern of given size. + cname: cmd_search_pattern + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "patternsize" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/P" + summary: Search similar blocks. + cname: cmd_search_blocks + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "patternsize" + type: RZ_CMD_ARG_TYPE_STRING + - name: "/s" + summary: Search sections by grouping blocks with similar entropy. + cname: cmd_search_sections + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: "threshold" + type: RZ_CMD_ARG_TYPE_STRING - name: "/e" summary: Raw regular expression search. subcommands: @@ -130,43 +380,58 @@ commands: - name: "/m" summary: Magic constants search. - cname: cmd_search_magic_const - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE - args: [] - + subcommands: + - name: "/m" + summary: Magic constants search. + cname: cmd_search_magic_const + args: + - name: magic-file + optional: true + type: RZ_CMD_ARG_TYPE_STRING + - name: "/mb" + summary: Search recognized RzBin headers. + cname: cmd_search_magic_bin_headers + args: [] + - name: "/E" - summary: Entropy search on sections by grouping in blocks. - cname: cmd_search_entropy_section - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD + summary: offset matching given esil expressions $$ = here. + cname: cmd_search_esil modes: - RZ_OUTPUT_MODE_STANDARD - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE args: - - name: threshold + - name: esil-expr type: RZ_CMD_ARG_TYPE_STRING - name: "/r" summary: Reference search. - cname: cmd_search_reference - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE - args: - - name: address - type: RZ_CMD_ARG_TYPE_RZNUM + subcommands: + - name: "/r" + summary: Reference search. + cname: cmd_search_reference + args: + - name: address + type: RZ_CMD_ARG_TYPE_STRING + - name: "/ra" + summary: Search all references. + cname: cmd_search_reference_all + args: [] + - name: "/rc" + summary: Search call references. + cname: cmd_search_reference_call + args: [] + - name: "/rr" + summary: Search read references. + cname: cmd_search_reference_read + args: [] + - name: "/rw" + summary: Search write references. + cname: cmd_search_reference_write + args: [] + - name: "/rx" + summary: Search execute references. + cname: cmd_search_reference_execute + args: [] - name: "/R" summary: Search, List, Query for ROP Gadgets @@ -289,7 +554,69 @@ commands: entries: - text: "512 value search of its 32-bit representation" comment: "/v4 512" + - name: "/V" + summary: Value search. + subcommands: + - name: "/V1" + summary: 8-bit value search. + cname: cmd_search_value_8be + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value8 + type: RZ_CMD_ARG_TYPE_NUM + + - name: "/V2" + summary: 16-bit size value search. + cname: cmd_search_value_16be + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value16 + type: RZ_CMD_ARG_TYPE_NUM + + - name: "/V4" + summary: 32-bit size value search. + cname: cmd_search_value_32be + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value32 + type: RZ_CMD_ARG_TYPE_NUM + - name: "/V8" + summary: 64-bit size value search. + cname: cmd_search_value_64be + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: value64 + type: RZ_CMD_ARG_TYPE_NUM + details: + - name: Usage example + entries: + - text: "512 value search of its 32-bit representation" + comment: "/V4 512" - name: "/x" summary: Raw hexadecimal search. cname: cmd_search_hex diff --git a/librz/search/bytepat.c b/librz/search/bytepat.c new file mode 100644 index 00000000000..4d776db57d3 --- /dev/null +++ b/librz/search/bytepat.c @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2006-2019 esteve +// SPDX-FileCopyrightText: 2006-2019 pancake +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include + +#define CTXMINB 5 +#define BSIZE (1024 * 1024) +#define MAX_PATLEN 1024 + +typedef struct _fnditem { + unsigned char str[MAX_PATLEN]; + void *next; +} fnditem; + +static fnditem *init_fi(void) { + fnditem *n; + n = (fnditem *)malloc(sizeof(fnditem)); + if (!n) { + return NULL; + } + n->next = NULL; + return n; +} + +static void fini_fi(fnditem *fi) { + fnditem *fu; + fu = fi; + while (fi->next) { + fu = fi; + fi = fi->next; + free(fu); + fu = NULL; + } + free(fu); +} + +static void add_fi(fnditem *n, unsigned char *blk, int patlen) { + fnditem *p; + for (p = n; p->next != NULL; p = p->next) { + ; + } + p->next = (fnditem *)malloc(sizeof(fnditem)); + p = p->next; + memcpy(p->str, blk, patlen); + p->next = NULL; +} + +static int is_fi_present(fnditem *n, unsigned char *blk, int patlen) { + fnditem *p; + for (p = n; p->next != NULL; p = p->next) { + if (!memcmp(blk, p->str, patlen)) { + return true; + } + } + return false; +} + +RZ_API int rz_search_pattern(RzSearch *s, ut64 from, ut64 to) { + ut8 block[BSIZE + MAX_PATLEN], sblk[BSIZE + MAX_PATLEN + 1]; + ut64 addr, bact, bytes, intaddr, rb, bproc = 0; + int nr, i, moar = 0, pcnt, cnt = 0, k = 0; + int patlen = s->pattern_size; + fnditem *root; + + eprintf("Searching patterns between 0x%08" PFMT64x " and 0x%08" PFMT64x "\n", from, to); + if (patlen < 1 || patlen > MAX_PATLEN) { + eprintf("Invalid pattern length (must be > 1 and < %d)\n", MAX_PATLEN); + return false; + } + bact = from; + bytes = to; + // bytes += bact; + root = init_fi(); + pcnt = -1; + + // bact = from + // bytes = to + // bproc = from2 + while (bact < bytes) { + addr = bact; + if (rz_print_is_interrupted()) { + break; + } + + bproc = bact + patlen; + // read ( fd, sblk, patlen ); + // XXX bytepattern should be used with a read callback + nr = ((bytes - bproc) < BSIZE) ? (bytes - bproc) : BSIZE; + // XXX rizin_read_at(bact, sblk, patlen); + s->iob.read_at(s->iob.io, addr, sblk, nr); + sblk[patlen] = 0; // XXX + + intaddr = bact; + cnt = 0; + while (bproc < bytes) { + // TODO: handle ^C here + nr = ((bytes - bproc) < BSIZE) ? (bytes - bproc) : BSIZE; + nr += (patlen - (nr % patlen)); // tamany de bloc llegit multiple superior de tamany busqueda + rb = s->iob.read_at(s->iob.io, bproc, block, nr); + if (rb < 1) { + break; + } + nr = rb; + addr += nr; + moar = 0; + for (i = 0; i < nr; i++) { + if (!memcmp(&block[i], sblk, patlen) && !is_fi_present(root, sblk, patlen)) { + if (cnt == 0) { + add_fi(root, sblk, patlen); + pcnt++; + eprintf("\nbytes: %d: ", pcnt); + for (k = 0; k < patlen; k++) { + eprintf("%02x", sblk[k]); + } + eprintf("\nfound: %d: 0x%08" PFMT64x " ", pcnt, intaddr); + } + moar++; + cnt++; + eprintf("0x%08" PFMT64x " ", bproc + i); + } + } + if (moar > 0) { + eprintf("\ncount: %d: %d\n", pcnt, moar + 1); + } + bproc += rb; + } + bact += (moar > 0) ? patlen : 1; + } + eprintf("\n"); + fini_fi(root); + return 0; +} diff --git a/librz/search/meson.build b/librz/search/meson.build index 98191cbd131..b10f24e3e08 100644 --- a/librz/search/meson.build +++ b/librz/search/meson.build @@ -1,5 +1,6 @@ rz_search_sources = [ 'aes-find.c', + 'bytepat.c', 'keyword.c', 'regexp.c', 'privkey-find.c', From eba1afc74f257c344456f9e8e8ed6b7b402a99a1 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 2 Feb 2025 15:17:00 -0500 Subject: [PATCH 070/157] Fix always true condition. --- librz/util/hex.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/librz/util/hex.c b/librz/util/hex.c index c69d3e6aa02..4536bb1f535 100644 --- a/librz/util/hex.c +++ b/librz/util/hex.c @@ -50,7 +50,7 @@ RZ_API ut8 rz_hex_digit_to_byte(const char c) { * * \param The string to parse as hex digit pair. * - * \param The byte value of the nibble pair. + * \return The byte value of the nibble pair. * Or UT16_MAX if the nibble is no hexadecimal character. */ RZ_API ut16 rz_hex_digit_pair_to_byte(const char *npair) { @@ -530,13 +530,13 @@ RZ_API int rz_hex_str2bin_msb(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 * i += 2; } - ut8 byte = 0; + ut16 byte = 0; size_t nibbles = rz_str_ansi_len(in + i); bool odd_nibble = (nibbles % 2) == 1; if (odd_nibble) { byte = rz_hex_digit_to_byte(in[i]); - if (byte == UT8_MAX) { + if (byte >= UT8_MAX) { return 0; } out[j] = byte; @@ -545,7 +545,7 @@ RZ_API int rz_hex_str2bin_msb(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 * } - for (byte = rz_hex_digit_pair_to_byte(in + i); i < strlen(in) && byte != UT16_MAX; j++, i += 2, byte = rz_hex_digit_pair_to_byte(in + i)) { + for (byte = rz_hex_digit_pair_to_byte(in + i); i < strlen(in) && byte <= UT8_MAX; j++, i += 2, byte = rz_hex_digit_pair_to_byte(in + i)) { out[j] = byte; } From 04211c49ebc89f6a03c18644ceffd5ecaf10b674 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 09:28:42 -0500 Subject: [PATCH 071/157] Fix: Add command handler for /as, /af, /at --- librz/core/cmd/cmd_search.c | 15 ++++++++++++ librz/core/cmd_descs/cmd_descs.c | 36 ++++++++++++++++++---------- librz/core/cmd_descs/cmd_descs.h | 6 +++++ librz/core/cmd_descs/cmd_search.yaml | 34 +++++++++++++++----------- 4 files changed, 65 insertions(+), 26 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index b9f72e1e3dd..da9e8bc0534 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2584,6 +2584,11 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, cons return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } +// "/af" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_f_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + // "/afl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_fl_handler(RzCore *core, int argc, const char **argv) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); @@ -2609,11 +2614,21 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, cons return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } +// "/as" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_s_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + // "/asl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_sl_handler(RzCore *core, int argc, const char **argv) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } +// "/at" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_t_handler(RzCore *core, int argc, const char **argv) { + return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +} + // "/atl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_tl_handler(RzCore *core, int argc, const char **argv) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 98a9dd813dd..1125e3e13d8 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -121,15 +121,15 @@ static const RzCmdDescArg cmd_search_assemble_d_args[2]; static const RzCmdDescArg cmd_search_assemble_d_slash_args[2]; static const RzCmdDescArg cmd_search_assemble_d_slasha_args[2]; static const RzCmdDescArg cmd_search_assemble_e_args[2]; -static const RzCmdDescArg cmd_search_assemble_fl_args[2]; static const RzCmdDescArg cmd_search_assemble_f_args[2]; +static const RzCmdDescArg cmd_search_assemble_fl_args[2]; static const RzCmdDescArg cmd_search_assemble_i_args[3]; static const RzCmdDescArg cmd_search_assemble_m_args[2]; static const RzCmdDescArg cmd_search_assemble_o_args[2]; -static const RzCmdDescArg cmd_search_assemble_sl_args[2]; static const RzCmdDescArg cmd_search_assemble_s_args[2]; -static const RzCmdDescArg cmd_search_assemble_tl_args[2]; +static const RzCmdDescArg cmd_search_assemble_sl_args[2]; static const RzCmdDescArg cmd_search_assemble_t_args[2]; +static const RzCmdDescArg cmd_search_assemble_tl_args[2]; static const RzCmdDescArg cmd_search_collision_args[4]; static const RzCmdDescArg cmd_search_deltified_args[2]; static const RzCmdDescArg cmd_search_file_args[4]; @@ -1569,6 +1569,9 @@ static const RzCmdDescHelp cmd_search_assemble_e_help = { .args = cmd_search_assemble_e_args, }; +static const RzCmdDescHelp slash_af_help = { + .summary = "Search for instruction of specific family (afl=list", +}; static const RzCmdDescArg cmd_search_assemble_f_args[] = { { .name = "family", @@ -1582,6 +1585,7 @@ static const RzCmdDescHelp cmd_search_assemble_f_help = { .summary = "Search for instruction of specific family (afl=list", .args = cmd_search_assemble_f_args, }; + static const RzCmdDescArg cmd_search_assemble_fl_args[] = { { .name = "family", @@ -1652,6 +1656,9 @@ static const RzCmdDescHelp cmd_search_assemble_o_help = { .args = cmd_search_assemble_o_args, }; +static const RzCmdDescHelp slash_as_help = { + .summary = "Search for syscalls (See /at swi and /af priv)", +}; static const RzCmdDescArg cmd_search_assemble_s_args[] = { { .name = "type", @@ -1666,6 +1673,7 @@ static const RzCmdDescHelp cmd_search_assemble_s_help = { .summary = "Search for syscalls (See /at swi and /af priv)", .args = cmd_search_assemble_s_args, }; + static const RzCmdDescArg cmd_search_assemble_sl_args[] = { { .name = "type", @@ -1681,6 +1689,9 @@ static const RzCmdDescHelp cmd_search_assemble_sl_help = { .args = cmd_search_assemble_sl_args, }; +static const RzCmdDescHelp slash_at_help = { + .summary = "Search for instructions of given type", +}; static const RzCmdDescArg cmd_search_assemble_t_args[] = { { .name = "type", @@ -1695,6 +1706,7 @@ static const RzCmdDescHelp cmd_search_assemble_t_help = { .summary = "Search for instructions of given type", .args = cmd_search_assemble_t_args, }; + static const RzCmdDescArg cmd_search_assemble_tl_args[] = { { .name = "type", @@ -20790,9 +20802,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_search_assemble_e_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ae", rz_cmd_search_assemble_e_handler, &cmd_search_assemble_e_help); rz_warn_if_fail(cmd_search_assemble_e_cd); - RzCmdDesc *cmd_search_assemble_f_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/af", NULL, NULL, &cmd_search_assemble_f_help); - rz_warn_if_fail(cmd_search_assemble_f_cd); - RzCmdDesc *cmd_search_assemble_fl_cd = rz_cmd_desc_argv_new(core->rcmd, cmd_search_assemble_f_cd, "/afl", rz_cmd_search_assemble_fl_handler, &cmd_search_assemble_fl_help); + RzCmdDesc *slash_af_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/af", rz_cmd_search_assemble_f_handler, &cmd_search_assemble_f_help, &slash_af_help); + rz_warn_if_fail(slash_af_cd); + RzCmdDesc *cmd_search_assemble_fl_cd = rz_cmd_desc_argv_new(core->rcmd, slash_af_cd, "/afl", rz_cmd_search_assemble_fl_handler, &cmd_search_assemble_fl_help); rz_warn_if_fail(cmd_search_assemble_fl_cd); RzCmdDesc *cmd_search_assemble_i_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ai", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_i_handler, &cmd_search_assemble_i_help); @@ -20807,14 +20819,14 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_search_assemble_o_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ao", rz_cmd_search_assemble_o_handler, &cmd_search_assemble_o_help); rz_warn_if_fail(cmd_search_assemble_o_cd); - RzCmdDesc *cmd_search_assemble_s_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/as", NULL, NULL, &cmd_search_assemble_s_help); - rz_warn_if_fail(cmd_search_assemble_s_cd); - RzCmdDesc *cmd_search_assemble_sl_cd = rz_cmd_desc_argv_new(core->rcmd, cmd_search_assemble_s_cd, "/asl", rz_cmd_search_assemble_sl_handler, &cmd_search_assemble_sl_help); + RzCmdDesc *slash_as_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/as", rz_cmd_search_assemble_s_handler, &cmd_search_assemble_s_help, &slash_as_help); + rz_warn_if_fail(slash_as_cd); + RzCmdDesc *cmd_search_assemble_sl_cd = rz_cmd_desc_argv_new(core->rcmd, slash_as_cd, "/asl", rz_cmd_search_assemble_sl_handler, &cmd_search_assemble_sl_help); rz_warn_if_fail(cmd_search_assemble_sl_cd); - RzCmdDesc *cmd_search_assemble_t_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/at", NULL, NULL, &cmd_search_assemble_t_help); - rz_warn_if_fail(cmd_search_assemble_t_cd); - RzCmdDesc *cmd_search_assemble_tl_cd = rz_cmd_desc_argv_new(core->rcmd, cmd_search_assemble_t_cd, "/atl", rz_cmd_search_assemble_tl_handler, &cmd_search_assemble_tl_help); + RzCmdDesc *slash_at_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/at", rz_cmd_search_assemble_t_handler, &cmd_search_assemble_t_help, &slash_at_help); + rz_warn_if_fail(slash_at_cd); + RzCmdDesc *cmd_search_assemble_tl_cd = rz_cmd_desc_argv_new(core->rcmd, slash_at_cd, "/atl", rz_cmd_search_assemble_tl_handler, &cmd_search_assemble_tl_help); rz_warn_if_fail(cmd_search_assemble_tl_cd); RzCmdDesc *slash_c_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/c", NULL, NULL, &slash_c_help); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 1d0917057c9..5bb48c26497 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -81,6 +81,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slash_handler(RzCore *core, int argc RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slasha_handler(RzCore *core, int argc, const char **argv); // "/ae" RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv); +// "/af" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_f_handler(RzCore *core, int argc, const char **argv); // "/afl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_fl_handler(RzCore *core, int argc, const char **argv); // "/ai" @@ -91,8 +93,12 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, cons RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv); // "/ao" RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv); +// "/as" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_s_handler(RzCore *core, int argc, const char **argv); // "/asl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_sl_handler(RzCore *core, int argc, const char **argv); +// "/at" +RZ_IPI RzCmdStatus rz_cmd_search_assemble_t_handler(RzCore *core, int argc, const char **argv); // "/atl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_tl_handler(RzCore *core, int argc, const char **argv); // "/ca" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index a7ff1e30709..b2d317677a1 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -75,11 +75,13 @@ commands: type: RZ_CMD_ARG_TYPE_STRING - name: "/af" summary: "Search for instruction of specific family (afl=list" - cname: cmd_search_assemble_f - args: - - name: "family" - type: RZ_CMD_ARG_TYPE_STRING subcommands: + - name: "/af" + summary: "Search for instruction of specific family (afl=list" + cname: cmd_search_assemble_f + args: + - name: "family" + type: RZ_CMD_ARG_TYPE_STRING - name: "/afl" summary: "Search for instruction of specific family. List mode." cname: cmd_search_assemble_fl @@ -116,12 +118,14 @@ commands: type: RZ_CMD_ARG_TYPE_STRING - name: "/as" summary: "Search for syscalls (See /at swi and /af priv)" - cname: cmd_search_assemble_s - args: - - name: "type" - optional: true - type: RZ_CMD_ARG_TYPE_STRING subcommands: + - name: "/as" + summary: "Search for syscalls (See /at swi and /af priv)" + cname: cmd_search_assemble_s + args: + - name: "type" + optional: true + type: RZ_CMD_ARG_TYPE_STRING - name: "/asl" summary: "Search for syscalls (See /at swi and /af priv). List mode." cname: cmd_search_assemble_sl @@ -131,12 +135,14 @@ commands: type: RZ_CMD_ARG_TYPE_STRING - name: "/at" summary: "Search for instructions of given type" - cname: cmd_search_assemble_t - args: - - name: "type" - optional: true - type: RZ_CMD_ARG_TYPE_STRING subcommands: + - name: "/at" + summary: "Search for instructions of given type" + cname: cmd_search_assemble_t + args: + - name: "type" + optional: true + type: RZ_CMD_ARG_TYPE_STRING - name: "/atl" summary: "Search for instructions of given type. List mode." cname: cmd_search_assemble_tl From da33a2af7216e5785bc4f009c0e6d1ee310453b0 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 09:36:02 -0500 Subject: [PATCH 072/157] Cut '/' from input string because the legacy handler expects this. --- librz/core/cmd/cmd_search.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index da9e8bc0534..318e7d1e725 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2409,7 +2409,9 @@ static int cmd_search_legacy_handler(void *data, const char *input) { } static int pass_to_legacy_api(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - RzStrBuf *legacy_input = rz_strbuf_new(argv[0]); + // The +1 strips the '/', because the legacy handler expect it this way. + const char *cmd = argv[0] + 1; + RzStrBuf *legacy_input = rz_strbuf_new(cmd); switch (mode) { default: break; From a87ab32bc059f296e8ac17e64c89dbe27aa043f5 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 09:38:46 -0500 Subject: [PATCH 073/157] Make offset and size arguments optional for /F. --- librz/core/cmd_descs/cmd_descs.c | 2 ++ librz/core/cmd_descs/cmd_search.yaml | 2 ++ test/db/cmd/cmd_search | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 1125e3e13d8..eaeb974ee6c 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -1812,12 +1812,14 @@ static const RzCmdDescArg cmd_search_file_args[] = { { .name = "offset", .type = RZ_CMD_ARG_TYPE_STRING, + .optional = true, }, { .name = "size", .type = RZ_CMD_ARG_TYPE_STRING, .flags = RZ_CMD_ARG_FLAG_LAST, + .optional = true, }, { 0 }, diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index b2d317677a1..911e6bfa7c4 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -229,8 +229,10 @@ commands: - name: "file" type: RZ_CMD_ARG_TYPE_STRING - name: "offset" + optional: true type: RZ_CMD_ARG_TYPE_STRING - name: "size" + optional: true type: RZ_CMD_ARG_TYPE_STRING - name: "/o" summary: Show offset of n instructions backward. diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index 3e0b30029b7..b88a8de6de8 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -2,7 +2,7 @@ NAME=trailing comment FILE== ARGS=-n CMDS=< Date: Mon, 3 Feb 2025 10:15:12 -0500 Subject: [PATCH 074/157] Move RzSearchHit free() to IPI --- librz/include/rz_search.h | 1 - librz/search/search.c | 2 +- librz/search/search_internal.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index c1e22dbf228..8e2ccd1544e 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -206,7 +206,6 @@ RZ_API RZ_OWN RzSearchCollection *rz_search_collection_magic(RZ_NONNULL const ch RZ_API bool rz_search_collection_match_any(RZ_NULLABLE RzSearchCollection *sc, RZ_NONNULL const ut8 *buffer, size_t length); RZ_API void rz_search_collection_free(RZ_NULLABLE RzSearchCollection *sc); -RZ_API void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit); RZ_API RZ_OWN RzList /**/ *rz_search_on_io(RZ_BORROW RZ_NONNULL RzSearchOpt *opt, RZ_BORROW RZ_NONNULL RzSearchCollection *col, RZ_BORROW RZ_NONNULL RzIO *io, RZ_BORROW RZ_NONNULL RzList /**/ *search_in); diff --git a/librz/search/search.c b/librz/search/search.c index bba40c80aaf..7255574d593 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -759,7 +759,7 @@ RZ_IPI RZ_OWN RzSearchHit *rz_search_hit_new(const char *hit_desc, ut64 address, * * \param hit The RzSearchHit pointer to free */ -RZ_API void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit) { +RZ_IPI void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit) { if (!hit) { return; } diff --git a/librz/search/search_internal.h b/librz/search/search_internal.h index 1319a0a9fba..fa1e64683c6 100644 --- a/librz/search/search_internal.h +++ b/librz/search/search_internal.h @@ -124,6 +124,7 @@ struct rz_search_find_opt_t { }; RZ_IPI RZ_OWN RzSearchHit *rz_search_hit_new(const char *metadata, ut64 address, size_t size); +RZ_IPI void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit); RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_bytes_space(RZ_NONNULL RzSearchFindBytesCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); RZ_IPI RZ_OWN RzSearchCollection *rz_search_collection_new_graph_space(RZ_NONNULL RzSearchFindGraphCallback find, RZ_NONNULL RzSearchIsEmptyCallback is_empty, RZ_NULLABLE RzSearchFreeCallback free, RZ_NULLABLE void *user); From b5408e3da390e6f6044400e2cd06e10c6b597a4d Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 10:37:20 -0500 Subject: [PATCH 075/157] Document rz_strbuf_drain. --- librz/include/rz_util/rz_strbuf.h | 2 +- librz/util/strbuf.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/librz/include/rz_util/rz_strbuf.h b/librz/include/rz_util/rz_strbuf.h index ca07e8066e2..3548da71623 100644 --- a/librz/include/rz_util/rz_strbuf.h +++ b/librz/include/rz_util/rz_strbuf.h @@ -28,7 +28,7 @@ RZ_API bool rz_strbuf_prepend(RzStrBuf *sb, const char *s); RZ_API bool rz_strbuf_appendf(RzStrBuf *sb, const char *fmt, ...) RZ_PRINTF_CHECK(2, 3); RZ_API bool rz_strbuf_vappendf(RzStrBuf *sb, const char *fmt, va_list ap); RZ_API char *rz_strbuf_get(RzStrBuf *sb); -RZ_API RZ_OWN char *rz_strbuf_drain(RzStrBuf *sb); +RZ_API RZ_OWN char *rz_strbuf_drain(RZ_OWN RZ_NONNULL RzStrBuf *sb); RZ_API RZ_OWN char *rz_strbuf_drain_nofree(RzStrBuf *sb); RZ_API size_t rz_strbuf_length(RzStrBuf *sb); RZ_API void rz_strbuf_free(RzStrBuf *sb); diff --git a/librz/util/strbuf.c b/librz/util/strbuf.c index 639aa77bd57..5e09d881ddb 100644 --- a/librz/util/strbuf.c +++ b/librz/util/strbuf.c @@ -313,7 +313,14 @@ static inline char *drain(RzStrBuf *sb) { return sb->ptr ? sb->ptr : rz_str_dup(sb->buf); } -RZ_API RZ_OWN char *rz_strbuf_drain(RzStrBuf *sb) { +/** + * \brief Drains the buffer, frees it and returns the drained string. + * + * \param sb The string buffer to drain. + * + * \return The string of \p sb. + */ +RZ_API RZ_OWN char *rz_strbuf_drain(RZ_OWN RZ_NONNULL RzStrBuf *sb) { rz_return_val_if_fail(sb, NULL); char *ret = drain(sb); free(sb); From efb2f69e49ca4efa2d454ba0e6d11cf9898cd827 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 11:05:56 -0500 Subject: [PATCH 076/157] Clarify that the cmd.hit command is not run when the hit is found. It is run at the end, once all hits are known. Then it is iterated over them and the command is run. --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 974df61e6c2..db9c88cacc7 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3534,7 +3534,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETPREF("cmd.stack", "", "Command to display the stack in visual debug mode"); SETPREF("cmd.cprompt", "", "Column visual prompt commands"); SETPREF("cmd.gprompt", "", "Graph visual prompt commands"); - SETPREF("cmd.hit", "", "Run when a search hit is found"); + SETPREF("cmd.hit", "", "Command to run on every search hit."); SETPREF("cmd.open", "", "Run when file is opened"); SETPREF("cmd.load", "", "Run when binary is loaded"); SETPREF("cmd.prompt", "", "Prompt commands"); From 128c8309747967c6f455b06efd3c4c45edad523f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 11:17:15 -0500 Subject: [PATCH 077/157] Move search hit flag building into function --- librz/core/cmd/cmd_search.c | 12 +++++------ librz/include/rz_search.h | 6 ++++-- librz/search/search.c | 41 +++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 318e7d1e725..0a32c8b3f4c 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2455,10 +2455,10 @@ static bool cmd_search_progress_cancel(void *user, size_t n_hits, RzSearchCancel static void cmd_search_output_to_state(RzCmdStateOutput *state, RzSearchHit *hit, const char *flag_name) { switch (state->mode) { case RZ_OUTPUT_MODE_QUIET: - rz_cons_printf("%08" PFMT64x "\n", hit->address); + rz_cons_printf("0x%08" PFMT64x "\n", hit->address); break; case RZ_OUTPUT_MODE_STANDARD: - rz_cons_printf("%08" PFMT64x " %" PFMTSZu " %s\n", hit->address, hit->size, flag_name); + rz_cons_printf("0x%08" PFMT64x " %" PFMTSZu " %s\n", hit->address, hit->size, flag_name); break; case RZ_OUTPUT_MODE_JSON: pj_o(state->d.pj); @@ -2493,7 +2493,6 @@ static RzCmdStatus cmd_core_handle_search_hits(RzCore *core, RzCmdStateOutput *s RzSearchHit *hit = NULL; const char *cmd_hit = NULL; const char *search_prefix = NULL; - size_t counter = 0; cmd_hit = rz_config_get(core->config, "cmd.hit"); search_prefix = rz_config_get(core->config, "search.prefix"); @@ -2509,19 +2508,18 @@ static RzCmdStatus cmd_core_handle_search_hits(RzCore *core, RzCmdStateOutput *s rz_flag_space_push(core->flags, "search"); } - rz_list_foreach (hits, it, hit) { + size_t i = 0; + rz_list_foreach_enum (hits, it, hit, i) { if (RZ_STR_ISNOTEMPTY(cmd_hit)) { cmd_search_call_command(core, hit, cmd_hit); continue; } // only output & add flag when cmd.hit is not set. - const char *meta = hit->hit_desc ? hit->hit_desc : "match"; - char *flag = rz_str_newf("%s.%s.%" PFMTSZu, search_prefix, meta, counter); + char *flag = rz_search_hit_flag_name(hit, i, search_prefix); rz_flag_set(core->flags, flag, hit->address, hit->size); cmd_search_output_to_state(state, hit, flag); free(flag); - counter++; } if (RZ_STR_ISEMPTY(cmd_hit)) { diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index 8e2ccd1544e..a5a557c7093 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -144,8 +144,8 @@ typedef struct rz_search_collection_t RzSearchCollection; typedef struct rz_search_hit_t { char *hit_desc; ///< Hit description (can be NULL) - ut64 address; ///< Address the matched data - size_t size; ///< Size of the matched data (can be 0) + ut64 address; ///< Address/offset of the matched data. + size_t size; ///< Size of the matched data (can be 0), in bytes. } RzSearchHit; typedef enum { @@ -155,6 +155,8 @@ typedef enum { typedef struct rz_search_bytes_pattern_t RzSearchBytesPattern; +RZ_API RZ_OWN char *rz_search_hit_flag_name(RZ_NONNULL const RzSearchHit *hit, size_t hit_id, RZ_NULLABLE const char *prefix); + RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern *hp); RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp); RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc); diff --git a/librz/search/search.c b/librz/search/search.c index 7255574d593..b94f213db49 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include #include "search_internal.h" @@ -766,3 +769,41 @@ RZ_IPI void rz_search_hit_free(RZ_NULLABLE RzSearchHit *hit) { free(hit->hit_desc); free(hit); } + +/** + * \brief Get a flag name describing the hit. The flag name can be customized. + * + * \param hit The RzSearchHit to build the flag name for. + * \param hit_id The id number of the hit. + * \param prefix An optional prefix for the flag. Defaults to "hit". + * + * Example: + * + * hit = { address = 0x110, hit_desc = "bytes", size = 0x10 } + * prefix = "sb" + * + * Result = sb.bytes.0 + + * hit = { address = 0x110, hit_desc = NULL, size = 0x10 } + * prefix = NULL + * + * Result = hit.0 + * + * \return A flag of \p hit, or NULL in case of failure. + */ +RZ_API RZ_OWN char *rz_search_hit_flag_name(RZ_NONNULL const RzSearchHit *hit, + size_t hit_id, + RZ_NULLABLE const char *prefix) { + rz_return_val_if_fail(hit, NULL); + RzStrBuf *buf = rz_strbuf_new(""); + if (!buf) { + return NULL; + } + rz_strbuf_appendf(buf, "%s", prefix ? prefix : "hit"); + if (hit->hit_desc) { + rz_strbuf_appendf(buf, ".%s", hit->hit_desc); + } + rz_strbuf_appendf(buf, ".%" PFMTSZd, hit_id); + + return rz_strbuf_drain(buf); +} From 049452d4311f3aff163c42c8c25c834bdadf732a Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 11:19:24 -0500 Subject: [PATCH 078/157] Give the byte search a hit description. --- librz/core/cmd/cmd_search.c | 2 +- test/db/cmd/cmd_search_x | 152 ++++++++++++++++++------------------ 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 0a32c8b3f4c..b6674401a79 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2829,7 +2829,7 @@ RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char CMD_SEARCH_BEGIN(); RzList *hits = NULL; - RzSearchBytesPattern *pattern = rz_search_parse_byte_pattern(argv[1], NULL); + RzSearchBytesPattern *pattern = rz_search_parse_byte_pattern(argv[1], "bytes"); if (!pattern) { RZ_LOG_ERROR("Failed to parse given pattern.\n"); diff --git a/test/db/cmd/cmd_search_x b/test/db/cmd/cmd_search_x index aa529eb2a78..52624acfeab 100644 --- a/test/db/cmd/cmd_search_x +++ b/test/db/cmd/cmd_search_x @@ -54,15 +54,15 @@ e search.prefix="🍍" /x f09f8d8d EOF EXPECT=< Date: Mon, 3 Feb 2025 11:21:39 -0500 Subject: [PATCH 079/157] Clang-format --- librz/core/cmd/cmd_search.c | 1 - librz/search/search.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index b6674401a79..1a9f4d6d2be 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2798,7 +2798,6 @@ RZ_IPI RzCmdStatus rz_cmd_search_value_64be_handler(RzCore *core, int argc, cons return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } - static RzSearchOpt *setup_search_options(RzCore *core) { RzSearchOpt *search_opts = rz_search_opt_new(); if (!(rz_search_opt_set_max_hits(search_opts, rz_config_get_i(core->config, "search.maxhits")) && diff --git a/librz/search/search.c b/librz/search/search.c index b94f213db49..dbfd855403f 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -626,7 +626,7 @@ static RzList *assemble_search_window_list(RzList /**/ *search_in, Rz RzIOMap *map; RzListIter *iter; - rz_list_foreach(search_in, iter, map) { + rz_list_foreach (search_in, iter, map) { ut64 start = map->itv.addr; ut64 end = start + map->itv.size; for (size_t chunk_begin = start; chunk_begin < end; chunk_begin += opt->chunk_size) { From 4138723209fa50d26b3d6a6ab3f58f1eb8fd3c8e Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 13:40:33 -0500 Subject: [PATCH 080/157] Fix leaks --- librz/arch/asm.c | 1 + librz/core/casm.c | 6 ++++++ librz/core/cio.c | 2 ++ librz/core/cmd/cmd_search.c | 4 +++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/librz/arch/asm.c b/librz/arch/asm.c index 97a74c99a6e..43f5728feb7 100644 --- a/librz/arch/asm.c +++ b/librz/arch/asm.c @@ -655,6 +655,7 @@ static Ase findAssembler(RzAsm *a, const char *kw) { if (assemblerMatches(a, h)) { if (kw) { if (strstr(h->name, kw)) { + rz_iterator_free(iter); return h->assemble; } } else { diff --git a/librz/core/casm.c b/librz/core/casm.c index 92f1c89322e..e8f03b7afd0 100644 --- a/librz/core/casm.c +++ b/librz/core/casm.c @@ -279,23 +279,28 @@ RZ_API RzList /**/ *rz_core_asm_strsearch(RzCore *core, const ch ut64 usrimm2 = inp_arg ? rz_num_math(core->num, inp_arg) : usrimm; if (usrimm > usrimm2) { RZ_LOG_ERROR("core: Invalid range [0x%08" PFMT64x ":0x%08" PFMT64x "]\n", usrimm, usrimm2); + free(inp); return NULL; } if (core->blocksize < 8) { RZ_LOG_ERROR("core: block size is too small\n"); + free(inp); return NULL; } if (!(buf = (ut8 *)calloc(core->blocksize, 1))) { + free(inp); return NULL; } if (!(ptr = rz_str_dup(input))) { free(buf); + free(inp); return NULL; } if (!(hits = rz_core_asm_hit_list_new())) { free(buf); free(ptr); + free(inp); return NULL; } tokens[0] = NULL; @@ -481,6 +486,7 @@ RZ_API RzList /**/ *rz_core_asm_strsearch(RzCore *core, const ch rz_cons_break_pop(); rz_asm_set_pc(core->rasm, toff); beach: + free(inp); free(buf); free(ptr); free(code); diff --git a/librz/core/cio.c b/librz/core/cio.c index 7b40744d129..8a8e807398f 100644 --- a/librz/core/cio.c +++ b/librz/core/cio.c @@ -667,9 +667,11 @@ RZ_API bool rz_core_write_string_wide_at(RzCore *core, ut64 addr, const char *s) if (!rz_core_write_at(core, addr, (const ut8 *)tmp, len * 2)) { RZ_LOG_ERROR("Could not write wide string '%s' at %" PFMT64x "\n", s, addr); free(str); + free(tmp); return false; } res = true; + free(tmp); str_err: free(str); return res; diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 1a9f4d6d2be..78309daaa36 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -1107,6 +1107,7 @@ static void do_asm_search(RzCore *core, struct search_parameters *param, const c const char *cmdhit = rz_config_get(core->config, "cmd.hit"); rz_list_foreach (hits, iter, hit) { if (rz_cons_is_breaked()) { + rz_list_free(hits); break; } if (cmdhit && *cmdhit) { @@ -1150,7 +1151,7 @@ static void do_asm_search(RzCore *core, struct search_parameters *param, const c count++; } rz_list_purge(hits); - free(hits); + rz_list_free(hits); } } if (param->outmode == RZ_MODE_JSON) { @@ -2191,6 +2192,7 @@ static int cmd_search_legacy_handler(void *data, const char *input) { rz_search_keyword_new((const ut8 *)v_buf, bsize, NULL, 0, NULL)); free(v_buf); } + rz_list_free(nums); rz_search_begin(core->search); dosearch = true; break; From 73f06e4106fd69c3fb1fee7ffced5cc78ac55619 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 14:06:57 -0500 Subject: [PATCH 081/157] Add min/max values to /v and /V commands. --- librz/core/cmd_descs/cmd_descs.c | 80 ++++++++++++++++++++++------ librz/core/cmd_descs/cmd_search.yaml | 40 +++++++++++--- 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index eaeb974ee6c..2c8c802c252 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -150,14 +150,14 @@ static const RzCmdDescArg cmd_info_gadget_args[2]; static const RzCmdDescArg cmd_search_gadget_args[2]; static const RzCmdDescArg cmd_query_gadget_args[2]; static const RzCmdDescArg cmd_detail_gadget_args[2]; -static const RzCmdDescArg cmd_search_value_8_args[2]; -static const RzCmdDescArg cmd_search_value_16_args[2]; -static const RzCmdDescArg cmd_search_value_32_args[2]; -static const RzCmdDescArg cmd_search_value_64_args[2]; -static const RzCmdDescArg cmd_search_value_8be_args[2]; -static const RzCmdDescArg cmd_search_value_16be_args[2]; -static const RzCmdDescArg cmd_search_value_32be_args[2]; -static const RzCmdDescArg cmd_search_value_64be_args[2]; +static const RzCmdDescArg cmd_search_value_8_args[3]; +static const RzCmdDescArg cmd_search_value_16_args[3]; +static const RzCmdDescArg cmd_search_value_32_args[3]; +static const RzCmdDescArg cmd_search_value_64_args[3]; +static const RzCmdDescArg cmd_search_value_8be_args[3]; +static const RzCmdDescArg cmd_search_value_16be_args[3]; +static const RzCmdDescArg cmd_search_value_32be_args[3]; +static const RzCmdDescArg cmd_search_value_64be_args[3]; static const RzCmdDescArg cmd_search_hex_args[2]; static const RzCmdDescArg cmd_search_string_sensitive_args[4]; static const RzCmdDescArg remote_args[3]; @@ -2176,9 +2176,15 @@ static const RzCmdDescHelp slash_v_help = { }; static const RzCmdDescArg cmd_search_value_8_args[] = { { - .name = "value8", + .name = "value8_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value8_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2189,9 +2195,15 @@ static const RzCmdDescHelp cmd_search_value_8_help = { static const RzCmdDescArg cmd_search_value_16_args[] = { { - .name = "value16", + .name = "value16_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value16_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2202,9 +2214,15 @@ static const RzCmdDescHelp cmd_search_value_16_help = { static const RzCmdDescArg cmd_search_value_32_args[] = { { - .name = "value32", + .name = "value32_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value32_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2215,9 +2233,15 @@ static const RzCmdDescHelp cmd_search_value_32_help = { static const RzCmdDescArg cmd_search_value_64_args[] = { { - .name = "value64", + .name = "value64_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value64_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2240,9 +2264,15 @@ static const RzCmdDescHelp slash_V_help = { }; static const RzCmdDescArg cmd_search_value_8be_args[] = { { - .name = "value8", + .name = "value8_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value8_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2253,9 +2283,15 @@ static const RzCmdDescHelp cmd_search_value_8be_help = { static const RzCmdDescArg cmd_search_value_16be_args[] = { { - .name = "value16", + .name = "value16_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value16_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2266,9 +2302,15 @@ static const RzCmdDescHelp cmd_search_value_16be_help = { static const RzCmdDescArg cmd_search_value_32be_args[] = { { - .name = "value32", + .name = "value32_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value32_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; @@ -2279,9 +2321,15 @@ static const RzCmdDescHelp cmd_search_value_32be_help = { static const RzCmdDescArg cmd_search_value_64be_args[] = { { - .name = "value64", + .name = "value64_min", .type = RZ_CMD_ARG_TYPE_NUM, + }, + { + .name = "value64_max", + .type = RZ_CMD_ARG_TYPE_NUM, + .optional = true, + }, { 0 }, }; diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 911e6bfa7c4..9076c7ed6fd 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -513,7 +513,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value8 + - name: value8_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value8_max + optional: true type: RZ_CMD_ARG_TYPE_NUM - name: "/v2" @@ -527,7 +530,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value16 + - name: value16_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value16_max + optional: true type: RZ_CMD_ARG_TYPE_NUM - name: "/v4" @@ -541,7 +547,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value32 + - name: value32_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value32_max + optional: true type: RZ_CMD_ARG_TYPE_NUM - name: "/v8" @@ -555,7 +564,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value64 + - name: value64_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value64_max + optional: true type: RZ_CMD_ARG_TYPE_NUM details: - name: Usage example @@ -576,7 +588,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value8 + - name: value8_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value8_max + optional: true type: RZ_CMD_ARG_TYPE_NUM - name: "/V2" @@ -590,7 +605,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value16 + - name: value16_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value16_max + optional: true type: RZ_CMD_ARG_TYPE_NUM - name: "/V4" @@ -604,7 +622,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value32 + - name: value32_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value32_max + optional: true type: RZ_CMD_ARG_TYPE_NUM - name: "/V8" @@ -618,7 +639,10 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: value64 + - name: value64_min + type: RZ_CMD_ARG_TYPE_NUM + - name: value64_max + optional: true type: RZ_CMD_ARG_TYPE_NUM details: - name: Usage example From 5a5d743de67b5ce313f7566b156f67849da95421 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 14:18:18 -0500 Subject: [PATCH 082/157] Fix tests: Adds 0x prefix and test for exacped strings. --- test/db/cmd/cmd_search_z | 148 +++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 68 deletions(-) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index afe7aad075d..2d5fe08d1a3 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -10,6 +10,19 @@ ERROR: core: invalid string: empty string. EOF RUN +NAME=search escaped string +FILE== +CMDS=< Date: Mon, 3 Feb 2025 15:08:02 -0500 Subject: [PATCH 083/157] Fix search tests with latest commands --- test/db/cmd/cmd_search | 197 ++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 131 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index b88a8de6de8..f6a4f5cc6c1 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -2,6 +2,7 @@ NAME=trailing comment FILE== ARGS=-n CMDS=< Date: Mon, 3 Feb 2025 15:15:32 -0500 Subject: [PATCH 084/157] Fix race condition and double frees. --- librz/search/string_search.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/librz/search/string_search.c b/librz/search/string_search.c index dabad62120d..3a115a4376c 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -21,8 +21,8 @@ typedef struct string_search { * For example, if the real string is UTF-16 or UTF-32. * Here we set the real (in memory encoded) string offsets and string length. */ -static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len, ut64 found_idx) { - if (rz_string_enc_is_utf8_compatible(ss->encoding)) { +static void align_offsets(RzUtilStrScanOptions options, RzStrEnc encoding, RzDetectedString *detected, RzRegexMatch *group0, ut64 *str_mem_offset, ut64 *str_mem_len, ut64 found_idx) { + if (rz_string_enc_is_utf8_compatible(encoding)) { *str_mem_offset = detected->addr + group0->start; *str_mem_len = group0->len; return; @@ -31,12 +31,12 @@ static void align_offsets(StringSearch *ss, RzDetectedString *detected, RzRegexM bool offset_found = false; bool len_found = false; - *str_mem_offset = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start), &offset_found); + *str_mem_offset = ht_uu_find(options.utf8_to_mem_offset_map, found_idx | (group0->start), &offset_found); if (!offset_found) { RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); *str_mem_offset = detected->addr + group0->start; } - *str_mem_len = ht_uu_find(ss->options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &len_found) - *str_mem_offset; + *str_mem_len = ht_uu_find(options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &len_found) - *str_mem_offset; if (!len_found) { if (!offset_found) { // If the previous offset was not found, we know something is broken. @@ -59,11 +59,16 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs return false; } - ss->options.utf8_to_mem_offset_map = ht_uu_new(); - int n_str_in_buf = rz_scan_strings_whole_buf(buffer, found, &ss->options, ss->encoding); + // Copy options here so we can set the hash table. + // The search options are a shared ressource and we might get + // runtime conditions editing and freeing it. + RzUtilStrScanOptions options = ss->options; + options.utf8_to_mem_offset_map = ht_uu_new(); + + int n_str_in_buf = rz_scan_strings_whole_buf(buffer, found, &options, ss->encoding); if (n_str_in_buf < 0) { RZ_LOG_ERROR("Failed to scan buffer for strings.\n"); - ht_uu_free(ss->options.utf8_to_mem_offset_map); + ht_uu_free(options.utf8_to_mem_offset_map); rz_list_free(found); return false; } @@ -80,17 +85,17 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs RzRegexMatch *group0 = rz_pvector_at(match, 0); if (!group0) { RZ_LOG_ERROR("search: Failed to get group of match.\n"); - ht_uu_free(ss->options.utf8_to_mem_offset_map); + ht_uu_free(options.utf8_to_mem_offset_map); rz_list_free(found); return false; } ut64 str_mem_len; ut64 str_mem_offset; - align_offsets(ss, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); + align_offsets(options, ss->encoding, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); RzSearchHit *hit = rz_search_hit_new("string", str_mem_offset, str_mem_len); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); - ht_uu_free(ss->options.utf8_to_mem_offset_map); + ht_uu_free(options.utf8_to_mem_offset_map); rz_list_free(found); return false; } @@ -100,7 +105,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs found_idx++; } - ht_uu_free(ss->options.utf8_to_mem_offset_map); + ht_uu_free(options.utf8_to_mem_offset_map); rz_list_free(found); return true; } From a5e18cd1bd9cc17eea7d547640fe7e5050520f5d Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 15:31:53 -0500 Subject: [PATCH 085/157] Enhance error message if string offset map is faulty. --- librz/search/string_search.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 3a115a4376c..0a3c7dcc752 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -33,7 +33,8 @@ static void align_offsets(RzUtilStrScanOptions options, RzStrEnc encoding, RzDet *str_mem_offset = ht_uu_find(options.utf8_to_mem_offset_map, found_idx | (group0->start), &offset_found); if (!offset_found) { - RZ_LOG_WARN("Could not determine memory offset of UTF-8 string in search. String offset will be off.\n"); + RZ_LOG_WARN("Could not determine memory offset of %s string in search. String offset will be off for: %s\n", + rz_str_enc_as_string(detected->type), detected->string); *str_mem_offset = detected->addr + group0->start; } *str_mem_len = ht_uu_find(options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &len_found) - *str_mem_offset; @@ -91,7 +92,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs } ut64 str_mem_len; ut64 str_mem_offset; - align_offsets(options, ss->encoding, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); + align_offsets(options, detected->type, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); RzSearchHit *hit = rz_search_hit_new("string", str_mem_offset, str_mem_len); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); From 7c7206dcb808b646065910032549e5923d11a201 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 15:33:42 -0500 Subject: [PATCH 086/157] Enhance doxygen of RzDetectedString. --- librz/include/rz_util/rz_str_search.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index f0f99c18d18..b8835ae48c4 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -16,12 +16,12 @@ extern "C" { * Represent a detected string. */ typedef struct { - char *string; ///< Pointer to the string. + char *string; ///< The detected string. Note that this one is always in UTF-8. No matter what the ecoding is in memory. RzRegex *regex; ///< Regex matching the string. If set, the string member is the pattern. ut64 addr; ///< Address/offset of the string in the RzBuffer ut32 size; ///< Size of buffer containing the string in bytes ut32 length; ///< Length of string in chars - RzStrEnc type; ///< String type + RzStrEnc type; ///< String encoding in memory. } RzDetectedString; /** From ef60f8611bdc4ec4cf72395646de6f1cb0b44e1c Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 15:51:50 -0500 Subject: [PATCH 087/157] Add JSON output to legacy /aa --- librz/core/cmd/cmd_search.c | 4 ++-- librz/core/cmd_descs/cmd_descs.c | 2 +- librz/core/cmd_descs/cmd_descs.h | 2 +- librz/core/cmd_descs/cmd_search.yaml | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 78309daaa36..920ce026f62 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2557,8 +2557,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, cons } // "/aa" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv) { - return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, mode); } // "/ac" diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 2c8c802c252..a06393ac306 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -20834,7 +20834,7 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_search_assemble_I_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/aI", rz_cmd_search_assemble_I_handler, &cmd_search_assemble_I_help); rz_warn_if_fail(cmd_search_assemble_I_cd); - RzCmdDesc *cmd_search_assemble_a_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/aa", rz_cmd_search_assemble_a_handler, &cmd_search_assemble_a_help); + RzCmdDesc *cmd_search_assemble_a_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/aa", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_a_handler, &cmd_search_assemble_a_help); rz_warn_if_fail(cmd_search_assemble_a_cd); RzCmdDesc *cmd_search_assemble_c_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ac", rz_cmd_search_assemble_c_handler, &cmd_search_assemble_c_help); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 5bb48c26497..811b636cc9d 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -70,7 +70,7 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, cons // "/aI" RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv); // "/aa" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/ac" RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv); // "/ad" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 9076c7ed6fd..d4999121694 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -37,6 +37,9 @@ commands: - name: "/aa" summary: "Linearly find aproximated assembly (case insensitive strstr)" cname: cmd_search_assemble_a + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "asm-text" type: RZ_CMD_ARG_TYPE_STRING From bd6361456ca1cd731313c413b186b69ebd8bc49b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 15:52:19 -0500 Subject: [PATCH 088/157] Document behavior of byte search for odd number of nibbles. --- librz/core/cmd_descs/cmd_descs.c | 1 + librz/core/cmd_descs/cmd_search.yaml | 2 ++ librz/search/bytes_search.c | 2 ++ test/db/cmd/cmd_search | 2 ++ 4 files changed, 7 insertions(+) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index a06393ac306..cac4bb4f0e1 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -2342,6 +2342,7 @@ static const RzCmdDescDetailEntry cmd_search_hex_Usage_space_example_detail_entr { .text = "Hexadecimal search for the exact bytes 'ffcc33'.", .arg_str = NULL, .comment = "/x ffcc33" }, { .text = "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits.", .arg_str = NULL, .comment = "/x ff..33.0" }, { .text = "Hexadecimal search of the bytes with mask. Pattern: ':'", .arg_str = NULL, .comment = "/x ffd0:ff43" }, + { .text = "Hexadecimal search with an odd number of nibbles.", .arg_str = NULL, .comment = "'aabbc' is equivalent to '.aabbc'" }, { 0 }, }; static const RzCmdDescDetail cmd_search_hex_details[] = { diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index d4999121694..7beb7982371 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -674,6 +674,8 @@ commands: comment: "/x ff..33.0" - text: "Hexadecimal search of the bytes with mask. Pattern: ':'" comment: "/x ffd0:ff43" + - text: "Hexadecimal search with an odd number of nibbles." + comment: "'aabbc' is equivalent to '.aabbc'" - name: "/z" summary: String search. details: diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index d9fa07a288b..a632fefa80f 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -95,6 +95,8 @@ static bool parse_custom_mask(const char *bytes_pattern, const RzRegexMatch *mas * - Mask and bytes should be given in hexadeciaml numbers. * - If the mask is given, it must be the same length as the bytes. * - Each nibble can be replaced with a '.' to indicate a wildcard nibble. + * - Odd number of nibbles are extended on the left hand side (MSB side). + * This means the nibble at the right hand side is aligned to a byte. * * Examples: * - `a987`: Exact pattern for the bytes '\xa9\x87'. diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index f6a4f5cc6c1..59404e57f50 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -799,6 +799,8 @@ NAME=/x wrong entries FILE=bins/elf/analysis/go_stripped CMDS=< Date: Mon, 3 Feb 2025 15:52:45 -0500 Subject: [PATCH 089/157] Remove progress output --- test/db/cmd/cmd_search | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index 59404e57f50..f765952a28f 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -850,10 +850,6 @@ EOF EXPECT=< Date: Mon, 3 Feb 2025 16:16:27 -0500 Subject: [PATCH 090/157] Fix UB in case LSHIFT(1) == 31. --- librz/arch/p/analysis/analysis_arm_cs.c | 2 +- librz/core/cmd/cmd_analysis.c | 2 +- librz/include/rz_analysis.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/librz/arch/p/analysis/analysis_arm_cs.c b/librz/arch/p/analysis/analysis_arm_cs.c index 91da755601c..6c62e62111f 100644 --- a/librz/arch/p/analysis/analysis_arm_cs.c +++ b/librz/arch/p/analysis/analysis_arm_cs.c @@ -1671,7 +1671,7 @@ jmp $$ + 4 + ( [delta] * 2 ) #endif // 0x000082a8 28301be5 ldr r3, [fp, -0x28] if (INSOP(1).mem.scale != -1) { - op->scale = INSOP(1).mem.scale << LSHIFT(1); + op->scale = (ut64)INSOP(1).mem.scale << LSHIFT(1); } op->ireg = cs_reg_name(handle, REGBASE(1)); op->disp = MEMDISP(1); diff --git a/librz/core/cmd/cmd_analysis.c b/librz/core/cmd/cmd_analysis.c index 58a1eadbaa1..4317a1ad78f 100644 --- a/librz/core/cmd/cmd_analysis.c +++ b/librz/core/cmd/cmd_analysis.c @@ -573,7 +573,7 @@ static void core_analysis_bytes_standard(RzCore *core, const ut8 *buf, int len, PRINTF_LN_NOT("type2", "0x%x\n", op->type2, 0); PRINTF_LN_STR("reg", op->reg); PRINTF_LN_STR("ireg", op->ireg); - PRINTF_LN_NOT("scale", "%d\n", op->scale, 0); + PRINTF_LN_NOT("scale", "%" PFMT64d "\n", op->scale, 0); PRINTF_LN_STR("esil", hint && hint->esil ? hint->esil : esilstr); if (op->il_op) { RzStrBuf *sbil = rz_strbuf_new(""); diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 69dda6e1683..6f9ff25f5fb 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -936,7 +936,7 @@ typedef struct rz_analysis_op_t { RzAnalysisLiftedILOp il_op; const char *reg; /* destination register */ const char *ireg; /* register used for indirect memory computation*/ - int scale; + ut64 scale; ut64 disp; RzAnalysisSwitchOp *switch_op; RzAnalysisHint hint; From d22eac66e2101006d6b44e5193952a54c6f6726f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 16:18:41 -0500 Subject: [PATCH 091/157] Set minimal string length to 3 to allow finding ELF --- test/db/cmd/cmd_search | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index f765952a28f..75002f77d36 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -142,7 +142,7 @@ s 0 e search.in=file e search.from=0 e search.to=0x00000050 -e search.str.min_len=3 +e search.str.min_length=3 e search.show_progress=false /z ELF EOF @@ -160,7 +160,7 @@ s 0x1000 e search.in=file e search.from=0 e search.to=0x50 -e search.str.min_len=3 +e search.str.min_length=3 e search.show_progress=false /z ELF EOF @@ -173,7 +173,7 @@ NAME=/zj search FILE=malloc://1024 CMDS=< Date: Mon, 3 Feb 2025 16:27:20 -0500 Subject: [PATCH 092/157] Add more json outputs --- librz/core/cmd/cmd_search.c | 28 +++++++++++----------- librz/core/cmd_descs/cmd_descs.c | 24 +++++++++---------- librz/core/cmd_descs/cmd_descs.h | 24 +++++++++---------- librz/core/cmd_descs/cmd_search.yaml | 36 ++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 920ce026f62..c964383fbba 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2542,17 +2542,17 @@ RZ_IPI RzCmdStatus rz_cmd_search_str_chunk_handler(RzCore *core, int argc, const } // "/a" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/a1" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/aI" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } @@ -2562,8 +2562,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, cons } // "/ac" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv) { - return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, mode); } // "/ad" @@ -2582,12 +2582,12 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slasha_handler(RzCore *core, int arg } // "/ae" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/af" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_f_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_f_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } @@ -2602,22 +2602,22 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_i_handler(RzCore *core, int argc, cons } // "/al" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/am" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/ao" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } // "/as" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_s_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_s_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } @@ -2627,7 +2627,7 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_sl_handler(RzCore *core, int argc, con } // "/at" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_t_handler(RzCore *core, int argc, const char **argv) { +RZ_IPI RzCmdStatus rz_cmd_search_assemble_t_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } @@ -2696,8 +2696,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_hash_block_handler(RzCore *core, int argc, cons } // "/m" -RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv) { - return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); +RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + return pass_to_legacy_api(core, argc, argv, mode); } // "/mb" diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index cac4bb4f0e1..46aba754360 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -20827,18 +20827,18 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_str_chunk_cd); rz_cmd_desc_set_default_mode(cmd_search_str_chunk_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *slash_a_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/a", rz_cmd_search_assemble_handler, &cmd_search_assemble_help, &slash_a_help); + RzCmdDesc *slash_a_cd = rz_cmd_desc_group_modes_new(core->rcmd, slash__cd, "/a", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_handler, &cmd_search_assemble_help, &slash_a_help); rz_warn_if_fail(slash_a_cd); - RzCmdDesc *cmd_search_assemble_1_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/a1", rz_cmd_search_assemble_1_handler, &cmd_search_assemble_1_help); + RzCmdDesc *cmd_search_assemble_1_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/a1", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_1_handler, &cmd_search_assemble_1_help); rz_warn_if_fail(cmd_search_assemble_1_cd); - RzCmdDesc *cmd_search_assemble_I_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/aI", rz_cmd_search_assemble_I_handler, &cmd_search_assemble_I_help); + RzCmdDesc *cmd_search_assemble_I_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/aI", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_I_handler, &cmd_search_assemble_I_help); rz_warn_if_fail(cmd_search_assemble_I_cd); RzCmdDesc *cmd_search_assemble_a_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/aa", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_a_handler, &cmd_search_assemble_a_help); rz_warn_if_fail(cmd_search_assemble_a_cd); - RzCmdDesc *cmd_search_assemble_c_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ac", rz_cmd_search_assemble_c_handler, &cmd_search_assemble_c_help); + RzCmdDesc *cmd_search_assemble_c_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ac", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_c_handler, &cmd_search_assemble_c_help); rz_warn_if_fail(cmd_search_assemble_c_cd); RzCmdDesc *cmd_search_assemble_d_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ad", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_d_handler, &cmd_search_assemble_d_help); @@ -20850,10 +20850,10 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_search_assemble_d_slasha_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ad/a", rz_cmd_search_assemble_d_slasha_handler, &cmd_search_assemble_d_slasha_help); rz_warn_if_fail(cmd_search_assemble_d_slasha_cd); - RzCmdDesc *cmd_search_assemble_e_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ae", rz_cmd_search_assemble_e_handler, &cmd_search_assemble_e_help); + RzCmdDesc *cmd_search_assemble_e_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ae", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_e_handler, &cmd_search_assemble_e_help); rz_warn_if_fail(cmd_search_assemble_e_cd); - RzCmdDesc *slash_af_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/af", rz_cmd_search_assemble_f_handler, &cmd_search_assemble_f_help, &slash_af_help); + RzCmdDesc *slash_af_cd = rz_cmd_desc_group_modes_new(core->rcmd, slash_a_cd, "/af", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_f_handler, &cmd_search_assemble_f_help, &slash_af_help); rz_warn_if_fail(slash_af_cd); RzCmdDesc *cmd_search_assemble_fl_cd = rz_cmd_desc_argv_new(core->rcmd, slash_af_cd, "/afl", rz_cmd_search_assemble_fl_handler, &cmd_search_assemble_fl_help); rz_warn_if_fail(cmd_search_assemble_fl_cd); @@ -20861,21 +20861,21 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_search_assemble_i_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ai", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_i_handler, &cmd_search_assemble_i_help); rz_warn_if_fail(cmd_search_assemble_i_cd); - RzCmdDesc *cmd_search_assemble_l_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/al", rz_cmd_search_assemble_l_handler, &cmd_search_assemble_l_help); + RzCmdDesc *cmd_search_assemble_l_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/al", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_l_handler, &cmd_search_assemble_l_help); rz_warn_if_fail(cmd_search_assemble_l_cd); - RzCmdDesc *cmd_search_assemble_m_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/am", rz_cmd_search_assemble_m_handler, &cmd_search_assemble_m_help); + RzCmdDesc *cmd_search_assemble_m_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/am", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_m_handler, &cmd_search_assemble_m_help); rz_warn_if_fail(cmd_search_assemble_m_cd); - RzCmdDesc *cmd_search_assemble_o_cd = rz_cmd_desc_argv_new(core->rcmd, slash_a_cd, "/ao", rz_cmd_search_assemble_o_handler, &cmd_search_assemble_o_help); + RzCmdDesc *cmd_search_assemble_o_cd = rz_cmd_desc_argv_modes_new(core->rcmd, slash_a_cd, "/ao", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_o_handler, &cmd_search_assemble_o_help); rz_warn_if_fail(cmd_search_assemble_o_cd); - RzCmdDesc *slash_as_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/as", rz_cmd_search_assemble_s_handler, &cmd_search_assemble_s_help, &slash_as_help); + RzCmdDesc *slash_as_cd = rz_cmd_desc_group_modes_new(core->rcmd, slash_a_cd, "/as", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_s_handler, &cmd_search_assemble_s_help, &slash_as_help); rz_warn_if_fail(slash_as_cd); RzCmdDesc *cmd_search_assemble_sl_cd = rz_cmd_desc_argv_new(core->rcmd, slash_as_cd, "/asl", rz_cmd_search_assemble_sl_handler, &cmd_search_assemble_sl_help); rz_warn_if_fail(cmd_search_assemble_sl_cd); - RzCmdDesc *slash_at_cd = rz_cmd_desc_group_new(core->rcmd, slash_a_cd, "/at", rz_cmd_search_assemble_t_handler, &cmd_search_assemble_t_help, &slash_at_help); + RzCmdDesc *slash_at_cd = rz_cmd_desc_group_modes_new(core->rcmd, slash_a_cd, "/at", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_assemble_t_handler, &cmd_search_assemble_t_help, &slash_at_help); rz_warn_if_fail(slash_at_cd); RzCmdDesc *cmd_search_assemble_tl_cd = rz_cmd_desc_argv_new(core->rcmd, slash_at_cd, "/atl", rz_cmd_search_assemble_tl_handler, &cmd_search_assemble_tl_help); rz_warn_if_fail(cmd_search_assemble_tl_cd); @@ -20941,7 +20941,7 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_hash_block_cd); rz_cmd_desc_set_default_mode(cmd_search_hash_block_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *slash_m_cd = rz_cmd_desc_group_new(core->rcmd, slash__cd, "/m", rz_cmd_search_magic_const_handler, &cmd_search_magic_const_help, &slash_m_help); + RzCmdDesc *slash_m_cd = rz_cmd_desc_group_modes_new(core->rcmd, slash__cd, "/m", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_search_magic_const_handler, &cmd_search_magic_const_help, &slash_m_help); rz_warn_if_fail(slash_m_cd); RzCmdDesc *cmd_search_magic_bin_headers_cd = rz_cmd_desc_argv_new(core->rcmd, slash_m_cd, "/mb", rz_cmd_search_magic_bin_headers_handler, &cmd_search_magic_bin_headers_help); rz_warn_if_fail(cmd_search_magic_bin_headers_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 811b636cc9d..b3fe0958305 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -64,15 +64,15 @@ RZ_IPI RzCmdStatus rz_interpret_macro_multiple_handler(RzCore *core, int argc, c // "/+" RZ_IPI RzCmdStatus rz_cmd_search_str_chunk_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/a" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/a1" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_1_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/aI" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_I_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/aa" RZ_IPI RzCmdStatus rz_cmd_search_assemble_a_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/ac" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_c_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/ad" RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/ad/" @@ -80,25 +80,25 @@ RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slash_handler(RzCore *core, int argc // "/ad/a" RZ_IPI RzCmdStatus rz_cmd_search_assemble_d_slasha_handler(RzCore *core, int argc, const char **argv); // "/ae" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_e_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/af" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_f_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_f_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/afl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_fl_handler(RzCore *core, int argc, const char **argv); // "/ai" RZ_IPI RzCmdStatus rz_cmd_search_assemble_i_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/al" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_l_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/am" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_m_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/ao" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_o_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/as" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_s_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_s_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/asl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_sl_handler(RzCore *core, int argc, const char **argv); // "/at" -RZ_IPI RzCmdStatus rz_cmd_search_assemble_t_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_assemble_t_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/atl" RZ_IPI RzCmdStatus rz_cmd_search_assemble_tl_handler(RzCore *core, int argc, const char **argv); // "/ca" @@ -134,7 +134,7 @@ RZ_IPI RzCmdStatus rz_cmd_search_graph_path_follow_jumps_handler(RzCore *core, i // "/h" RZ_IPI RzCmdStatus rz_cmd_search_hash_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/m" -RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv); +RZ_IPI RzCmdStatus rz_cmd_search_magic_const_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode); // "/mb" RZ_IPI RzCmdStatus rz_cmd_search_magic_bin_headers_handler(RzCore *core, int argc, const char **argv); // "/E" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 7beb7982371..bcf13b33113 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -21,18 +21,27 @@ commands: - name: "/a" summary: Assemble the instruction and search its bytes cname: cmd_search_assemble + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: asm-text type: RZ_CMD_ARG_TYPE_STRING - name: "/a1" summary: "Find valid assembly generated by changing only the nth byte" cname: cmd_search_assemble_1 + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "number" type: RZ_CMD_ARG_TYPE_STRING - name: "/aI" summary: "Search for infinite loop instructions (jmp $$)" cname: cmd_search_assemble_I + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: [] - name: "/aa" summary: "Linearly find aproximated assembly (case insensitive strstr)" @@ -46,6 +55,9 @@ commands: - name: "/ac" summary: "Same as /aa, but case-sensitive" cname: cmd_search_assemble_c + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "asm-text" type: RZ_CMD_ARG_TYPE_STRING @@ -73,6 +85,9 @@ commands: - name: "/ae" summary: "Search for esil expressions matching substring" cname: cmd_search_assemble_e + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "esil" type: RZ_CMD_ARG_TYPE_STRING @@ -82,6 +97,9 @@ commands: - name: "/af" summary: "Search for instruction of specific family (afl=list" cname: cmd_search_assemble_f + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "family" type: RZ_CMD_ARG_TYPE_STRING @@ -106,16 +124,25 @@ commands: - name: "/al" summary: "Same as aoml, list all opcodes" cname: cmd_search_assemble_l + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: [] - name: "/am" summary: "Search for specific instructions of specific mnemonic" cname: cmd_search_assemble_m + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "opcode" type: RZ_CMD_ARG_TYPE_STRING - name: "/ao" summary: "Search for instruction 'instr' (in all offsets)" cname: cmd_search_assemble_o + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "instr" type: RZ_CMD_ARG_TYPE_STRING @@ -125,6 +152,9 @@ commands: - name: "/as" summary: "Search for syscalls (See /at swi and /af priv)" cname: cmd_search_assemble_s + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "type" optional: true @@ -142,6 +172,9 @@ commands: - name: "/at" summary: "Search for instructions of given type" cname: cmd_search_assemble_t + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: "type" optional: true @@ -395,6 +428,9 @@ commands: - name: "/m" summary: Magic constants search. cname: cmd_search_magic_const + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON args: - name: magic-file optional: true From c2b73b5f644e699f58835da43b7bf09e7e8786fa Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 16:32:46 -0500 Subject: [PATCH 093/157] Fix some tests which were invalidly formatted. --- test/db/cmd/cmd_search | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index 75002f77d36..f5721347732 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -238,26 +238,6 @@ EXPECT=< Date: Mon, 3 Feb 2025 16:39:55 -0500 Subject: [PATCH 094/157] Fix, don't append a second j to the command --- librz/core/cmd/cmd_search.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index c964383fbba..637075fc96f 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2414,13 +2414,6 @@ static int pass_to_legacy_api(RzCore *core, int argc, const char **argv, RzOutpu // The +1 strips the '/', because the legacy handler expect it this way. const char *cmd = argv[0] + 1; RzStrBuf *legacy_input = rz_strbuf_new(cmd); - switch (mode) { - default: - break; - case RZ_OUTPUT_MODE_JSON: - rz_strbuf_append(legacy_input, "j"); - break; - } // Append arguments for (size_t i = 1; i < argc; i++) { rz_strbuf_appendf(legacy_input, " %s", argv[i]); From 94305aff348d2aa8fbc6bb5a56fb2aee45bda645 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 3 Feb 2025 16:50:34 -0500 Subject: [PATCH 095/157] Fix two NULL passes to rz_hex_str2bin --- librz/debug/p/debug_dmp.c | 2 +- librz/main/rz-asm.c | 7 ++++--- librz/util/hex.c | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/librz/debug/p/debug_dmp.c b/librz/debug/p/debug_dmp.c index b9825d8cb8f..3c93561d6bc 100644 --- a/librz/debug/p/debug_dmp.c +++ b/librz/debug/p/debug_dmp.c @@ -32,8 +32,8 @@ static bool rz_debug_dmp_init(RzDebug *dbg, void **user) { DmpCtx *ctx = dbg->plugin_data; ctx->bf = core->bin->cur; + ctx->context = malloc((strlen(core->bin->cur->o->regstate) / 2) + 1); int ret = rz_hex_str2bin(core->bin->cur->o->regstate, NULL); - ctx->context = malloc(ret); if (!ctx->context) { return false; } diff --git a/librz/main/rz-asm.c b/librz/main/rz-asm.c index daa2b02ec44..fb2909aeef3 100644 --- a/librz/main/rz-asm.c +++ b/librz/main/rz-asm.c @@ -303,12 +303,13 @@ static int rasm_disasm(RzAsmState *as, ut64 addr, const char *buf, int len, int clen = len; // XXX data = (ut8 *)buf; } else { - clen = rz_hex_str2bin(buf, NULL); - if ((int)clen < 1 || !(data = malloc(clen))) { + if (!(data = malloc((strlen(buf) / 2) + 1))) { ret = 0; goto beach; } - rz_hex_str2bin(buf, data); + clen = rz_hex_str2bin(buf, data); + // Odd number of nibbles case. + clen *= clen < 0 ? -1 : 1; len = clen; } diff --git a/librz/util/hex.c b/librz/util/hex.c index 4536bb1f535..e7365953033 100644 --- a/librz/util/hex.c +++ b/librz/util/hex.c @@ -566,7 +566,8 @@ RZ_API int rz_hex_str2bin_msb(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 * * Use rz_hex_str2bin_msb() if you need to extend it on the MSB side. * * \param in Input string in hexadecimal form. An optional "0x" prefix may be present. - * \param out Output buffer having at least strlen(in) / 2 bytes available + * \param out Output buffer having at least (strlen(in) / 2) + 1 bytes available. + * * \return Number of bytes written into \p out. The number is negative if an odd number of nibbles was parsed. */ RZ_API int rz_hex_str2bin(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 *out) { From f78b5f9593282a8c1294127f65d867ac4798897c Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 4 Feb 2025 10:48:55 -0500 Subject: [PATCH 096/157] Move string search settings: str.search -> search.str --- librz/core/cconfig.c | 48 +- librz/core/cmd_descs/cmd_descs.c | 2 +- librz/core/cmd_descs/cmd_print.yaml | 2 +- librz/core/csearch.c | 2 +- librz/core/project_migrate.c | 25 + librz/include/rz_project.h | 3 +- librz/include/rz_util/rz_str.h | 2 +- librz/main/rz-bin.c | 8 +- librz/util/str.c | 2 +- test/db/archos/darwin-x64/dbg | 2 +- test/db/cmd/cmd_graph | 2 +- test/db/cmd/cmd_i | 32 +- test/db/cmd/cmd_pd | 78 +- test/db/cmd/cmd_pd2 | 8 +- test/db/cmd/cmd_ps | 14 +- test/db/cmd/cmd_psj | 4 +- test/db/cmd/cmd_search_z | 2 +- test/db/cmd/metadata | 4 +- test/db/cmd/write | 6 +- test/db/formats/mach0/fatmach0 | 4 +- test/db/formats/mach0/mach0 | 2 +- test/db/rzil/ppc32 | 4 +- test/db/rzil/ppc64 | 4 +- test/db/tools/rz_bin | 2 +- test/integration/test_project_migrate.c | 32 + test/prj/v18-str-config.rzdb | 5899 +++++++++++++++++++++++ 26 files changed, 6075 insertions(+), 118 deletions(-) create mode 100644 test/prj/v18-str-config.rzdb diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index db9c88cacc7..894b1a843e2 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1128,14 +1128,14 @@ static bool cb_search_max_threads(void *user, void *data) { return true; } -static bool cb_str_search_min_length(void *user, void *data) { +static bool cb_search_str_min_length(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; if (node->i_value < 1) { - RZ_LOG_ERROR("str.search.min_length cannot be less than 1.\n"); + RZ_LOG_ERROR("search.str.min_length cannot be less than 1.\n"); return false; } else if (node->i_value >= core->bin->str_search_cfg.buffer_size) { - RZ_LOG_ERROR("str.search.buffer_size cannot be greater or equal to %" PFMTSZu ".\n", core->bin->str_search_cfg.buffer_size); + RZ_LOG_ERROR("search.str.buffer_size cannot be greater or equal to %" PFMTSZu ".\n", core->bin->str_search_cfg.buffer_size); return false; } @@ -1149,13 +1149,13 @@ static bool cb_str_search_min_length(void *user, void *data) { return true; } -static bool cb_str_search_buffer_size(void *user, void *data) { +static bool cb_search_str_buffer_size(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; size_t min_buffer_size = RZ_MIN(core->bin->str_search_cfg.min_length, RZ_BIN_STRING_SEARCH_BUFFER_SIZE); if (node->i_value < min_buffer_size) { - RZ_LOG_ERROR("str.search.buffer_size cannot be less than %" PFMTSZu ".\n", min_buffer_size); + RZ_LOG_ERROR("search.str.buffer_size cannot be less than %" PFMTSZu ".\n", min_buffer_size); return false; } @@ -1169,11 +1169,11 @@ static bool cb_str_search_buffer_size(void *user, void *data) { return true; } -static bool cb_str_search_max_uni_blocks(void *user, void *data) { +static bool cb_search_str_max_uni_blocks(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; if (node->i_value < 1) { - RZ_LOG_ERROR("str.search.max_uni_blocks cannot be less than 1.\n"); + RZ_LOG_ERROR("search.str.max_uni_blocks cannot be less than 1.\n"); return false; } core->bin->str_search_cfg.max_uni_blocks = node->i_value; @@ -1186,11 +1186,11 @@ static bool cb_str_search_max_uni_blocks(void *user, void *data) { return true; } -static bool cb_str_search_max_region_size(void *user, void *data) { +static bool cb_search_str_max_region_size(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; if (node->i_value < RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE) { - RZ_LOG_ERROR("str.search.max_region_size cannot be less than " RZ_STR(RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE) ".\n"); + RZ_LOG_ERROR("search.str.max_region_size cannot be less than " RZ_STR(RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE) ".\n"); return false; } core->bin->str_search_cfg.max_region_size = node->i_value; @@ -1203,25 +1203,25 @@ static bool cb_str_search_max_region_size(void *user, void *data) { return true; } -static bool cb_str_search_raw_alignment(void *user, void *data) { +static bool cb_search_str_raw_alignment(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; if (node->i_value < 8) { - RZ_LOG_ERROR("str.search.raw_alignment cannot be less than 8.\n"); + RZ_LOG_ERROR("search.str.raw_alignment cannot be less than 8.\n"); return false; } core->bin->str_search_cfg.raw_alignment = node->i_value; return true; } -static bool cb_str_search_check_ascii_freq(void *user, void *data) { +static bool cb_search_str_check_ascii_freq(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; if (node->value[0] == '?') { rz_cons_printf("true\nfalse\n"); return false; } else if (!rz_str_is_bool(node->value)) { - RZ_LOG_ERROR("Invalid value for str.search.check_ascii_freq (%s).\n", node->value); + RZ_LOG_ERROR("Invalid value for search.str.check_ascii_freq (%s).\n", node->value); return false; } core->bin->str_search_cfg.check_ascii_freq = rz_str_is_true(node->value); @@ -1249,7 +1249,7 @@ static bool find_encoding(RzConfigNode *node, RzStrEnc *encoding) { return false; } -static bool cb_str_search_encoding(void *user, void *data) { +static bool cb_search_str_encoding(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; RzStrEnc encoding = RZ_STRING_ENC_GUESS; @@ -1261,7 +1261,7 @@ static bool cb_str_search_encoding(void *user, void *data) { "if utf8 char detected then utf8 else 8bit\n"); return false; } else if (RZ_STR_EQ("settings", node->value) || (rz_str_casecmp("guess", node->value) && !found_enc)) { - RZ_LOG_ERROR("Invalid value for str.search.encoding (%s).\n", node->value); + RZ_LOG_ERROR("Invalid value for search.str.encoding (%s).\n", node->value); return false; } @@ -3751,15 +3751,6 @@ RZ_API int rz_core_config_init(RzCore *core) { /* string search options */ SETB("str.search.reload", true, "When enabled, any change to any option `str.search.*` will reload the bin strings."); - SETICB("str.search.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_str_search_min_length, "Smallest string length that is possible to find."); - SETICB("str.search.buffer_size", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_str_search_buffer_size, "Maximum buffer size, which will also determine the maximum string length."); - SETICB("str.search.max_uni_blocks", RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS, &cb_str_search_max_uni_blocks, "Maximum number of unicode blocks."); - SETICB("str.search.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_str_search_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); - SETICB("str.search.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_str_search_raw_alignment, "Memory sector alignment used for the raw string search."); - SETICB("str.search.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_str_search_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); - n = NODECB("str.search.encoding", "guess", &cb_str_search_encoding); - SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); - SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); n = NODECB("str.search.mode", "auto", &cb_str_search_mode); SETDESC(n, "String search mode which can override how strings are found (auto, rosections or raw)"); SETOPTIONS(n, "auto", "rosections", "raw", NULL); @@ -3790,6 +3781,15 @@ RZ_API int rz_core_config_init(RzCore *core) { SETBPREF("search.show_progress", "true", "Show the search process."); SETBPREF("search.overlap", "true", "Look for overlapped search hits."); SETICB("search.io.alignment", 1, &cb_searchalignment, "Only search at set byte alignment."); + SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find."); + SETICB("search.str.buffer_size", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_buffer_size, "Maximum buffer size, which will also determine the maximum string length."); + SETICB("search.str.max_uni_blocks", RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS, &cb_search_str_max_uni_blocks, "Maximum number of unicode blocks."); + SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); + SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); + SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); + n = NODECB("search.str.encoding", "guess", &cb_search_str_encoding); + SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); + SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); SETICB("search.align", 0, &cb_searchalign, "Only catch aligned search hits"); SETI("search.esilcombo", 8, "Stop search after N consecutive hits"); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 46aba754360..9f1e7e51aef 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -15915,7 +15915,7 @@ static const RzCmdDescHelp ps_help = { .summary = "Print string at the current offset", }; static const RzCmdDescDetailEntry print_string_Value_space_details_detail_entries[] = { - { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'str.search.encoding' option." }, + { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'search.str.encoding' option." }, { .text = "delimeter=null", .arg_str = NULL, .comment = "String is NUL terminated." }, { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (dosn't stop at non-printable character)." }, { 0 }, diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index f1e3281272b..70ed084fbe8 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1128,7 +1128,7 @@ commands: - name: Value details entries: - text: "encoding=settings" - comment: "Use encoding from 'str.search.encoding' option." + comment: "Use encoding from 'search.str.encoding' option." - text: "delimeter=null" comment: "String is NUL terminated." - text: "delimeter=block" diff --git a/librz/core/csearch.c b/librz/core/csearch.c index 0e8900cefd1..12d1c793453 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -177,7 +177,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor return NULL; } if (strlen(re_pattern) >= core->bin->str_search_cfg.buffer_size) { - RZ_LOG_ERROR("core: String to search is larger then str.search.buffer_size.\n"); + RZ_LOG_ERROR("core: String to search is larger then search.str.buffer_size.\n"); return NULL; } diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 3006d9df5d8..2f1447a855a 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -677,6 +677,30 @@ RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *re return true; } +// -- +// Migration 18 -> 19 +// +// Changes from f9422ac0cd6922f73208e5f5e6f47b3d64b3bd0d: +// Renamed non RzBin string search options: +// - `str.search.X` to `search.str.X` + +RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *res) { + Sdb *core_db; + RZ_SERIALIZE_SUB(prj, core_db, res, "core", return false;); + Sdb *config_db; + RZ_SERIALIZE_SUB(core_db, config_db, res, "config", return false;); + sdb_rename(config_db, "str.search.max_threads", "search.max_threads"); + sdb_rename(config_db, "str.search.min_length", "search.str.min_length"); + sdb_rename(config_db, "str.search.buffer_size", "search.str.buffer_size"); + sdb_rename(config_db, "str.search.max_uni_blocks", "search.str.max_uni_blocks"); + sdb_rename(config_db, "str.search.max_region_size", "search.str.max_region_size"); + sdb_rename(config_db, "str.search.raw_alignment", "search.str.raw_alignment"); + sdb_rename(config_db, "str.search.check_ascii_freq", "search.str.check_ascii_freq"); + sdb_rename(config_db, "str.search.encoding", "search.str.encoding"); + + return true; +} + static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = { rz_project_migrate_v1_v2, rz_project_migrate_v2_v3, @@ -695,6 +719,7 @@ static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = rz_project_migrate_v15_v16, rz_project_migrate_v16_v17, rz_project_migrate_v17_v18, + rz_project_migrate_v18_v19, }; /// Migrate the given project to the current version in-place diff --git a/librz/include/rz_project.h b/librz/include/rz_project.h index 5fc61ae7b95..5409e6c8157 100644 --- a/librz/include/rz_project.h +++ b/librz/include/rz_project.h @@ -12,7 +12,7 @@ extern "C" { #endif -#define RZ_PROJECT_VERSION 18 +#define RZ_PROJECT_VERSION 19 typedef Sdb RzProject; @@ -63,6 +63,7 @@ RZ_API bool rz_project_migrate_v14_v15(RzProject *prj, RzSerializeResultInfo *re RZ_API bool rz_project_migrate_v15_v16(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v16_v17(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *res); +RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *res); RZ_API bool rz_project_migrate(RzProject *prj, unsigned long version, RzSerializeResultInfo *res); #ifdef __cplusplus diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index c88dcbbca15..f0894c10541 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -31,7 +31,7 @@ typedef enum { RZ_STRING_ENC_EBCDIC_US = 's', RZ_STRING_ENC_EBCDIC_ES = 't', RZ_STRING_ENC_GUESS = 'g', - RZ_STRING_ENC_SETTINGS = 'S', ///< Use str.search.encoding. + RZ_STRING_ENC_SETTINGS = 'S', ///< Use search.str.encoding. } RzStrEnc; /** diff --git a/librz/main/rz-bin.c b/librz/main/rz-bin.c index d6d6a04c1ef..ef2ab64f52e 100644 --- a/librz/main/rz-bin.c +++ b/librz/main/rz-bin.c @@ -240,7 +240,7 @@ static int rzbin_show_help(int v) { " RZ_BIN_DEBUGINFOD_URLS: e bin.dbginfo.debuginfod_urls # use alternative debuginfod server\n" " RZ_BIN_DEMANGLE=0: e bin.demangle # do not demangle symbols\n" " RZ_BIN_LANG: e bin.lang # assume lang for demangling\n" - " RZ_BIN_MAXSTRBUF: e str.search.buffer_size # specify maximum buffer size\n" + " RZ_BIN_MAXSTRBUF: e search.str.buffer_size # specify maximum buffer size\n" " RZ_BIN_PDBSERVER: e pdb.server # use alternative PDB server\n" " RZ_BIN_PREFIX: e bin.prefix # prefix symbols/sections/relocs with a specific string\n" " RZ_BIN_STRFILTER: e bin.str.filter # rizin -qc 'e bin.str.filter=?" @@ -784,7 +784,7 @@ RZ_API int rz_main_rz_bin(int argc, const char **argv) { if ((tmp = rz_sys_getenv("RZ_BIN_MAXSTRBUF"))) { if (rz_num_is_valid_input(NULL, tmp)) { ut64 value = rz_num_math(NULL, tmp); - rz_config_set_i(core.config, "str.search.buffer_size", value); + rz_config_set_i(core.config, "search.str.buffer_size", value); } free(tmp); } @@ -988,10 +988,10 @@ RZ_API int rz_main_rz_bin(int argc, const char **argv) { case 'N': { tmp = strchr(opt.arg, ':'); size_t value = rz_num_math(NULL, opt.arg); - rz_config_set_i(core.config, "str.search.min_length", value); + rz_config_set_i(core.config, "search.str.min_length", value); if (tmp) { value = rz_num_math(NULL, tmp + 1); - rz_config_set_i(core.config, "str.search.buffer_size", value); + rz_config_set_i(core.config, "search.str.buffer_size", value); } break; } diff --git a/librz/util/str.c b/librz/util/str.c index a866b62bd5a..4b21e000eaf 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -72,7 +72,7 @@ RZ_API const char *rz_str_enc_as_string(RzStrEnc enc) { case RZ_STRING_ENC_GUESS: return "guessed"; case RZ_STRING_ENC_SETTINGS: - return "str.search.encoding"; + return "search.str.encoding"; default: rz_warn_if_reached(); return "unknown"; diff --git a/test/db/archos/darwin-x64/dbg b/test/db/archos/darwin-x64/dbg index 94882bbab10..c204f35f323 100644 --- a/test/db/archos/darwin-x64/dbg +++ b/test/db/archos/darwin-x64/dbg @@ -81,7 +81,7 @@ dcu main 3 ds dr rip dr rdi -ps @e:str.search.encoding=utf8 @ rdi +ps @e:search.str.encoding=utf8 @ rdi EOF EXPECT=<\\n"}] +0x1ae4e=[{"size":14,"type":"s","subtype":98,"str":"GNU coreutils"}] +0x1ae60=[{"size":27,"type":"s","subtype":98,"str":"Full documentation <%s%s>\\n"}] +0x1ae7b=[{"size":17,"type":"s","subtype":98,"str":"memory exhausted"}] +0x1ae8=[{"size":8,"type":"d","str":"8"}] +0x1ae8c=[{"size":6,"type":"s","subtype":98,"str":"%*lu "}] +0x1ae92=[{"size":12,"type":"s","subtype":98,"str":"write error"}] +0x1ae9e=[{"size":27,"type":"s","subtype":98,"str":"invalid argument %s for %s"}] +0x1aeb9=[{"size":29,"type":"s","subtype":98,"str":"ambiguous argument %s for %s"}] +0x1aed6=[{"size":6,"type":"s","subtype":98,"str":"POSIX"}] +0x1aede=[{"size":6,"type":"s","subtype":98,"str":"%.0Lf"}] +0x1aee4=[{"size":6,"type":"s","subtype":98,"str":"%.1Lf"}] +0x1aefb=[{"size":8,"type":"s","subtype":98,"str":"GB18030"}] +0x1af0=[{"size":8,"type":"d","str":"8"}] +0x1af03=[{"size":10,"type":"s","subtype":98,"str":"unlabeled"}] +0x1af10=[{"size":12,"type":"s","subtype":98,"str":"../src/ls.c"}] +0x1af1c=[{"size":26,"type":"s","subtype":98,"str":"sort_type != sort_version"}] +0x1af36=[{"size":7,"type":"s","subtype":98,"str":"%%%02x"}] +0x1af3d=[{"size":20,"type":"s","subtype":98,"str":"\\u001b]8;;file://%s%s%s\\u0007"}] +0x1af51=[{"size":7,"type":"s","subtype":98,"str":"\\u001b]8;;\\u0007"}] +0x1af5e=[{"size":8,"type":"s","subtype":98,"str":"%s %*s "}] +0x1af69=[{"size":10,"type":"s","subtype":98,"str":"%*s, %*s "}] +0x1af73=[{"size":5,"type":"s","subtype":98,"str":" -> "}] +0x1af78=[{"size":25,"type":"s","subtype":98,"str":"cannot open directory %s"}] +0x1af8=[{"size":8,"type":"d","str":"8"}] +0x1af91=[{"size":24,"type":"s","subtype":98,"str":"error canonicalizing %s"}] +0x1afa9=[{"size":21,"type":"s","subtype":98,"str":"reading directory %s"}] +0x1afbe=[{"size":21,"type":"s","subtype":98,"str":"closing directory %s"}] +0x1afd3=[{"size":6,"type":"s","subtype":98,"str":"total"}] +0x1afd9=[{"size":27,"type":"s","subtype":98,"str":"invalid %s%s argument '%s'"}] +0x1aff4=[{"size":29,"type":"s","subtype":98,"str":"%s%s argument '%s' too large"}] +0x1b00=[{"size":8,"type":"d","str":"8"}] +0x1b014=[{"size":9,"type":"s","subtype":98,"str":"full-iso"}] +0x1b020=[{"size":8,"type":"s","subtype":98,"str":"/.libs/"}] +0x1b02c=[{"size":18,"type":"s","subtype":98,"str":"/usr/share/locale"}] +0x1b03e=[{"size":19,"type":"s","subtype":98,"str":"invalid line width"}] +0x1b051=[{"size":7,"type":"s","subtype":98,"str":"%s: %s"}] +0x1b05c=[{"size":11,"type":"s","subtype":98,"str":"--classify"}] +0x1b067=[{"size":17,"type":"s","subtype":98,"str":"invalid tab size"}] +0x1b078=[{"size":7,"type":"s","subtype":98,"str":"--sort"}] +0x1b07f=[{"size":7,"type":"s","subtype":98,"str":"--time"}] +0x1b08=[{"size":8,"type":"d","str":"8"}] +0x1b086=[{"size":9,"type":"s","subtype":98,"str":"--format"}] +0x1b08f=[{"size":8,"type":"s","subtype":98,"str":"--color"}] +0x1b097=[{"size":12,"type":"s","subtype":98,"str":"--hyperlink"}] +0x1b0a3=[{"size":18,"type":"s","subtype":98,"str":"--indicator-style"}] +0x1b0b5=[{"size":16,"type":"s","subtype":98,"str":"--quoting-style"}] +0x1b0c5=[{"size":16,"type":"s","subtype":98,"str":"David MacKenzie"}] +0x1b0d5=[{"size":20,"type":"s","subtype":98,"str":"Richard M. Stallman"}] +0x1b0ed=[{"size":14,"type":"s","subtype":98,"str":"LS_BLOCK_SIZE"}] +0x1b0fb=[{"size":8,"type":"s","subtype":98,"str":"COLUMNS"}] +0x1b10=[{"size":8,"type":"d","str":"8"}] +0x1b103=[{"size":8,"type":"s","subtype":98,"str":"TABSIZE"}] +0x1b10b=[{"size":14,"type":"s","subtype":98,"str":"QUOTING_STYLE"}] +0x1b119=[{"size":6,"type":"s","subtype":98,"str":"*=>@|"}] +0x1b11f=[{"size":11,"type":"s","subtype":98,"str":"TIME_STYLE"}] +0x1b12a=[{"size":29,"type":"s","subtype":98,"str":"invalid time style format %s"}] +0x1b147=[{"size":11,"type":"s","subtype":98,"str":"time style"}] +0x1b152=[{"size":22,"type":"s","subtype":98,"str":"Valid arguments are:\\n"}] +0x1b168=[{"size":16,"type":"s","subtype":98,"str":" - [posix-]%s\\n"}] +0x1b178=[{"size":24,"type":"s","subtype":98,"str":"%Y-%m-%d %H:%M:%S.%N %z"}] +0x1b18=[{"size":8,"type":"d","str":"8"}] +0x1b190=[{"size":15,"type":"s","subtype":98,"str":"%Y-%m-%d %H:%M"}] +0x1b19f=[{"size":10,"type":"s","subtype":98,"str":"%Y-%m-%d "}] +0x1b1a9=[{"size":10,"type":"s","subtype":98,"str":"LS_COLORS"}] +0x1b1b3=[{"size":10,"type":"s","subtype":98,"str":"COLORTERM"}] +0x1b1bd=[{"size":6,"type":"s","subtype":98,"str":"TERM "}] +0x1b1c3=[{"size":24,"type":"s","subtype":98,"str":"unrecognized prefix: %s"}] +0x1b1db=[{"size":7,"type":"s","subtype":98,"str":"target"}] +0x1b1e2=[{"size":6,"type":"s","subtype":98,"str":"found"}] +0x1b1e8=[{"size":10,"type":"s","subtype":98,"str":"//DIRED//"}] +0x1b1f2=[{"size":13,"type":"s","subtype":98,"str":"//SUBDIRED//"}] +0x1b1ff=[{"size":9,"type":"s","subtype":98,"str":"long-iso"}] +0x1b20=[{"size":8,"type":"d","str":"8"}] +0x1b208=[{"size":5,"type":"s","subtype":98,"str":"none"}] +0x1b20d=[{"size":6,"type":"s","subtype":98,"str":"slash"}] +0x1b213=[{"size":10,"type":"s","subtype":98,"str":"file-type"}] +0x1b21d=[{"size":8,"type":"s","subtype":98,"str":"verbose"}] +0x1b225=[{"size":5,"type":"s","subtype":98,"str":"long"}] +0x1b22a=[{"size":7,"type":"s","subtype":98,"str":"commas"}] +0x1b231=[{"size":11,"type":"s","subtype":98,"str":"horizontal"}] +0x1b23c=[{"size":7,"type":"s","subtype":98,"str":"across"}] +0x1b243=[{"size":9,"type":"s","subtype":98,"str":"vertical"}] +0x1b24c=[{"size":14,"type":"s","subtype":98,"str":"single-column"}] +0x1b25a=[{"size":6,"type":"s","subtype":98,"str":"atime"}] +0x1b264=[{"size":6,"type":"s","subtype":98,"str":"ctime"}] +0x1b26a=[{"size":7,"type":"s","subtype":98,"str":"status"}] +0x1b271=[{"size":6,"type":"s","subtype":98,"str":"mtime"}] +0x1b277=[{"size":13,"type":"s","subtype":98,"str":"modification"}] +0x1b28=[{"size":8,"type":"d","str":"8"}] +0x1b284=[{"size":6,"type":"s","subtype":98,"str":"birth"}] +0x1b28a=[{"size":9,"type":"s","subtype":98,"str":"creation"}] +0x1b293=[{"size":10,"type":"s","subtype":98,"str":"extension"}] +0x1b2a1=[{"size":6,"type":"s","subtype":98,"str":"force"}] +0x1b2a7=[{"size":6,"type":"s","subtype":98,"str":"never"}] +0x1b2b0=[{"size":5,"type":"s","subtype":98,"str":"auto"}] +0x1b2b5=[{"size":7,"type":"s","subtype":98,"str":"if-tty"}] +0x1b2bc=[{"size":10,"type":"s","subtype":98,"str":"directory"}] +0x1b2c6=[{"size":6,"type":"s","subtype":98,"str":"dired"}] +0x1b2cc=[{"size":10,"type":"s","subtype":98,"str":"full-time"}] +0x1b2d6=[{"size":24,"type":"s","subtype":98,"str":"group-directories-first"}] +0x1b2ee=[{"size":15,"type":"s","subtype":98,"str":"human-readable"}] +0x1b2fd=[{"size":6,"type":"s","subtype":98,"str":"inode"}] +0x1b30=[{"size":8,"type":"d","str":"8"}] +0x1b303=[{"size":10,"type":"s","subtype":98,"str":"kibibytes"}] +0x1b30d=[{"size":16,"type":"s","subtype":98,"str":"numeric-uid-gid"}] +0x1b31d=[{"size":9,"type":"s","subtype":98,"str":"no-group"}] +0x1b326=[{"size":19,"type":"s","subtype":98,"str":"hide-control-chars"}] +0x1b339=[{"size":8,"type":"s","subtype":98,"str":"reverse"}] +0x1b341=[{"size":11,"type":"s","subtype":98,"str":"almost-all"}] +0x1b34c=[{"size":15,"type":"s","subtype":98,"str":"ignore-backups"}] +0x1b35e=[{"size":25,"type":"s","subtype":98,"str":"dereference-command-line"}] +0x1b377=[{"size":5,"type":"s","subtype":98,"str":"hide"}] +0x1b37c=[{"size":7,"type":"s","subtype":98,"str":"ignore"}] +0x1b38=[{"size":8,"type":"d","str":"8"}] +0x1b383=[{"size":12,"type":"s","subtype":98,"str":"dereference"}] +0x1b38f=[{"size":8,"type":"s","subtype":98,"str":"literal"}] +0x1b397=[{"size":11,"type":"s","subtype":98,"str":"quote-name"}] +0x1b3a2=[{"size":10,"type":"s","subtype":98,"str":"recursive"}] +0x1b3ac=[{"size":19,"type":"s","subtype":98,"str":"show-control-chars"}] +0x1b3bf=[{"size":8,"type":"s","subtype":98,"str":"tabsize"}] +0x1b3c7=[{"size":11,"type":"s","subtype":98,"str":"time-style"}] +0x1b3d2=[{"size":5,"type":"s","subtype":98,"str":"zero"}] +0x1b3d7=[{"size":11,"type":"s","subtype":98,"str":"block-size"}] +0x1b3e2=[{"size":8,"type":"s","subtype":98,"str":"context"}] +0x1b3ea=[{"size":7,"type":"s","subtype":98,"str":"author"}] +0x1b3f1=[{"size":5,"type":"s","subtype":98,"str":"help"}] +0x1b40=[{"size":8,"type":"d","str":"8"}] +0x1b429=[{"size":6,"type":"s","subtype":98,"str":"shell"}] +0x1b42f=[{"size":13,"type":"s","subtype":98,"str":"shell-always"}] +0x1b43c=[{"size":13,"type":"s","subtype":98,"str":"shell-escape"}] +0x1b449=[{"size":20,"type":"s","subtype":98,"str":"shell-escape-always"}] +0x1b45d=[{"size":8,"type":"s","subtype":98,"str":"c-maybe"}] +0x1b465=[{"size":8,"type":"s","subtype":98,"str":"clocale"}] +0x1b470=[{"size":6,"type":"s","subtype":98,"str":"01;34"}] +0x1b476=[{"size":6,"type":"s","subtype":98,"str":"01;36"}] +0x1b47c=[{"size":6,"type":"s","subtype":98,"str":"01;35"}] +0x1b48=[{"size":8,"type":"d","str":"8"}] +0x1b482=[{"size":6,"type":"s","subtype":98,"str":"01;33"}] +0x1b488=[{"size":6,"type":"s","subtype":98,"str":"01;32"}] +0x1b48e=[{"size":6,"type":"s","subtype":98,"str":"37;41"}] +0x1b494=[{"size":6,"type":"s","subtype":98,"str":"30;43"}] +0x1b49a=[{"size":6,"type":"s","subtype":98,"str":"37;44"}] +0x1b4a0=[{"size":6,"type":"s","subtype":98,"str":"34;42"}] +0x1b4a6=[{"size":6,"type":"s","subtype":98,"str":"30;42"}] +0x1b4b0=[{"size":10,"type":"s","subtype":98,"str":"%b %e %Y"}] +0x1b4ba=[{"size":12,"type":"s","subtype":98,"str":"%b %e %H:%M"}] +0x1b4c6=[{"size":12,"type":"s","subtype":98,"str":"%s (%s) %s\\n"}] +0x1b4d6=[{"size":16,"type":"s","subtype":98,"str":"Written by %s.\\n"}] +0x1b4e6=[{"size":23,"type":"s","subtype":98,"str":"Written by %s and %s.\\n"}] +0x1b4fd=[{"size":28,"type":"s","subtype":98,"str":"Written by %s, %s, and %s.\\n"}] +0x1b50=[{"size":8,"type":"d","str":"8"}] +0x1b519=[{"size":10,"type":"s","subtype":98,"str":"BLOCKSIZE"}] +0x1b523=[{"size":16,"type":"s","subtype":98,"str":"POSIXLY_CORRECT"}] +0x1b533=[{"size":18,"type":"s","subtype":98,"str":"eEgGkKmMpPtTyYzZ0"}] +0x1b547=[{"size":21,"type":"s","subtype":98,"str":"Valid arguments are:"}] +0x1b55c=[{"size":8,"type":"s","subtype":98,"str":"\\n - %s"}] +0x1b564=[{"size":5,"type":"s","subtype":98,"str":", %s"}] +0x1b569=[{"size":9,"type":"s","subtype":98,"str":"%m/%d/%y"}] +0x1b572=[{"size":9,"type":"s","subtype":98,"str":"%Y-%m-%d"}] +0x1b57b=[{"size":9,"type":"s","subtype":98,"str":"%H:%M:%S"}] +0x1b58=[{"size":8,"type":"d","str":"8"}] +0x1b584=[{"size":16,"type":"s","subtype":98,"str":"system.nfs4_acl"}] +0x1b594=[{"size":24,"type":"s","subtype":98,"str":"system.posix_acl_access"}] +0x1b5ac=[{"size":25,"type":"s","subtype":98,"str":"system.posix_acl_default"}] +0x1b5c5=[{"size":17,"type":"s","subtype":98,"str":"cannot access %s"}] +0x1b5d6=[{"size":7,"type":"s","subtype":98,"str":"OWNER@"}] +0x1b5dd=[{"size":7,"type":"s","subtype":98,"str":"GROUP@"}] +0x1b5e4=[{"size":10,"type":"s","subtype":98,"str":"EVERYONE@"}] +0x1b5ee=[{"size":29,"type":"s","subtype":98,"str":"cannot read symbolic link %s"}] +0x1b60=[{"size":8,"type":"d","str":"8"}] +0x1b610=[{"size":39,"type":"s","subtype":98,"str":"Try '%s --help' for more information.\\n"}] +0x1b640=[{"size":33,"type":"s","subtype":98,"str":"Usage: %s [OPTION]... [FILE]...\\n"}] +0x1b668=[{"size":144,"type":"s","subtype":98,"str":"List information about the FILEs (the current directory by default).\\nSort entries alphabetically if none of -cftuvSUX nor --sort is specified.\\n"}] +0x1b68=[{"size":8,"type":"d","str":"8"}] +0x1b6f8=[{"size":75,"type":"s","subtype":98,"str":"\\nMandatory arguments to long options are mandatory for short options too.\\n"}] +0x1b70=[{"size":8,"type":"d","str":"8"}] +0x1b748=[{"size":271,"type":"s","subtype":98,"str":" -a, --all do not ignore entries starting with .\\n -A, --almost-all do not list implied . and ..\\n --author with -l, print the author of each file\\n -b, --escape print C-style escapes for nongraphic characters\\n"}] +0x1b78=[{"size":8,"type":"d","str":"8"}] +0x1b80=[{"size":8,"type":"d","str":"8"}] +0x1b858=[{"size":155,"type":"s","subtype":98,"str":" --block-size=SIZE with -l, scale sizes by SIZE when printing them;\\n e.g., '--block-size=M'; see SIZE format below\\n\\n"}] +0x1b88=[{"size":8,"type":"d","str":"8"}] +0x1b8f8=[{"size":72,"type":"s","subtype":98,"str":" -B, --ignore-backups do not list implied entries ending with ~\\n"}] +0x1b90=[{"size":8,"type":"d","str":"8"}] +0x1b940=[{"size":280,"type":"s","subtype":98,"str":" -c with -lt: sort by, and show, ctime (time of last\\n change of file status information);\\n with -l: show ctime and sort by name;\\n otherwise: sort by ctime, newest first\\n\\n"}] +0x1b98=[{"size":8,"type":"d","str":"8"}] +0x1ba0=[{"size":8,"type":"d","str":"8"}] +0x1ba58=[{"size":275,"type":"s","subtype":98,"str":" -C list entries by columns\\n --color[=WHEN] color the output WHEN; more info below\\n -d, --directory list directories themselves, not their contents\\n -D, --dired generate output designed for Emacs' dired mode\\n"}] +0x1ba8=[{"size":8,"type":"d","str":"8"}] +0x1bb0=[{"size":8,"type":"d","str":"8"}] +0x1bb70=[{"size":208,"type":"s","subtype":98,"str":" -f list all entries in directory order\\n -F, --classify[=WHEN] append indicator (one of */=>@|) to entries WHEN\\n --file-type likewise, except do not append '*'\\n"}] +0x1bb8=[{"size":8,"type":"d","str":"8"}] +0x1bc0=[{"size":8,"type":"d","str":"8"}] +0x1bc40=[{"size":148,"type":"s","subtype":98,"str":" --format=WORD across -x, commas -m, horizontal -x, long -l,\\n single-column -1, verbose -l, vertical -C\\n\\n"}] +0x1bc8=[{"size":8,"type":"d","str":"8"}] +0x1bcd8=[{"size":60,"type":"s","subtype":98,"str":" --full-time like -l --time-style=full-iso\\n"}] +0x1bd0=[{"size":8,"type":"d","str":"8"}] +0x1bd18=[{"size":61,"type":"s","subtype":98,"str":" -g like -l, but do not list owner\\n"}] +0x1bd58=[{"size":242,"type":"s","subtype":98,"str":" --group-directories-first\\n group directories before files;\\n can be augmented with a --sort option, but any\\n use of --sort=none (-U) disables grouping\\n\\n"}] +0x1bd8=[{"size":8,"type":"d","str":"8"}] +0x1be0=[{"size":8,"type":"d","str":"8"}] +0x1be50=[{"size":73,"type":"s","subtype":98,"str":" -G, --no-group in a long listing, don't print group names\\n"}] +0x1be8=[{"size":8,"type":"d","str":"8"}] +0x1bea0=[{"size":150,"type":"s","subtype":98,"str":" -h, --human-readable with -l and -s, print sizes like 1K 234M 2G etc.\\n --si likewise, but use powers of 1000 not 1024\\n"}] +0x1bf0=[{"size":8,"type":"d","str":"8"}] +0x1bf38=[{"size":112,"type":"s","subtype":98,"str":" -H, --dereference-command-line\\n follow symbolic links listed on the command line\\n"}] +0x1bf8=[{"size":8,"type":"d","str":"8"}] +0x1bfa8=[{"size":174,"type":"s","subtype":98,"str":" --dereference-command-line-symlink-to-dir\\n follow each command line symbolic link\\n that points to a directory\\n\\n"}] +0x1c00=[{"size":8,"type":"d","str":"8"}] +0x1c058=[{"size":136,"type":"s","subtype":98,"str":" --hide=PATTERN do not list implied entries matching shell PATTERN\\n (overridden by -a or -A)\\n\\n"}] +0x1c08=[{"size":8,"type":"d","str":"8"}] +0x1c0e0=[{"size":56,"type":"s","subtype":98,"str":" --hyperlink[=WHEN] hyperlink file names WHEN\\n"}] +0x1c10=[{"size":8,"type":"d","str":"8"}] +0x1c118=[{"size":234,"type":"s","subtype":98,"str":" --indicator-style=WORD\\n append indicator with style WORD to entry names:\\n none (default), slash (-p),\\n file-type (--file-type), classify (-F)\\n\\n"}] +0x1c18=[{"size":8,"type":"d","str":"8"}] +0x1c20=[{"size":8,"type":"d","str":"8"}] +0x1c208=[{"size":146,"type":"s","subtype":98,"str":" -i, --inode print the index number of each file\\n -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\\n"}] +0x1c28=[{"size":8,"type":"d","str":"8"}] +0x1c2a0=[{"size":154,"type":"s","subtype":98,"str":" -k, --kibibytes default to 1024-byte blocks for file system usage;\\n used only with -s and per directory totals\\n\\n"}] +0x1c30=[{"size":8,"type":"d","str":"8"}] +0x1c340=[{"size":56,"type":"s","subtype":98,"str":" -l use a long listing format\\n"}] +0x1c378=[{"size":222,"type":"s","subtype":98,"str":" -L, --dereference when showing file information for a symbolic\\n link, show information for the file the link\\n references rather than for the link itself\\n\\n"}] +0x1c38=[{"size":8,"type":"d","str":"8"}] +0x1c40=[{"size":8,"type":"d","str":"8"}] +0x1c458=[{"size":80,"type":"s","subtype":98,"str":" -m fill width with a comma separated list of entries\\n"}] +0x1c48=[{"size":8,"type":"d","str":"8"}] +0x1c4a8=[{"size":303,"type":"s","subtype":98,"str":" -n, --numeric-uid-gid like -l, but list numeric user and group IDs\\n -N, --literal print entry names without quoting\\n -o like -l, but do not list group information\\n -p, --indicator-style=slash\\n append / indicator to directories\\n"}] +0x1c50=[{"size":8,"type":"d","str":"8"}] +0x1c58=[{"size":8,"type":"d","str":"8"}] +0x1c5d8=[{"size":71,"type":"s","subtype":98,"str":" -q, --hide-control-chars print ? instead of nongraphic characters\\n"}] +0x1c60=[{"size":8,"type":"d","str":"8"}] +0x1c620=[{"size":156,"type":"s","subtype":98,"str":" --show-control-chars show nongraphic characters as-is (the default,\\n unless program is 'ls' and output is a terminal)\\n\\n"}] +0x1c68=[{"size":8,"type":"d","str":"8"}] +0x1c6c0=[{"size":67,"type":"s","subtype":98,"str":" -Q, --quote-name enclose entry names in double quotes\\n"}] +0x1c70=[{"size":8,"type":"d","str":"8"}] +0x1c708=[{"size":288,"type":"s","subtype":98,"str":" --quoting-style=WORD use quoting style WORD for entry names:\\n literal, locale, shell, shell-always,\\n shell-escape, shell-escape-always, c, escape\\n (overrides QUOTING_STYLE environment variable)\\n\\n"}] +0x1c78=[{"size":8,"type":"d","str":"8"}] +0x1c80=[{"size":8,"type":"d","str":"8"}] +0x1c828=[{"size":197,"type":"s","subtype":98,"str":" -r, --reverse reverse order while sorting\\n -R, --recursive list subdirectories recursively\\n -s, --size print the allocated size of each file, in blocks\\n"}] +0x1c88=[{"size":8,"type":"d","str":"8"}] +0x1c8f0=[{"size":63,"type":"s","subtype":98,"str":" -S sort by file size, largest first\\n"}] +0x1c90=[{"size":8,"type":"d","str":"8"}] +0x1c930=[{"size":159,"type":"s","subtype":98,"str":" --sort=WORD sort by WORD instead of name: none (-U), size (-S),\\n time (-t), version (-v), extension (-X), width\\n\\n"}] +0x1c98=[{"size":8,"type":"d","str":"8"}] +0x1c9d0=[{"size":507,"type":"s","subtype":98,"str":" --time=WORD select which timestamp used to display or sort;\\n access time (-u): atime, access, use;\\n metadata change time (-c): ctime, status;\\n modified time (default): mtime, modification;\\n birth time: birth, creation;\\n with -l, WORD determines which time to show;\\n with --sort=time, sort by WORD (newest first)\\n\\n"}] +0x1ca0=[{"size":8,"type":"d","str":"8"}] +0x1ca8=[{"size":8,"type":"d","str":"8"}] +0x1cb0=[{"size":8,"type":"d","str":"8"}] +0x1cb8=[{"size":8,"type":"d","str":"8"}] +0x1cbd0=[{"size":107,"type":"s","subtype":98,"str":" --time-style=TIME_STYLE\\n time/date format with -l; see TIME_STYLE below\\n"}] +0x1cc0=[{"size":8,"type":"d","str":"8"}] +0x1cc40=[{"size":141,"type":"s","subtype":98,"str":" -t sort by time, newest first; see --time\\n -T, --tabsize=COLS assume tab stops at each COLS instead of 8\\n"}] +0x1cc8=[{"size":8,"type":"d","str":"8"}] +0x1ccd0=[{"size":220,"type":"s","subtype":98,"str":" -u with -lt: sort by, and show, access time;\\n with -l: show access time and sort by name;\\n otherwise: sort by access time, newest first\\n\\n"}] +0x1cd0=[{"size":8,"type":"d","str":"8"}] +0x1cd8=[{"size":8,"type":"d","str":"8"}] +0x1cdb0=[{"size":75,"type":"s","subtype":98,"str":" -U do not sort; list entries in directory order\\n"}] +0x1ce0=[{"size":8,"type":"d","str":"8"}] +0x1ce00=[{"size":76,"type":"s","subtype":98,"str":" -v natural sort of (version) numbers within text\\n"}] +0x1ce50=[{"size":408,"type":"s","subtype":98,"str":" -w, --width=COLS set output width to COLS. 0 means no limit\\n -x list entries by lines instead of by columns\\n -X sort alphabetically by entry extension\\n -Z, --context print any security context of each file\\n --zero end each output line with NUL, not newline\\n -1 list one file per line\\n"}] +0x1ce8=[{"size":8,"type":"d","str":"8"}] +0x1cf0=[{"size":8,"type":"d","str":"8"}] +0x1cf8=[{"size":8,"type":"d","str":"8"}] +0x1cfe8=[{"size":48,"type":"s","subtype":98,"str":" --help display this help and exit\\n"}] +0x1d00=[{"size":8,"type":"d","str":"8"}] +0x1d018=[{"size":57,"type":"s","subtype":98,"str":" --version output version information and exit\\n"}] +0x1d058=[{"size":216,"type":"s","subtype":98,"str":"\\nThe SIZE argument is an integer and optional unit (example: 10K is 10*1024).\\nUnits are K,M,G,T,P,E,Z,Y,R,Q (powers of 1024) or KB,MB,... (powers of 1000).\\nBinary prefixes can be used, too: KiB=K, MiB=M, and so on.\\n"}] +0x1d08=[{"size":8,"type":"d","str":"8"}] +0x1d10=[{"size":8,"type":"d","str":"8"}] +0x1d130=[{"size":376,"type":"s","subtype":98,"str":"\\nThe TIME_STYLE argument can be full-iso, long-iso, iso, locale, or +FORMAT.\\nFORMAT is interpreted like in date(1). If FORMAT is FORMAT1FORMAT2,\\nthen FORMAT1 applies to non-recent files and FORMAT2 to recent files.\\nTIME_STYLE prefixed with 'posix-' takes effect only outside the POSIX locale.\\nAlso the TIME_STYLE environment variable sets the default style to use.\\n"}] +0x1d18=[{"size":8,"type":"d","str":"8"}] +0x1d20=[{"size":8,"type":"d","str":"8"}] +0x1d28=[{"size":8,"type":"d","str":"8"}] +0x1d2a8=[{"size":76,"type":"s","subtype":98,"str":"\\nThe WHEN argument defaults to 'always' and can also be 'auto' or 'never'.\\n"}] +0x1d2f8=[{"size":289,"type":"s","subtype":98,"str":"\\nUsing color to distinguish file types is disabled both by default and\\nwith --color=never. With --color=auto, ls emits color codes only when\\nstandard output is connected to a terminal. The LS_COLORS environment\\nvariable can change the settings. Use the dircolors(1) command to set it.\\n"}] +0x1d30=[{"size":8,"type":"d","str":"8"}] +0x1d38=[{"size":8,"type":"d","str":"8"}] +0x1d40=[{"size":8,"type":"d","str":"8"}] +0x1d420=[{"size":152,"type":"s","subtype":98,"str":"\\nExit status:\\n 0 if OK,\\n 1 if minor problems (e.g., cannot access subdirectory),\\n 2 if serious trouble (e.g., cannot access command-line argument).\\n"}] +0x1d48=[{"size":8,"type":"d","str":"8"}] +0x1d4b8=[{"size":40,"type":"s","subtype":98,"str":"https://www.gnu.org/software/coreutils/"}] +0x1d4e0=[{"size":71,"type":"s","subtype":98,"str":"Report any translation bugs to \\n"}] +0x1d50=[{"size":8,"type":"d","str":"8"}] +0x1d528=[{"size":51,"type":"s","subtype":98,"str":"or available locally via: info '(coreutils) %s%s'\\n"}] +0x1d560=[{"size":40,"type":"s","subtype":98,"str":"cannot determine device and inode of %s"}] +0x1d58=[{"size":8,"type":"d","str":"8"}] +0x1d588=[{"size":41,"type":"s","subtype":98,"str":"%s: not listing already-listed directory"}] +0x1d5b8=[{"size":37,"type":"s","subtype":98,"str":"invalid suffix in %s%s argument '%s'"}] +0x1d5e0=[{"size":56,"type":"s","subtype":98,"str":"A NULL argv[0] was passed through an exec system call.\\n"}] +0x1d60=[{"size":8,"type":"d","str":"8"}] +0x1d618=[{"size":44,"type":"s","subtype":98,"str":"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1"}] +0x1d648=[{"size":59,"type":"s","subtype":98,"str":"ignoring invalid width in environment variable COLUMNS: %s"}] +0x1d68=[{"size":8,"type":"d","str":"8"}] +0x1d688=[{"size":62,"type":"s","subtype":98,"str":"ignoring invalid tab size in environment variable TABSIZE: %s"}] +0x1d6c8=[{"size":65,"type":"s","subtype":98,"str":"ignoring invalid value of environment variable QUOTING_STYLE: %s"}] +0x1d70=[{"size":8,"type":"d","str":"8"}] +0x1d710=[{"size":36,"type":"s","subtype":98,"str":"--dired and --zero are incompatible"}] +0x1d738=[{"size":54,"type":"s","subtype":98,"str":" - +FORMAT (e.g., +%H:%M) for a 'date'-style format\\n"}] +0x1d770=[{"size":52,"type":"s","subtype":98,"str":"unparsable value for LS_COLORS environment variable"}] +0x1d78=[{"size":8,"type":"d","str":"8"}] +0x1d7a8=[{"size":130,"type":"s","subtype":98,"str":"dev_ino_size <= __extension__ ({ struct obstack const *__o = (&dev_ino_obstack); (size_t) (__o->next_free - __o->object_base); })"}] +0x1d80=[{"size":8,"type":"d","str":"8"}] +0x1d830=[{"size":38,"type":"s","subtype":98,"str":"//DIRED-OPTIONS// --quoting-style=%s\\n"}] +0x1d858=[{"size":41,"type":"s","subtype":98,"str":"hash_get_n_entries (active_dir_set) == 0"}] +0x1d88=[{"size":8,"type":"d","str":"8"}] +0x1d888=[{"size":40,"type":"s","subtype":98,"str":"dereference-command-line-symlink-to-dir"}] +0x1d8b0=[{"size":171,"type":"s","subtype":98,"str":"License GPLv3+: GNU GPL version 3 or later <%s>.\\nThis is free software: you are free to change and redistribute it.\\nThere is NO WARRANTY, to the extent permitted by law.\\n"}] +0x1d90=[{"size":8,"type":"d","str":"8"}] +0x1d960=[{"size":34,"type":"s","subtype":98,"str":"https://gnu.org/licenses/gpl.html"}] +0x1d98=[{"size":8,"type":"d","str":"8"}] +0x1d988=[{"size":60,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\n%s, %s, %s, %s,\\n%s, %s, and others.\\n"}] +0x1d9c8=[{"size":32,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\nand %s.\\n"}] +0x1d9e8=[{"size":36,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\n%s, and %s.\\n"}] +0x1da0=[{"size":8,"type":"d","str":"8"}] +0x1da10=[{"size":40,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\n%s, %s, and %s.\\n"}] +0x1da38=[{"size":44,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\n%s, %s, %s, and %s.\\n"}] +0x1da68=[{"size":48,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\n%s, %s, %s, %s,\\nand %s.\\n"}] +0x1da8=[{"size":8,"type":"d","str":"8"}] +0x1da98=[{"size":52,"type":"s","subtype":98,"str":"Written by %s, %s, %s,\\n%s, %s, %s, %s,\\n%s, and %s.\\n"}] +0x1db0=[{"size":8,"type":"d","str":"8"}] +0x1db8=[{"size":8,"type":"d","str":"8"}] +0x1dc0=[{"size":8,"type":"d","str":"8"}] +0x1dc8=[{"size":8,"type":"d","str":"8"}] +0x1dd0=[{"size":8,"type":"d","str":"8"}] +0x1dd8=[{"size":8,"type":"d","str":"8"}] +0x1de0=[{"size":8,"type":"d","str":"8"}] +0x1de8=[{"size":8,"type":"d","str":"8"}] +0x1df0=[{"size":8,"type":"d","str":"8"}] +0x1df8=[{"size":8,"type":"d","str":"8"}] +0x1e00=[{"size":8,"type":"d","str":"8"}] +0x1e08=[{"size":8,"type":"d","str":"8"}] +0x1e10=[{"size":8,"type":"d","str":"8"}] +0x1e120=[{"size":47,"type":"s","subtype":98,"str":"Copyright %s %d Free Software Foundation, Inc."}] +0x1e150=[{"type":"C","str":"[19] -r-- section size 1500 named .eh_frame_hdr"}] +0x1e18=[{"size":8,"type":"d","str":"8"}] +0x1e20=[{"size":8,"type":"d","str":"8"}] +0x1e28=[{"size":8,"type":"d","str":"8"}] +0x1e30=[{"size":8,"type":"d","str":"8"}] +0x1e38=[{"size":8,"type":"d","str":"8"}] +0x1e40=[{"size":8,"type":"d","str":"8"}] +0x1e48=[{"size":8,"type":"d","str":"8"}] +0x1e50=[{"size":8,"type":"d","str":"8"}] +0x1e58=[{"size":8,"type":"d","str":"8"}] +0x1e60=[{"size":8,"type":"d","str":"8"}] +0x1e68=[{"size":8,"type":"d","str":"8"}] +0x1e70=[{"size":8,"type":"d","str":"8"}] +0x1e730=[{"type":"C","str":"[20] -r-- section size 6688 named .eh_frame"}] +0x1e78=[{"size":8,"type":"d","str":"8"}] +0x1e80=[{"size":8,"type":"d","str":"8"}] +0x1e88=[{"size":8,"type":"d","str":"8"}] +0x1e90=[{"size":8,"type":"d","str":"8"}] +0x1e98=[{"size":8,"type":"d","str":"8"}] +0x1ea0=[{"size":8,"type":"d","str":"8"}] +0x1ea8=[{"size":8,"type":"d","str":"8"}] +0x1eb0=[{"size":8,"type":"d","str":"8"}] +0x1eb8=[{"size":8,"type":"d","str":"8"}] +0x1ec0=[{"size":8,"type":"d","str":"8"}] +0x1ec8=[{"size":8,"type":"d","str":"8"}] +0x1ed0=[{"size":8,"type":"d","str":"8"}] +0x1ed8=[{"size":8,"type":"d","str":"8"}] +0x1ee0=[{"size":8,"type":"d","str":"8"}] +0x1ee8=[{"size":8,"type":"d","str":"8"}] +0x1ef0=[{"size":8,"type":"d","str":"8"}] +0x1ef8=[{"size":8,"type":"d","str":"8"}] +0x1f00=[{"size":8,"type":"d","str":"8"}] +0x1f08=[{"size":8,"type":"d","str":"8"}] +0x1f10=[{"size":8,"type":"d","str":"8"}] +0x1f18=[{"size":8,"type":"d","str":"8"}] +0x1f20=[{"size":8,"type":"d","str":"8"}] +0x1f28=[{"size":8,"type":"d","str":"8"}] +0x1f30=[{"size":8,"type":"d","str":"8"}] +0x1f38=[{"size":8,"type":"d","str":"8"}] +0x1f40=[{"size":8,"type":"d","str":"8"}] +0x1f48=[{"size":8,"type":"d","str":"8"}] +0x1f50=[{"size":8,"type":"d","str":"8"}] +0x1f58=[{"size":8,"type":"d","str":"8"}] +0x1f60=[{"size":8,"type":"d","str":"8"}] +0x1f68=[{"size":8,"type":"d","str":"8"}] +0x1f70=[{"size":8,"type":"d","str":"8"}] +0x1f78=[{"size":8,"type":"d","str":"8"}] +0x1f80=[{"size":8,"type":"d","str":"8"}] +0x1f88=[{"size":8,"type":"d","str":"8"}] +0x1f90=[{"size":8,"type":"d","str":"8"}] +0x1f98=[{"size":8,"type":"d","str":"8"}] +0x1fa0=[{"size":8,"type":"d","str":"8"}] +0x1fa8=[{"size":8,"type":"d","str":"8"}] +0x1fb0=[{"size":8,"type":"d","str":"8"}] +0x1fb8=[{"size":8,"type":"d","str":"8"}] +0x1fc0=[{"size":8,"type":"d","str":"8"}] +0x1fc8=[{"size":8,"type":"d","str":"8"}] +0x1fd0=[{"size":8,"type":"d","str":"8"}] +0x1fd8=[{"size":8,"type":"d","str":"8"}] +0x1fe0=[{"size":8,"type":"d","str":"8"}] +0x1fe8=[{"size":8,"type":"d","str":"8"}] +0x1ff0=[{"size":8,"type":"d","str":"8"}] +0x1ff8=[{"size":8,"type":"d","str":"8"}] +0x2000=[{"size":8,"type":"d","str":"8"}] +0x2008=[{"size":8,"type":"d","str":"8"}] +0x2010=[{"size":8,"type":"d","str":"8"}] +0x2018=[{"size":8,"type":"d","str":"8"}] +0x2020=[{"size":8,"type":"d","str":"8"}] +0x2028=[{"size":8,"type":"d","str":"8"}] +0x2030=[{"size":8,"type":"d","str":"8"}] +0x2038=[{"size":8,"type":"d","str":"8"}] +0x2040=[{"size":8,"type":"d","str":"8"}] +0x2048=[{"size":8,"type":"d","str":"8"}] +0x2050=[{"size":8,"type":"d","str":"8"}] +0x2058=[{"size":8,"type":"d","str":"8"}] +0x2060=[{"size":8,"type":"d","str":"8"}] +0x2068=[{"size":8,"type":"d","str":"8"}] +0x2070=[{"size":8,"type":"d","str":"8"}] +0x2078=[{"size":8,"type":"d","str":"8"}] +0x2080=[{"size":8,"type":"d","str":"8"}] +0x2088=[{"size":8,"type":"d","str":"8"}] +0x2090=[{"size":8,"type":"d","str":"8"}] +0x2098=[{"size":8,"type":"d","str":"8"}] +0x20a0=[{"size":8,"type":"d","str":"8"}] +0x20a8=[{"size":8,"type":"d","str":"8"}] +0x20b0=[{"size":8,"type":"d","str":"8"}] +0x20b8=[{"size":8,"type":"d","str":"8"}] +0x20c0=[{"size":8,"type":"d","str":"8"}] +0x20c8=[{"size":8,"type":"d","str":"8"}] +0x20d0=[{"size":8,"type":"d","str":"8"}] +0x20d8=[{"size":8,"type":"d","str":"8"}] +0x20e0=[{"size":8,"type":"d","str":"8"}] +0x20e8=[{"size":8,"type":"d","str":"8"}] +0x20f0=[{"size":8,"type":"d","str":"8"}] +0x20f8=[{"size":8,"type":"d","str":"8"}] +0x2100=[{"size":8,"type":"d","str":"8"}] +0x2108=[{"size":8,"type":"d","str":"8"}] +0x2110=[{"size":8,"type":"d","str":"8"}] +0x2118=[{"size":8,"type":"d","str":"8"}] +0x2120=[{"size":8,"type":"d","str":"8"}] +0x2128=[{"size":8,"type":"d","str":"8"}] +0x2130=[{"size":8,"type":"d","str":"8"}] +0x2138=[{"size":8,"type":"d","str":"8"}] +0x2140=[{"size":8,"type":"d","str":"8"}] +0x2148=[{"size":8,"type":"d","str":"8"}] +0x2150=[{"size":8,"type":"d","str":"8"}] +0x2158=[{"size":8,"type":"d","str":"8"}] +0x2160=[{"size":8,"type":"d","str":"8"}] +0x2168=[{"size":8,"type":"d","str":"8"}] +0x2170=[{"size":8,"type":"d","str":"8"}] +0x2178=[{"size":8,"type":"d","str":"8"}] +0x2180=[{"size":8,"type":"d","str":"8"}] +0x2188=[{"size":8,"type":"d","str":"8"}] +0x2190=[{"size":8,"type":"d","str":"8"}] +0x2198=[{"size":8,"type":"d","str":"8"}] +0x21a0=[{"size":8,"type":"d","str":"8"}] +0x21a8=[{"size":8,"type":"d","str":"8"}] +0x21b0=[{"size":8,"type":"d","str":"8"}] +0x21b8=[{"size":8,"type":"d","str":"8"}] +0x21c0=[{"size":8,"type":"d","str":"8"}] +0x21c8=[{"size":8,"type":"d","str":"8"}] +0x21d0=[{"size":8,"type":"d","str":"8"}] +0x21d8=[{"size":8,"type":"d","str":"8"}] +0x21e0=[{"size":8,"type":"d","str":"8"}] +0x21e50=[{"size":8,"type":"d","str":"8"},{"type":"C","str":"[21] -rw- section size 8 named .init_array"}] +0x21e58=[{"size":8,"type":"d","str":"8"},{"type":"C","str":"[22] -rw- section size 8 named .fini_array"}] +0x21e60=[{"size":8,"type":"d","str":"8"},{"type":"C","str":"[23] -rw- section size 2888 named .data.rel.ro"}] +0x21e68=[{"size":8,"type":"d","str":"8"}] +0x21e70=[{"size":8,"type":"d","str":"8"}] +0x21e78=[{"size":8,"type":"d","str":"8"}] +0x21e8=[{"size":8,"type":"d","str":"8"}] +0x21e80=[{"size":8,"type":"d","str":"8"}] +0x21e88=[{"size":8,"type":"d","str":"8"}] +0x21e90=[{"size":8,"type":"d","str":"8"}] +0x21e98=[{"size":8,"type":"d","str":"8"}] +0x21ea0=[{"size":8,"type":"d","str":"8"}] +0x21ea8=[{"size":8,"type":"d","str":"8"}] +0x21eb0=[{"size":8,"type":"d","str":"8"}] +0x21eb8=[{"size":8,"type":"d","str":"8"}] +0x21ec0=[{"size":8,"type":"d","str":"8"}] +0x21ec8=[{"size":8,"type":"d","str":"8"}] +0x21ed0=[{"size":8,"type":"d","str":"8"}] +0x21ed8=[{"size":8,"type":"d","str":"8"}] +0x21ee0=[{"size":8,"type":"d","str":"8"}] +0x21ee8=[{"size":8,"type":"d","str":"8"}] +0x21ef0=[{"size":8,"type":"d","str":"8"}] +0x21ef8=[{"size":8,"type":"d","str":"8"}] +0x21f0=[{"size":8,"type":"d","str":"8"}] +0x21f00=[{"size":8,"type":"d","str":"8"}] +0x21f08=[{"size":8,"type":"d","str":"8"}] +0x21f10=[{"size":8,"type":"d","str":"8"}] +0x21f18=[{"size":8,"type":"d","str":"8"}] +0x21f20=[{"size":8,"type":"d","str":"8"}] +0x21f28=[{"size":8,"type":"d","str":"8"}] +0x21f30=[{"size":8,"type":"d","str":"8"}] +0x21f38=[{"size":8,"type":"d","str":"8"}] +0x21f40=[{"size":8,"type":"d","str":"8"}] +0x21f48=[{"size":8,"type":"d","str":"8"}] +0x21f50=[{"size":8,"type":"d","str":"8"}] +0x21f58=[{"size":8,"type":"d","str":"8"}] +0x21f60=[{"size":8,"type":"d","str":"8"}] +0x21f68=[{"size":8,"type":"d","str":"8"}] +0x21f70=[{"size":8,"type":"d","str":"8"}] +0x21f78=[{"size":8,"type":"d","str":"8"}] +0x21f8=[{"size":8,"type":"d","str":"8"}] +0x21f80=[{"size":8,"type":"d","str":"8"}] +0x21f88=[{"size":8,"type":"d","str":"8"}] +0x21f90=[{"size":8,"type":"d","str":"8"}] +0x21f98=[{"size":8,"type":"d","str":"8"}] +0x21fa0=[{"size":8,"type":"d","str":"8"}] +0x21fa8=[{"size":8,"type":"d","str":"8"}] +0x21fb0=[{"size":8,"type":"d","str":"8"}] +0x21fb8=[{"size":8,"type":"d","str":"8"}] +0x21fc0=[{"size":8,"type":"d","str":"8"}] +0x21fc8=[{"size":8,"type":"d","str":"8"}] +0x21fd0=[{"size":8,"type":"d","str":"8"}] +0x21fd8=[{"size":8,"type":"d","str":"8"}] +0x21fe0=[{"size":8,"type":"d","str":"8"}] +0x21fe8=[{"size":8,"type":"d","str":"8"}] +0x21ff0=[{"size":8,"type":"d","str":"8"}] +0x21ff8=[{"size":8,"type":"d","str":"8"}] +0x2200=[{"size":8,"type":"d","str":"8"}] +0x22000=[{"size":8,"type":"d","str":"8"}] +0x22008=[{"size":8,"type":"d","str":"8"}] +0x22010=[{"size":8,"type":"d","str":"8"}] +0x22018=[{"size":8,"type":"d","str":"8"}] +0x22020=[{"size":8,"type":"d","str":"8"}] +0x22028=[{"size":8,"type":"d","str":"8"}] +0x22030=[{"size":8,"type":"d","str":"8"}] +0x22038=[{"size":8,"type":"d","str":"8"}] +0x22040=[{"size":8,"type":"d","str":"8"}] +0x22048=[{"size":8,"type":"d","str":"8"}] +0x22050=[{"size":8,"type":"d","str":"8"}] +0x22058=[{"size":8,"type":"d","str":"8"}] +0x22060=[{"size":8,"type":"d","str":"8"}] +0x22068=[{"size":8,"type":"d","str":"8"}] +0x22070=[{"size":8,"type":"d","str":"8"}] +0x22078=[{"size":8,"type":"d","str":"8"}] +0x2208=[{"size":8,"type":"d","str":"8"}] +0x22080=[{"size":8,"type":"d","str":"8"}] +0x22088=[{"size":8,"type":"d","str":"8"}] +0x22090=[{"size":8,"type":"d","str":"8"}] +0x22098=[{"size":8,"type":"d","str":"8"}] +0x220a0=[{"size":8,"type":"d","str":"8"}] +0x220a8=[{"size":8,"type":"d","str":"8"}] +0x220b0=[{"size":8,"type":"d","str":"8"}] +0x220b8=[{"size":8,"type":"d","str":"8"}] +0x220c0=[{"size":8,"type":"d","str":"8"}] +0x220c8=[{"size":8,"type":"d","str":"8"}] +0x220d0=[{"size":8,"type":"d","str":"8"}] +0x220d8=[{"size":8,"type":"d","str":"8"}] +0x220e0=[{"size":8,"type":"d","str":"8"}] +0x220e8=[{"size":8,"type":"d","str":"8"}] +0x220f0=[{"size":8,"type":"d","str":"8"}] +0x220f8=[{"size":8,"type":"d","str":"8"}] +0x2210=[{"size":8,"type":"d","str":"8"}] +0x22100=[{"size":8,"type":"d","str":"8"}] +0x22108=[{"size":8,"type":"d","str":"8"}] +0x22110=[{"size":8,"type":"d","str":"8"}] +0x22118=[{"size":8,"type":"d","str":"8"}] +0x22120=[{"size":8,"type":"d","str":"8"}] +0x22128=[{"size":8,"type":"d","str":"8"}] +0x22130=[{"size":8,"type":"d","str":"8"}] +0x22138=[{"size":8,"type":"d","str":"8"}] +0x22140=[{"size":8,"type":"d","str":"8"}] +0x22148=[{"size":8,"type":"d","str":"8"}] +0x22150=[{"size":8,"type":"d","str":"8"}] +0x22158=[{"size":8,"type":"d","str":"8"}] +0x22160=[{"size":8,"type":"d","str":"8"}] +0x22168=[{"size":8,"type":"d","str":"8"}] +0x22170=[{"size":8,"type":"d","str":"8"}] +0x22178=[{"size":8,"type":"d","str":"8"}] +0x2218=[{"size":8,"type":"d","str":"8"}] +0x22180=[{"size":8,"type":"d","str":"8"}] +0x22188=[{"size":8,"type":"d","str":"8"}] +0x22190=[{"size":8,"type":"d","str":"8"}] +0x22198=[{"size":8,"type":"d","str":"8"}] +0x221a0=[{"size":8,"type":"d","str":"8"}] +0x221a8=[{"size":8,"type":"d","str":"8"}] +0x221b0=[{"size":8,"type":"d","str":"8"}] +0x221b8=[{"size":8,"type":"d","str":"8"}] +0x221c0=[{"size":8,"type":"d","str":"8"}] +0x221c8=[{"size":8,"type":"d","str":"8"}] +0x221d0=[{"size":8,"type":"d","str":"8"}] +0x221d8=[{"size":8,"type":"d","str":"8"}] +0x221e0=[{"size":8,"type":"d","str":"8"}] +0x221e8=[{"size":8,"type":"d","str":"8"}] +0x221f0=[{"size":8,"type":"d","str":"8"}] +0x221f8=[{"size":8,"type":"d","str":"8"}] +0x2220=[{"size":8,"type":"d","str":"8"}] +0x22200=[{"size":8,"type":"d","str":"8"}] +0x22208=[{"size":8,"type":"d","str":"8"}] +0x22210=[{"size":8,"type":"d","str":"8"}] +0x22218=[{"size":8,"type":"d","str":"8"}] +0x22220=[{"size":8,"type":"d","str":"8"}] +0x22228=[{"size":8,"type":"d","str":"8"}] +0x22230=[{"size":8,"type":"d","str":"8"}] +0x22238=[{"size":8,"type":"d","str":"8"}] +0x22240=[{"size":8,"type":"d","str":"8"}] +0x22248=[{"size":8,"type":"d","str":"8"}] +0x22250=[{"size":8,"type":"d","str":"8"}] +0x22258=[{"size":8,"type":"d","str":"8"}] +0x22260=[{"size":8,"type":"d","str":"8"}] +0x22268=[{"size":8,"type":"d","str":"8"}] +0x22270=[{"size":8,"type":"d","str":"8"}] +0x22278=[{"size":8,"type":"d","str":"8"}] +0x2228=[{"size":8,"type":"d","str":"8"}] +0x22280=[{"size":8,"type":"d","str":"8"}] +0x22288=[{"size":8,"type":"d","str":"8"}] +0x22290=[{"size":8,"type":"d","str":"8"}] +0x22298=[{"size":8,"type":"d","str":"8"}] +0x222a0=[{"size":8,"type":"d","str":"8"}] +0x222a8=[{"size":8,"type":"d","str":"8"}] +0x222b0=[{"size":8,"type":"d","str":"8"}] +0x222b8=[{"size":8,"type":"d","str":"8"}] +0x222c0=[{"size":8,"type":"d","str":"8"}] +0x222c8=[{"size":8,"type":"d","str":"8"}] +0x222d0=[{"size":8,"type":"d","str":"8"}] +0x222d8=[{"size":8,"type":"d","str":"8"}] +0x222e0=[{"size":8,"type":"d","str":"8"}] +0x222e8=[{"size":8,"type":"d","str":"8"}] +0x222f0=[{"size":8,"type":"d","str":"8"}] +0x222f8=[{"size":8,"type":"d","str":"8"}] +0x2230=[{"size":8,"type":"d","str":"8"}] +0x22300=[{"size":8,"type":"d","str":"8"}] +0x22308=[{"size":8,"type":"d","str":"8"}] +0x22310=[{"size":8,"type":"d","str":"8"}] +0x22318=[{"size":8,"type":"d","str":"8"}] +0x22320=[{"size":8,"type":"d","str":"8"}] +0x22328=[{"size":8,"type":"d","str":"8"}] +0x22330=[{"size":8,"type":"d","str":"8"}] +0x22338=[{"size":8,"type":"d","str":"8"}] +0x22340=[{"size":8,"type":"d","str":"8"}] +0x22348=[{"size":8,"type":"d","str":"8"}] +0x22350=[{"size":8,"type":"d","str":"8"}] +0x22358=[{"size":8,"type":"d","str":"8"}] +0x22360=[{"size":8,"type":"d","str":"8"}] +0x22368=[{"size":8,"type":"d","str":"8"}] +0x22370=[{"size":8,"type":"d","str":"8"}] +0x22378=[{"size":8,"type":"d","str":"8"}] +0x2238=[{"size":8,"type":"d","str":"8"}] +0x22380=[{"size":8,"type":"d","str":"8"}] +0x22388=[{"size":8,"type":"d","str":"8"}] +0x22390=[{"size":8,"type":"d","str":"8"}] +0x22398=[{"size":8,"type":"d","str":"8"}] +0x223a0=[{"size":8,"type":"d","str":"8"}] +0x223a8=[{"size":8,"type":"d","str":"8"}] +0x223b0=[{"size":8,"type":"d","str":"8"}] +0x223b8=[{"size":8,"type":"d","str":"8"}] +0x223c0=[{"size":8,"type":"d","str":"8"}] +0x223c8=[{"size":8,"type":"d","str":"8"}] +0x223d0=[{"size":8,"type":"d","str":"8"}] +0x223d8=[{"size":8,"type":"d","str":"8"}] +0x223e0=[{"size":8,"type":"d","str":"8"}] +0x223e8=[{"size":8,"type":"d","str":"8"}] +0x223f0=[{"size":8,"type":"d","str":"8"}] +0x223f8=[{"size":8,"type":"d","str":"8"}] +0x2240=[{"size":8,"type":"d","str":"8"}] +0x22400=[{"size":8,"type":"d","str":"8"}] +0x22408=[{"size":8,"type":"d","str":"8"}] +0x22410=[{"size":8,"type":"d","str":"8"}] +0x22418=[{"size":8,"type":"d","str":"8"}] +0x22420=[{"size":8,"type":"d","str":"8"}] +0x22428=[{"size":8,"type":"d","str":"8"}] +0x22430=[{"size":8,"type":"d","str":"8"}] +0x22438=[{"size":8,"type":"d","str":"8"}] +0x22440=[{"size":8,"type":"d","str":"8"}] +0x22448=[{"size":8,"type":"d","str":"8"}] +0x22450=[{"size":8,"type":"d","str":"8"}] +0x22458=[{"size":8,"type":"d","str":"8"}] +0x22460=[{"size":8,"type":"d","str":"8"}] +0x22468=[{"size":8,"type":"d","str":"8"}] +0x22470=[{"size":8,"type":"d","str":"8"}] +0x22478=[{"size":8,"type":"d","str":"8"}] +0x2248=[{"size":8,"type":"d","str":"8"}] +0x22480=[{"size":8,"type":"d","str":"8"}] +0x22488=[{"size":8,"type":"d","str":"8"}] +0x22490=[{"size":8,"type":"d","str":"8"}] +0x22498=[{"size":8,"type":"d","str":"8"}] +0x224a0=[{"size":8,"type":"d","str":"8"}] +0x224a8=[{"size":8,"type":"d","str":"8"}] +0x224b0=[{"size":8,"type":"d","str":"8"}] +0x224b8=[{"size":8,"type":"d","str":"8"}] +0x224c0=[{"size":8,"type":"d","str":"8"}] +0x224c8=[{"size":8,"type":"d","str":"8"}] +0x224d0=[{"size":8,"type":"d","str":"8"}] +0x224d8=[{"size":8,"type":"d","str":"8"}] +0x224e0=[{"size":8,"type":"d","str":"8"}] +0x224e8=[{"size":8,"type":"d","str":"8"}] +0x224f0=[{"size":8,"type":"d","str":"8"}] +0x224f8=[{"size":8,"type":"d","str":"8"}] +0x2250=[{"size":8,"type":"d","str":"8"}] +0x22500=[{"size":8,"type":"d","str":"8"}] +0x22508=[{"size":8,"type":"d","str":"8"}] +0x22510=[{"size":8,"type":"d","str":"8"}] +0x22518=[{"size":8,"type":"d","str":"8"}] +0x22520=[{"size":8,"type":"d","str":"8"}] +0x22528=[{"size":8,"type":"d","str":"8"}] +0x22530=[{"size":8,"type":"d","str":"8"}] +0x22538=[{"size":8,"type":"d","str":"8"}] +0x22540=[{"size":8,"type":"d","str":"8"}] +0x22548=[{"size":8,"type":"d","str":"8"}] +0x22550=[{"size":8,"type":"d","str":"8"}] +0x22558=[{"size":8,"type":"d","str":"8"}] +0x22560=[{"size":8,"type":"d","str":"8"}] +0x22568=[{"size":8,"type":"d","str":"8"}] +0x22570=[{"size":8,"type":"d","str":"8"}] +0x22578=[{"size":8,"type":"d","str":"8"}] +0x2258=[{"size":8,"type":"d","str":"8"}] +0x22580=[{"size":8,"type":"d","str":"8"}] +0x22588=[{"size":8,"type":"d","str":"8"}] +0x22590=[{"size":8,"type":"d","str":"8"}] +0x22598=[{"size":8,"type":"d","str":"8"}] +0x225a0=[{"size":8,"type":"d","str":"8"}] +0x225a8=[{"size":8,"type":"d","str":"8"}] +0x225b0=[{"size":8,"type":"d","str":"8"}] +0x225b8=[{"size":8,"type":"d","str":"8"}] +0x225c0=[{"size":8,"type":"d","str":"8"}] +0x225c8=[{"size":8,"type":"d","str":"8"}] +0x225d0=[{"size":8,"type":"d","str":"8"}] +0x225d8=[{"size":8,"type":"d","str":"8"}] +0x225e0=[{"size":8,"type":"d","str":"8"}] +0x225e8=[{"size":8,"type":"d","str":"8"}] +0x225f0=[{"size":8,"type":"d","str":"8"}] +0x225f8=[{"size":8,"type":"d","str":"8"}] +0x2260=[{"size":8,"type":"d","str":"8"}] +0x22600=[{"size":8,"type":"d","str":"8"}] +0x22608=[{"size":8,"type":"d","str":"8"}] +0x22610=[{"size":8,"type":"d","str":"8"}] +0x22618=[{"size":8,"type":"d","str":"8"}] +0x22620=[{"size":8,"type":"d","str":"8"}] +0x22628=[{"size":8,"type":"d","str":"8"}] +0x22630=[{"size":8,"type":"d","str":"8"}] +0x22638=[{"size":8,"type":"d","str":"8"}] +0x22640=[{"size":8,"type":"d","str":"8"}] +0x22648=[{"size":8,"type":"d","str":"8"}] +0x22650=[{"size":8,"type":"d","str":"8"}] +0x22658=[{"size":8,"type":"d","str":"8"}] +0x22660=[{"size":8,"type":"d","str":"8"}] +0x22668=[{"size":8,"type":"d","str":"8"}] +0x22670=[{"size":8,"type":"d","str":"8"}] +0x22678=[{"size":8,"type":"d","str":"8"}] +0x2268=[{"size":8,"type":"d","str":"8"}] +0x22680=[{"size":8,"type":"d","str":"8"}] +0x22688=[{"size":8,"type":"d","str":"8"}] +0x22690=[{"size":8,"type":"d","str":"8"}] +0x22698=[{"size":8,"type":"d","str":"8"}] +0x226a0=[{"size":8,"type":"d","str":"8"}] +0x226a8=[{"size":8,"type":"d","str":"8"}] +0x226b0=[{"size":8,"type":"d","str":"8"}] +0x226b8=[{"size":8,"type":"d","str":"8"}] +0x226c0=[{"size":8,"type":"d","str":"8"}] +0x226c8=[{"size":8,"type":"d","str":"8"}] +0x226d0=[{"size":8,"type":"d","str":"8"}] +0x226d8=[{"size":8,"type":"d","str":"8"}] +0x226e0=[{"size":8,"type":"d","str":"8"}] +0x226e8=[{"size":8,"type":"d","str":"8"}] +0x226f0=[{"size":8,"type":"d","str":"8"}] +0x226f8=[{"size":8,"type":"d","str":"8"}] +0x2270=[{"size":8,"type":"d","str":"8"}] +0x22700=[{"size":8,"type":"d","str":"8"}] +0x22708=[{"size":8,"type":"d","str":"8"}] +0x22710=[{"size":8,"type":"d","str":"8"}] +0x22718=[{"size":8,"type":"d","str":"8"}] +0x22720=[{"size":8,"type":"d","str":"8"}] +0x22728=[{"size":8,"type":"d","str":"8"}] +0x22730=[{"size":8,"type":"d","str":"8"}] +0x22738=[{"size":8,"type":"d","str":"8"}] +0x22740=[{"size":8,"type":"d","str":"8"}] +0x22748=[{"size":8,"type":"d","str":"8"}] +0x22750=[{"size":8,"type":"d","str":"8"}] +0x22758=[{"size":8,"type":"d","str":"8"}] +0x22760=[{"size":8,"type":"d","str":"8"}] +0x22768=[{"size":8,"type":"d","str":"8"}] +0x22770=[{"size":8,"type":"d","str":"8"}] +0x22778=[{"size":8,"type":"d","str":"8"}] +0x2278=[{"size":8,"type":"d","str":"8"}] +0x22780=[{"size":8,"type":"d","str":"8"}] +0x22788=[{"size":8,"type":"d","str":"8"}] +0x22790=[{"size":8,"type":"d","str":"8"}] +0x22798=[{"size":8,"type":"d","str":"8"}] +0x227a0=[{"size":8,"type":"d","str":"8"}] +0x227a8=[{"size":8,"type":"d","str":"8"}] +0x227b0=[{"size":8,"type":"d","str":"8"}] +0x227b8=[{"size":8,"type":"d","str":"8"}] +0x227c0=[{"size":8,"type":"d","str":"8"}] +0x227c8=[{"size":8,"type":"d","str":"8"}] +0x227d0=[{"size":8,"type":"d","str":"8"}] +0x227d8=[{"size":8,"type":"d","str":"8"}] +0x227e0=[{"size":8,"type":"d","str":"8"}] +0x227e8=[{"size":8,"type":"d","str":"8"}] +0x227f0=[{"size":8,"type":"d","str":"8"}] +0x227f8=[{"size":8,"type":"d","str":"8"}] +0x2280=[{"size":8,"type":"d","str":"8"}] +0x22800=[{"size":8,"type":"d","str":"8"}] +0x22808=[{"size":8,"type":"d","str":"8"}] +0x22810=[{"size":8,"type":"d","str":"8"}] +0x22818=[{"size":8,"type":"d","str":"8"}] +0x22820=[{"size":8,"type":"d","str":"8"}] +0x22828=[{"size":8,"type":"d","str":"8"}] +0x22830=[{"size":8,"type":"d","str":"8"}] +0x22838=[{"size":8,"type":"d","str":"8"}] +0x22840=[{"size":8,"type":"d","str":"8"}] +0x22848=[{"size":8,"type":"d","str":"8"}] +0x22850=[{"size":8,"type":"d","str":"8"}] +0x22858=[{"size":8,"type":"d","str":"8"}] +0x22860=[{"size":8,"type":"d","str":"8"}] +0x22868=[{"size":8,"type":"d","str":"8"}] +0x22870=[{"size":8,"type":"d","str":"8"}] +0x22878=[{"size":8,"type":"d","str":"8"}] +0x2288=[{"size":8,"type":"d","str":"8"}] +0x22880=[{"size":8,"type":"d","str":"8"}] +0x22888=[{"size":8,"type":"d","str":"8"}] +0x22890=[{"size":8,"type":"d","str":"8"}] +0x22898=[{"size":8,"type":"d","str":"8"}] +0x228a0=[{"size":8,"type":"d","str":"8"}] +0x228a8=[{"size":8,"type":"d","str":"8"}] +0x228b0=[{"size":8,"type":"d","str":"8"}] +0x228b8=[{"size":8,"type":"d","str":"8"}] +0x228c0=[{"size":8,"type":"d","str":"8"}] +0x228c8=[{"size":8,"type":"d","str":"8"}] +0x228d0=[{"size":8,"type":"d","str":"8"}] +0x228d8=[{"size":8,"type":"d","str":"8"}] +0x228e0=[{"size":8,"type":"d","str":"8"}] +0x228e8=[{"size":8,"type":"d","str":"8"}] +0x228f0=[{"size":8,"type":"d","str":"8"}] +0x228f8=[{"size":8,"type":"d","str":"8"}] +0x2290=[{"size":8,"type":"d","str":"8"}] +0x22900=[{"size":8,"type":"d","str":"8"}] +0x22908=[{"size":8,"type":"d","str":"8"}] +0x22910=[{"size":8,"type":"d","str":"8"}] +0x22918=[{"size":8,"type":"d","str":"8"}] +0x22920=[{"size":8,"type":"d","str":"8"}] +0x22928=[{"size":8,"type":"d","str":"8"}] +0x22930=[{"size":8,"type":"d","str":"8"}] +0x22938=[{"size":8,"type":"d","str":"8"}] +0x22940=[{"size":8,"type":"d","str":"8"}] +0x22948=[{"size":8,"type":"d","str":"8"}] +0x22950=[{"size":8,"type":"d","str":"8"}] +0x22958=[{"size":8,"type":"d","str":"8"}] +0x22960=[{"size":8,"type":"d","str":"8"}] +0x22968=[{"size":8,"type":"d","str":"8"}] +0x22970=[{"size":8,"type":"d","str":"8"}] +0x22978=[{"size":8,"type":"d","str":"8"}] +0x2298=[{"size":8,"type":"d","str":"8"}] +0x22980=[{"size":8,"type":"d","str":"8"}] +0x22988=[{"size":8,"type":"d","str":"8"}] +0x22990=[{"size":8,"type":"d","str":"8"}] +0x22998=[{"size":8,"type":"d","str":"8"}] +0x229a0=[{"size":8,"type":"d","str":"8"}] +0x229a8=[{"size":8,"type":"d","str":"8"},{"type":"C","str":"[24] -rw- section size 576 named .dynamic"}] +0x229b0=[{"size":8,"type":"d","str":"8"}] +0x229b8=[{"size":8,"type":"d","str":"8"}] +0x229c0=[{"size":8,"type":"d","str":"8"}] +0x229c8=[{"size":8,"type":"d","str":"8"}] +0x229d0=[{"size":8,"type":"d","str":"8"}] +0x229d8=[{"size":8,"type":"d","str":"8"}] +0x229e0=[{"size":8,"type":"d","str":"8"}] +0x229e8=[{"size":8,"type":"d","str":"8"}] +0x229f0=[{"size":8,"type":"d","str":"8"}] +0x229f8=[{"size":8,"type":"d","str":"8"}] +0x22a0=[{"size":8,"type":"d","str":"8"}] +0x22a00=[{"size":8,"type":"d","str":"8"}] +0x22a08=[{"size":8,"type":"d","str":"8"}] +0x22a10=[{"size":8,"type":"d","str":"8"}] +0x22a18=[{"size":8,"type":"d","str":"8"}] +0x22a20=[{"size":8,"type":"d","str":"8"}] +0x22a28=[{"size":8,"type":"d","str":"8"}] +0x22a30=[{"size":8,"type":"d","str":"8"}] +0x22a38=[{"size":8,"type":"d","str":"8"}] +0x22a40=[{"size":8,"type":"d","str":"8"}] +0x22a48=[{"size":8,"type":"d","str":"8"}] +0x22a50=[{"size":8,"type":"d","str":"8"}] +0x22a58=[{"size":8,"type":"d","str":"8"}] +0x22a60=[{"size":8,"type":"d","str":"8"}] +0x22a68=[{"size":8,"type":"d","str":"8"}] +0x22a70=[{"size":8,"type":"d","str":"8"}] +0x22a78=[{"size":8,"type":"d","str":"8"}] +0x22a8=[{"size":8,"type":"d","str":"8"}] +0x22a80=[{"size":8,"type":"d","str":"8"}] +0x22a88=[{"size":8,"type":"d","str":"8"}] +0x22a90=[{"size":8,"type":"d","str":"8"}] +0x22a98=[{"size":8,"type":"d","str":"8"}] +0x22aa0=[{"size":8,"type":"d","str":"8"}] +0x22aa8=[{"size":8,"type":"d","str":"8"}] +0x22ab0=[{"size":8,"type":"d","str":"8"}] +0x22ab8=[{"size":8,"type":"d","str":"8"}] +0x22ac0=[{"size":8,"type":"d","str":"8"}] +0x22ac8=[{"size":8,"type":"d","str":"8"}] +0x22ad0=[{"size":8,"type":"d","str":"8"}] +0x22ad8=[{"size":8,"type":"d","str":"8"}] +0x22ae0=[{"size":8,"type":"d","str":"8"}] +0x22ae8=[{"size":8,"type":"d","str":"8"}] +0x22af0=[{"size":8,"type":"d","str":"8"}] +0x22af8=[{"size":8,"type":"d","str":"8"}] +0x22b0=[{"size":8,"type":"d","str":"8"}] +0x22b00=[{"size":8,"type":"d","str":"8"}] +0x22b08=[{"size":8,"type":"d","str":"8"}] +0x22b10=[{"size":8,"type":"d","str":"8"}] +0x22b18=[{"size":8,"type":"d","str":"8"}] +0x22b20=[{"size":8,"type":"d","str":"8"}] +0x22b28=[{"size":8,"type":"d","str":"8"}] +0x22b30=[{"size":8,"type":"d","str":"8"}] +0x22b38=[{"size":8,"type":"d","str":"8"}] +0x22b40=[{"size":8,"type":"d","str":"8"}] +0x22b48=[{"size":8,"type":"d","str":"8"}] +0x22b50=[{"size":8,"type":"d","str":"8"}] +0x22b58=[{"size":8,"type":"d","str":"8"}] +0x22b60=[{"size":8,"type":"d","str":"8"}] +0x22b68=[{"size":8,"type":"d","str":"8"}] +0x22b70=[{"size":8,"type":"d","str":"8"}] +0x22b78=[{"size":8,"type":"d","str":"8"}] +0x22b8=[{"size":8,"type":"d","str":"8"}] +0x22b80=[{"size":8,"type":"d","str":"8"}] +0x22b88=[{"size":8,"type":"d","str":"8"}] +0x22b90=[{"size":8,"type":"d","str":"8"}] +0x22b98=[{"size":8,"type":"d","str":"8"}] +0x22ba0=[{"size":8,"type":"d","str":"8"}] +0x22ba8=[{"size":8,"type":"d","str":"8"}] +0x22bb0=[{"size":8,"type":"d","str":"8"}] +0x22bb8=[{"size":8,"type":"d","str":"8"}] +0x22bc0=[{"size":8,"type":"d","str":"8"}] +0x22bc8=[{"size":8,"type":"d","str":"8"}] +0x22bd0=[{"size":8,"type":"d","str":"8"}] +0x22bd8=[{"size":8,"type":"d","str":"8"}] +0x22be0=[{"size":8,"type":"d","str":"8"}] +0x22be8=[{"size":8,"type":"d","str":"8"},{"type":"C","str":"[25] -rw- section size 1024 named .got"}] +0x22bf0=[{"size":8,"type":"d","str":"8"}] +0x22bf8=[{"size":8,"type":"d","str":"8"}] +0x22c0=[{"size":8,"type":"d","str":"8"}] +0x22c00=[{"size":8,"type":"d"}] +0x22c08=[{"size":8,"type":"d"}] +0x22c10=[{"size":8,"type":"d"}] +0x22c18=[{"size":8,"type":"d"}] +0x22c20=[{"size":8,"type":"d"}] +0x22c28=[{"size":8,"type":"d"}] +0x22c30=[{"size":8,"type":"d"}] +0x22c38=[{"size":8,"type":"d"}] +0x22c40=[{"size":8,"type":"d"}] +0x22c48=[{"size":8,"type":"d"}] +0x22c50=[{"size":8,"type":"d"}] +0x22c58=[{"size":8,"type":"d"}] +0x22c60=[{"size":8,"type":"d"}] +0x22c68=[{"size":8,"type":"d"}] +0x22c70=[{"size":8,"type":"d"}] +0x22c78=[{"size":8,"type":"d"}] +0x22c8=[{"size":8,"type":"d","str":"8"}] +0x22c80=[{"size":8,"type":"d"}] +0x22c88=[{"size":8,"type":"d"}] +0x22c90=[{"size":8,"type":"d"}] +0x22c98=[{"size":8,"type":"d"}] +0x22ca0=[{"size":8,"type":"d"}] +0x22ca8=[{"size":8,"type":"d"}] +0x22cb0=[{"size":8,"type":"d"}] +0x22cb8=[{"size":8,"type":"d"}] +0x22cc0=[{"size":8,"type":"d"}] +0x22cc8=[{"size":8,"type":"d"}] +0x22cd0=[{"size":8,"type":"d"}] +0x22cd8=[{"size":8,"type":"d"}] +0x22ce0=[{"size":8,"type":"d"}] +0x22ce8=[{"size":8,"type":"d"}] +0x22cf0=[{"size":8,"type":"d"}] +0x22cf8=[{"size":8,"type":"d"}] +0x22d0=[{"size":8,"type":"d","str":"8"}] +0x22d00=[{"size":8,"type":"d"}] +0x22d08=[{"size":8,"type":"d"}] +0x22d10=[{"size":8,"type":"d"}] +0x22d18=[{"size":8,"type":"d"}] +0x22d20=[{"size":8,"type":"d"}] +0x22d28=[{"size":8,"type":"d"}] +0x22d30=[{"size":8,"type":"d"}] +0x22d38=[{"size":8,"type":"d"}] +0x22d40=[{"size":8,"type":"d"}] +0x22d48=[{"size":8,"type":"d"}] +0x22d50=[{"size":8,"type":"d"}] +0x22d58=[{"size":8,"type":"d"}] +0x22d60=[{"size":8,"type":"d"}] +0x22d68=[{"size":8,"type":"d"}] +0x22d70=[{"size":8,"type":"d"}] +0x22d78=[{"size":8,"type":"d"}] +0x22d8=[{"size":8,"type":"d","str":"8"}] +0x22d80=[{"size":8,"type":"d"}] +0x22d88=[{"size":8,"type":"d"}] +0x22d90=[{"size":8,"type":"d"}] +0x22d98=[{"size":8,"type":"d"}] +0x22da0=[{"size":8,"type":"d"}] +0x22da8=[{"size":8,"type":"d"}] +0x22db0=[{"size":8,"type":"d"}] +0x22db8=[{"size":8,"type":"d"}] +0x22dc0=[{"size":8,"type":"d"}] +0x22dc8=[{"size":8,"type":"d"}] +0x22dd0=[{"size":8,"type":"d"}] +0x22dd8=[{"size":8,"type":"d"}] +0x22de0=[{"size":8,"type":"d"}] +0x22de8=[{"size":8,"type":"d"}] +0x22df0=[{"size":8,"type":"d"}] +0x22df8=[{"size":8,"type":"d"}] +0x22e0=[{"size":8,"type":"d","str":"8"}] +0x22e00=[{"size":8,"type":"d"}] +0x22e08=[{"size":8,"type":"d"}] +0x22e10=[{"size":8,"type":"d"}] +0x22e18=[{"size":8,"type":"d"}] +0x22e20=[{"size":8,"type":"d"}] +0x22e28=[{"size":8,"type":"d"}] +0x22e30=[{"size":8,"type":"d"}] +0x22e38=[{"size":8,"type":"d"}] +0x22e40=[{"size":8,"type":"d"}] +0x22e48=[{"size":8,"type":"d"}] +0x22e50=[{"size":8,"type":"d"}] +0x22e58=[{"size":8,"type":"d"}] +0x22e60=[{"size":8,"type":"d"}] +0x22e68=[{"size":8,"type":"d"}] +0x22e70=[{"size":8,"type":"d"}] +0x22e78=[{"size":8,"type":"d"}] +0x22e8=[{"size":8,"type":"d","str":"8"}] +0x22e80=[{"size":8,"type":"d"}] +0x22e88=[{"size":8,"type":"d"}] +0x22e90=[{"size":8,"type":"d"}] +0x22e98=[{"size":8,"type":"d"}] +0x22ea0=[{"size":8,"type":"d"}] +0x22ea8=[{"size":8,"type":"d"}] +0x22eb0=[{"size":8,"type":"d"}] +0x22eb8=[{"size":8,"type":"d"}] +0x22ec0=[{"size":8,"type":"d"}] +0x22ec8=[{"size":8,"type":"d"}] +0x22ed0=[{"size":8,"type":"d"}] +0x22ed8=[{"size":8,"type":"d"}] +0x22ee0=[{"size":8,"type":"d"}] +0x22ee8=[{"size":8,"type":"d"}] +0x22ef0=[{"size":8,"type":"d"}] +0x22ef8=[{"size":8,"type":"d"}] +0x22f0=[{"size":8,"type":"d","str":"8"}] +0x22f00=[{"size":8,"type":"d"}] +0x22f08=[{"size":8,"type":"d"}] +0x22f10=[{"size":8,"type":"d"}] +0x22f18=[{"size":8,"type":"d"}] +0x22f20=[{"size":8,"type":"d"}] +0x22f28=[{"size":8,"type":"d"}] +0x22f30=[{"size":8,"type":"d"}] +0x22f38=[{"size":8,"type":"d"}] +0x22f40=[{"size":8,"type":"d"}] +0x22f48=[{"size":8,"type":"d"}] +0x22f50=[{"size":8,"type":"d"}] +0x22f58=[{"size":8,"type":"d"}] +0x22f60=[{"size":8,"type":"d"}] +0x22f68=[{"size":8,"type":"d"}] +0x22f70=[{"size":8,"type":"d"}] +0x22f78=[{"size":8,"type":"d"}] +0x22f8=[{"size":8,"type":"d","str":"8"}] +0x22f80=[{"size":8,"type":"d"}] +0x22f88=[{"size":8,"type":"d"}] +0x22f90=[{"size":8,"type":"d"}] +0x22f98=[{"size":8,"type":"d"}] +0x22fa0=[{"size":8,"type":"d"}] +0x22fa8=[{"size":8,"type":"d"}] +0x22fb0=[{"size":8,"type":"d"}] +0x22fb8=[{"size":8,"type":"d"}] +0x22fc0=[{"size":8,"type":"d"}] +0x22fc8=[{"size":8,"type":"d"}] +0x22fd0=[{"size":8,"type":"d"}] +0x22fd8=[{"size":8,"type":"d"}] +0x22fe0=[{"size":8,"type":"d"}] +0x2300=[{"size":8,"type":"d","str":"8"}] +0x23000=[{"type":"C","str":"[26] -rw- section size 632 named .data"}] +0x2308=[{"size":8,"type":"d","str":"8"}] +0x2310=[{"size":8,"type":"d","str":"8"}] +0x2318=[{"size":8,"type":"d","str":"8"}] +0x2320=[{"size":8,"type":"d","str":"8"}] +0x2328=[{"size":8,"type":"d","str":"8"}] +0x23280=[{"type":"C","str":"[27] -rw- section size 4768 named .bss"}] +0x2330=[{"size":8,"type":"d","str":"8"}] +0x2338=[{"size":8,"type":"d","str":"8"}] +0x2340=[{"size":8,"type":"d","str":"8"}] +0x2348=[{"size":8,"type":"d","str":"8"}] +0x2350=[{"size":8,"type":"d","str":"8"}] +0x2358=[{"size":8,"type":"d","str":"8"}] +0x2360=[{"size":8,"type":"d","str":"8"}] +0x2368=[{"size":8,"type":"d","str":"8"}] +0x2370=[{"size":8,"type":"d","str":"8"}] +0x2378=[{"size":8,"type":"d","str":"8"}] +0x2380=[{"size":8,"type":"d","str":"8"}] +0x2388=[{"size":8,"type":"d","str":"8"}] +0x2390=[{"size":8,"type":"d","str":"8"}] +0x2398=[{"size":8,"type":"d","str":"8"}] +0x23a0=[{"size":8,"type":"d","str":"8"}] +0x23a8=[{"size":8,"type":"d","str":"8"}] +0x23b0=[{"size":8,"type":"d","str":"8"}] +0x23b8=[{"size":8,"type":"d","str":"8"}] +0x23c0=[{"size":8,"type":"d","str":"8"}] +0x23c8=[{"size":8,"type":"d","str":"8"}] +0x23d0=[{"size":8,"type":"d","str":"8"}] +0x23d8=[{"size":8,"type":"d","str":"8"}] +0x23e0=[{"size":8,"type":"d","str":"8"}] +0x23e8=[{"size":8,"type":"d","str":"8"}] +0x23f0=[{"size":8,"type":"d","str":"8"}] +0x23f8=[{"size":8,"type":"d","str":"8"}] +0x2400=[{"size":8,"type":"d","str":"8"}] +0x2408=[{"size":8,"type":"d","str":"8"}] +0x2410=[{"size":8,"type":"d","str":"8"}] +0x2418=[{"size":8,"type":"d","str":"8"}] +0x2420=[{"size":8,"type":"d","str":"8"}] +0x2428=[{"size":8,"type":"d","str":"8"}] +0x2430=[{"size":8,"type":"d","str":"8"}] +0x2438=[{"size":8,"type":"d","str":"8"}] +0x2440=[{"size":8,"type":"d","str":"8"}] +0x2448=[{"size":8,"type":"d","str":"8"}] +0x2450=[{"size":8,"type":"d","str":"8"}] +0x24528=[{"size":8,"type":"d"}] +0x24530=[{"size":8,"type":"d"}] +0x24538=[{"size":8,"type":"d"}] +0x24540=[{"size":8,"type":"d"}] +0x24548=[{"size":8,"type":"d"}] +0x24550=[{"size":8,"type":"d"}] +0x24558=[{"size":8,"type":"d"}] +0x24560=[{"size":8,"type":"d"}] +0x24568=[{"size":8,"type":"d"}] +0x24570=[{"size":8,"type":"d"}] +0x24578=[{"size":8,"type":"d"}] +0x2458=[{"size":8,"type":"d","str":"8"}] +0x24580=[{"size":8,"type":"d"}] +0x24588=[{"size":8,"type":"d"}] +0x24590=[{"size":8,"type":"d"}] +0x24598=[{"size":8,"type":"d"}] +0x245a0=[{"size":8,"type":"d"}] +0x245a8=[{"size":8,"type":"d"}] +0x245b0=[{"size":8,"type":"d"}] +0x245b8=[{"size":8,"type":"d"}] +0x245c0=[{"size":8,"type":"d"}] +0x245c8=[{"size":8,"type":"d"}] +0x245d0=[{"size":8,"type":"d"}] +0x245d8=[{"size":8,"type":"d"}] +0x245e0=[{"size":8,"type":"d"}] +0x245e8=[{"size":8,"type":"d"}] +0x245f0=[{"size":8,"type":"d"}] +0x245f8=[{"size":8,"type":"d"}] +0x2460=[{"size":8,"type":"d","str":"8"}] +0x24600=[{"size":8,"type":"d"}] +0x24608=[{"size":8,"type":"d"}] +0x24610=[{"size":8,"type":"d"}] +0x24618=[{"size":8,"type":"d"}] +0x24620=[{"size":8,"type":"d"}] +0x24628=[{"size":8,"type":"d"}] +0x24630=[{"size":8,"type":"d"}] +0x24638=[{"size":8,"type":"d"}] +0x24640=[{"size":8,"type":"d"}] +0x24648=[{"size":8,"type":"d"}] +0x24650=[{"size":8,"type":"d"}] +0x24658=[{"size":8,"type":"d"}] +0x24660=[{"size":8,"type":"d"}] +0x24668=[{"size":8,"type":"d"}] +0x24670=[{"size":8,"type":"d"}] +0x24678=[{"size":8,"type":"d"}] +0x2468=[{"size":8,"type":"d","str":"8"}] +0x24680=[{"size":8,"type":"d"}] +0x24688=[{"size":8,"type":"d"}] +0x24690=[{"size":8,"type":"d"}] +0x24698=[{"size":8,"type":"d"}] +0x246a0=[{"size":8,"type":"d"}] +0x246a8=[{"size":8,"type":"d"}] +0x246b0=[{"size":8,"type":"d"}] +0x246b8=[{"size":8,"type":"d"}] +0x246c0=[{"size":8,"type":"d"}] +0x246c8=[{"size":8,"type":"d"}] +0x246d0=[{"size":8,"type":"d"}] +0x246d8=[{"size":8,"type":"d"}] +0x246e0=[{"size":8,"type":"d"}] +0x246e8=[{"size":8,"type":"d"}] +0x246f0=[{"size":8,"type":"d"}] +0x246f8=[{"size":8,"type":"d"}] +0x2470=[{"size":8,"type":"d","str":"8"}] +0x24700=[{"size":8,"type":"d"}] +0x24708=[{"size":8,"type":"d"}] +0x24710=[{"size":8,"type":"d"}] +0x24718=[{"size":8,"type":"d"}] +0x24720=[{"size":8,"type":"d"}] +0x24728=[{"size":8,"type":"d"}] +0x24730=[{"size":8,"type":"d"}] +0x24738=[{"size":8,"type":"d"}] +0x24740=[{"size":8,"type":"d"}] +0x24748=[{"size":8,"type":"d"}] +0x24750=[{"size":8,"type":"d"}] +0x24758=[{"size":8,"type":"d"}] +0x24760=[{"size":8,"type":"d"}] +0x24768=[{"size":8,"type":"d"}] +0x24770=[{"size":8,"type":"d"}] +0x24778=[{"size":8,"type":"d"}] +0x2478=[{"size":8,"type":"d","str":"8"}] +0x24780=[{"size":8,"type":"d"}] +0x24788=[{"size":8,"type":"d"}] +0x24790=[{"size":8,"type":"d"}] +0x24798=[{"size":8,"type":"d"}] +0x247a0=[{"size":8,"type":"d"}] +0x247a8=[{"size":8,"type":"d"}] +0x247b0=[{"size":8,"type":"d"}] +0x247b8=[{"size":8,"type":"d"}] +0x247c0=[{"size":8,"type":"d"}] +0x247c8=[{"size":8,"type":"d"}] +0x247d0=[{"size":8,"type":"d"}] +0x247d8=[{"size":8,"type":"d"}] +0x247e0=[{"size":8,"type":"d"}] +0x247e8=[{"size":8,"type":"d"}] +0x247f0=[{"size":8,"type":"d"}] +0x247f8=[{"size":8,"type":"d"}] +0x2480=[{"size":8,"type":"d","str":"8"}] +0x24800=[{"size":8,"type":"d"}] +0x24808=[{"size":8,"type":"d"}] +0x24810=[{"size":8,"type":"d"}] +0x24818=[{"size":8,"type":"d"}] +0x24820=[{"size":8,"type":"d"}] +0x24828=[{"size":8,"type":"d"}] +0x24830=[{"size":8,"type":"d"}] +0x24838=[{"size":8,"type":"d"}] +0x24840=[{"size":8,"type":"d"}] +0x24848=[{"size":8,"type":"d"}] +0x24850=[{"size":8,"type":"d"}] +0x24858=[{"size":8,"type":"d"}] +0x24860=[{"size":8,"type":"d"}] +0x24868=[{"size":8,"type":"d"}] +0x24870=[{"size":8,"type":"d"}] +0x24878=[{"size":8,"type":"d"}] +0x2488=[{"size":8,"type":"d","str":"8"}] +0x24880=[{"size":8,"type":"d"}] +0x24888=[{"size":8,"type":"d"}] +0x24890=[{"size":8,"type":"d"}] +0x24898=[{"size":8,"type":"d"}] +0x248a0=[{"size":8,"type":"d"}] +0x248a8=[{"size":8,"type":"d"}] +0x248b0=[{"size":8,"type":"d"}] +0x248b8=[{"size":8,"type":"d"}] +0x248c0=[{"size":8,"type":"d"}] +0x248c8=[{"size":8,"type":"d"}] +0x248d0=[{"size":8,"type":"d"}] +0x248d8=[{"size":8,"type":"d"}] +0x248e0=[{"size":8,"type":"d"}] +0x248e8=[{"size":8,"type":"d"}] +0x2490=[{"size":8,"type":"d","str":"8"}] +0x2498=[{"size":8,"type":"d","str":"8"}] +0x24a0=[{"size":8,"type":"d","str":"8"}] +0x24a8=[{"size":8,"type":"d","str":"8"}] +0x24b0=[{"size":8,"type":"d","str":"8"}] +0x24b8=[{"size":8,"type":"d","str":"8"}] +0x24c0=[{"size":8,"type":"d","str":"8"}] +0x24c8=[{"size":8,"type":"d","str":"8"}] +0x24d0=[{"size":8,"type":"d","str":"8"}] +0x24d8=[{"size":8,"type":"d","str":"8"}] +0x24e0=[{"size":8,"type":"d","str":"8"}] +0x24e8=[{"size":8,"type":"d","str":"8"}] +0x24f0=[{"size":8,"type":"d","str":"8"}] +0x24f8=[{"type":"C","str":"[12] -r-- section size 72 named .relr.dyn"}] +0x3000=[{"type":"C","str":"[13] -r-x section size 27 named .init"}] +0x3020=[{"type":"C","str":"[14] -r-x section size 1792 named .plt"}] +0x318=[{"type":"C","str":"[00] -r-- section size 28 named .interp"}] +0x338=[{"type":"C","str":"[01] -r-- section size 80 named .note.gnu.property"}] +0x3720=[{"type":"C","str":"[15] -r-x section size 1776 named .plt.sec"}] +0x388=[{"type":"C","str":"[02] -r-- section size 36 named .note.gnu.build-id"}] +0x3ac=[{"type":"C","str":"[03] -r-- section size 32 named .note.ABI-tag"}] +0x3cc=[{"type":"C","str":"[04] -r-- section size 140 named .note.package"}] +0x3e40=[{"type":"C","str":"[16] -r-x section size 86306 named .text"}] +0x458=[{"type":"C","str":"[05] -r-- section size 64 named .gnu.hash"}] +0x498=[{"type":"C","str":"[06] -r-- section size 3144 named .dynsym"}] + +/core/analysis/meta/spaces +name=CS +spacestack=["*"] + +/core/analysis/meta/spaces/spaces +bin=s + +/core/analysis/noreturn + +/core/analysis/types +FILE=typedef +_Bool=type +__div_t=struct +__idtype=enum +__imaxdiv_t=struct +__ldiv_t=struct +__lldiv_t=struct +__siginfo_t=struct +__sigset_t=struct +_fd_set=struct +access_perm=enum +bool=type +char=type +char *=type +char16_t=type +char32_t=type +char8_t=type +clock_t=typedef +div_t=typedef +double=type +enum.__idtype=P_ALL,P_GID,P_PGID +enum.__idtype.0x0=P_ALL +enum.__idtype.0x1=P_GID +enum.__idtype.0x2=P_PGID +enum.__idtype.P_ALL=0x0 +enum.__idtype.P_GID=0x1 +enum.__idtype.P_PGID=0x2 +enum.access_perm=F_OK,X_OK,W_OK,R_OK,WX_OK,RX_OK,RW_OK,RWX_OK +enum.access_perm.0x0=F_OK +enum.access_perm.0x1=X_OK +enum.access_perm.0x2=W_OK +enum.access_perm.0x3=WX_OK +enum.access_perm.0x4=R_OK +enum.access_perm.0x5=RX_OK +enum.access_perm.0x6=RW_OK +enum.access_perm.0x7=RWX_OK +enum.access_perm.F_OK=0x0 +enum.access_perm.RWX_OK=0x7 +enum.access_perm.RW_OK=0x6 +enum.access_perm.RX_OK=0x5 +enum.access_perm.R_OK=0x4 +enum.access_perm.WX_OK=0x3 +enum.access_perm.W_OK=0x2 +enum.access_perm.X_OK=0x1 +enum.sock_domain=AF_UNIX,AF_INET,AF_AX25,AF_IPX,AF_APPLETALK,AF_X25,AF_INET6,AF_DECnet,AF_KEY,AF_NETLINK,AF_PACKET,AF_RDS,AF_PPPOX,AF_LLC,AF_IB,AF_MPLS,AF_CAN,AF_TIPC,AF_BLUETOOTH,AF_ALG,AF_VSOCK,AF_KCM,AF_XDP +enum.sock_domain.0x1=AF_UNIX +enum.sock_domain.0x10=AF_INET6 +enum.sock_domain.0x12=AF_DECnet +enum.sock_domain.0x15=AF_KEY +enum.sock_domain.0x16=AF_NETLINK +enum.sock_domain.0x17=AF_PACKET +enum.sock_domain.0x2=AF_INET +enum.sock_domain.0x21=AF_RDS +enum.sock_domain.0x24=AF_PPPOX +enum.sock_domain.0x26=AF_LLC +enum.sock_domain.0x27=AF_IB +enum.sock_domain.0x28=AF_MPLS +enum.sock_domain.0x29=AF_CAN +enum.sock_domain.0x3=AF_AX25 +enum.sock_domain.0x30=AF_TIPC +enum.sock_domain.0x31=AF_BLUETOOTH +enum.sock_domain.0x38=AF_ALG +enum.sock_domain.0x4=AF_IPX +enum.sock_domain.0x40=AF_VSOCK +enum.sock_domain.0x41=AF_KCM +enum.sock_domain.0x44=AF_XDP +enum.sock_domain.0x5=AF_APPLETALK +enum.sock_domain.0x9=AF_X25 +enum.sock_domain.AF_ALG=0x38 +enum.sock_domain.AF_APPLETALK=0x5 +enum.sock_domain.AF_AX25=0x3 +enum.sock_domain.AF_BLUETOOTH=0x31 +enum.sock_domain.AF_CAN=0x29 +enum.sock_domain.AF_DECnet=0x12 +enum.sock_domain.AF_IB=0x27 +enum.sock_domain.AF_INET=0x2 +enum.sock_domain.AF_INET6=0x10 +enum.sock_domain.AF_IPX=0x4 +enum.sock_domain.AF_KCM=0x41 +enum.sock_domain.AF_KEY=0x15 +enum.sock_domain.AF_LLC=0x26 +enum.sock_domain.AF_MPLS=0x28 +enum.sock_domain.AF_NETLINK=0x16 +enum.sock_domain.AF_PACKET=0x17 +enum.sock_domain.AF_PPPOX=0x24 +enum.sock_domain.AF_RDS=0x21 +enum.sock_domain.AF_TIPC=0x30 +enum.sock_domain.AF_UNIX=0x1 +enum.sock_domain.AF_VSOCK=0x40 +enum.sock_domain.AF_X25=0x9 +enum.sock_domain.AF_XDP=0x44 +enum.sock_type=SOCK_STREAM,SOCK_DGRAM,SOCK_SEQPACKET,SOCK_RAW,SOCK_RDM,SOCK_PACKET,SOCK_DCCP +enum.sock_type.0x1=SOCK_DGRAM +enum.sock_type.0x2=SOCK_STREAM +enum.sock_type.0x3=SOCK_RAW +enum.sock_type.0x4=SOCK_RDM +enum.sock_type.0x5=SOCK_SEQPACKET +enum.sock_type.0x6=SOCK_DCCP +enum.sock_type.0x7=SOCK_PACKET +enum.sock_type.SOCK_DCCP=0x6 +enum.sock_type.SOCK_DGRAM=0x1 +enum.sock_type.SOCK_PACKET=0x7 +enum.sock_type.SOCK_RAW=0x3 +enum.sock_type.SOCK_RDM=0x4 +enum.sock_type.SOCK_SEQPACKET=0x5 +enum.sock_type.SOCK_STREAM=0x2 +fd_mask=typedef +fd_set=typedef +fenv_t=typedef +fexcept_t=typedef +float=type +fpos_t=typedef +gid_t=type +id_t=type +idtype_t=typedef +imaxdiv_t=typedef +int=type +int16_t=type +int32_t=type +int64_t=type +int8_t=type +int_fast16_t=type +int_fast32_t=type +int_fast64_t=type +int_fast8_t=type +int_least16_t=type +int_least32_t=type +int_least64_t=type +int_least8_t=type +intmax_t=type +intptr_t=type +jmp_buf=typedef +lconv=struct +ldiv_t=typedef +lldiv_t=typedef +locale_t=typedef +long=type +long double=type +long int=type +long long=type +long long int=type +long long signed=type +long long signed int=type +long long unsigned=type +long long unsigned int=type +long signed int=type +long unsigned=type +long unsigned int=type +mbstate_t=typedef +nl_item=typedef +pid_t=type +ptrdiff_t=type +short=type +short int=type +short signed int=type +short unsigned int=type +sigaction=struct +siginfo_t=typedef +signed char=type +signed int=type +signed long=type +signed long int=type +signed long long=type +signed long long int=type +signed short=type +signed short int=type +sigset_t=typedef +sigval=union +size_t=type +sock_domain=enum +sock_type=enum +sockaddr=struct +socklen_t=typedef +ssize_t=type +std__type_info=struct +struct.__div_t=quot,rem +struct.__div_t.quot=int,0,0 +struct.__div_t.rem=int,2,0 +struct.__imaxdiv_t=quot,rem +struct.__imaxdiv_t.quot=intmax_t,0,0 +struct.__imaxdiv_t.rem=intmax_t,8,0 +struct.__ldiv_t=quot,rem +struct.__ldiv_t.quot=long int,0,0 +struct.__ldiv_t.rem=long int,4,0 +struct.__lldiv_t=quot,rem +struct.__lldiv_t.quot=long long int,0,0 +struct.__lldiv_t.rem=long long int,4,0 +struct.__siginfo_t=si_signo,si_code,si_value,si_errno,si_pid,si_uid,si_addr,si_status,si_band +struct.__siginfo_t.si_addr=void *,28,0 +struct.__siginfo_t.si_band=int,36,0 +struct.__siginfo_t.si_code=int,4,0 +struct.__siginfo_t.si_errno=int,16,0 +struct.__siginfo_t.si_pid=pid_t,20,0 +struct.__siginfo_t.si_signo=int,0,0 +struct.__siginfo_t.si_status=int,32,0 +struct.__siginfo_t.si_uid=uid_t,24,0 +struct.__siginfo_t.si_value=union sigval,8,0 +struct.__sigset_t=sig +struct.__sigset_t.sig=unsigned long,0,0 +struct._fd_set=fds_bits +struct._fd_set.fds_bits=fd_mask,0,0 +struct.sigaction=sa_handler,sa_flags,sa_restorer,sa_mask +struct.sigaction.sa_flags=unsigned long,8,0 +struct.sigaction.sa_handler=void *,0,0 +struct.sigaction.sa_mask=sigset_t,20,0 +struct.sigaction.sa_restorer=void *,12,0 +struct.timespec=tv_sec,tv_nsec +struct.timespec.tv_nsec=long,8,0 +struct.timespec.tv_sec=time_t,0,0 +struct.timeval=tv_sec,tv_usec +struct.timeval.tv_sec=time_t,0,0 +struct.timeval.tv_usec=suseconds_t,8,0 +struct.tm=tm_sec,tm_min,tm_hour,tm_mday,tm_mon,tm_year,tm_wday,tm_yday,tm_isdst +struct.tm.tm_hour=int,8,0 +struct.tm.tm_isdst=int,32,0 +struct.tm.tm_mday=int,12,0 +struct.tm.tm_min=int,4,0 +struct.tm.tm_mon=int,16,0 +struct.tm.tm_sec=int,0,0 +struct.tm.tm_wday=int,24,0 +struct.tm.tm_yday=int,28,0 +struct.tm.tm_year=int,20,0 +suseconds_t=typedef +time_t=typedef +timespec=struct +timeval=struct +tm=struct +type._Bool=b +type._Bool.size=8 +type._Bool.typeclass=None +type.bool=b +type.bool.size=8 +type.bool.typeclass=None +type.char=c +type.char *=z +type.char *.size=64 +type.char *.typeclass=None +type.char.size=8 +type.char.typeclass=Signed Integral +type.char16_t=c +type.char16_t.size=16 +type.char16_t.typeclass=Signed Integral +type.char32_t=c +type.char32_t.size=32 +type.char32_t.typeclass=Signed Integral +type.char8_t=c +type.char8_t.size=8 +type.char8_t.typeclass=Signed Integral +type.double=F +type.double.size=64 +type.double.typeclass=Floating +type.float=f +type.float.size=32 +type.float.typeclass=Floating +type.gid_t=q +type.gid_t.size=64 +type.gid_t.typeclass=Integral +type.id_t=q +type.id_t.size=64 +type.id_t.typeclass=Integral +type.int=d +type.int.size=32 +type.int.typeclass=Signed Integral +type.int16_t=w +type.int16_t.size=16 +type.int16_t.typeclass=Signed Integral +type.int32_t=d +type.int32_t.size=32 +type.int32_t.typeclass=Signed Integral +type.int64_t=q +type.int64_t.size=64 +type.int64_t.typeclass=Signed Integral +type.int8_t=b +type.int8_t.size=8 +type.int8_t.typeclass=Signed Integral +type.int_fast16_t=w +type.int_fast16_t.size=16 +type.int_fast16_t.typeclass=Signed Integral +type.int_fast32_t=d +type.int_fast32_t.size=32 +type.int_fast32_t.typeclass=Signed Integral +type.int_fast64_t=q +type.int_fast64_t.size=64 +type.int_fast64_t.typeclass=Signed Integral +type.int_fast8_t=b +type.int_fast8_t.size=8 +type.int_fast8_t.typeclass=Signed Integral +type.int_least16_t=w +type.int_least16_t.size=16 +type.int_least16_t.typeclass=Signed Integral +type.int_least32_t=d +type.int_least32_t.size=32 +type.int_least32_t.typeclass=Signed Integral +type.int_least64_t=q +type.int_least64_t.size=64 +type.int_least64_t.typeclass=Signed Integral +type.int_least8_t=b +type.int_least8_t.size=8 +type.int_least8_t.typeclass=Signed Integral +type.intmax_t=q +type.intmax_t.size=64 +type.intmax_t.typeclass=Signed Integral +type.intptr_t=q +type.intptr_t.size=64 +type.intptr_t.typeclass=Signed Integral +type.long=q +type.long double=F +type.long double.size=64 +type.long double.typeclass=Floating +type.long int=q +type.long int.size=64 +type.long int.typeclass=Signed Integral +type.long long=q +type.long long int=q +type.long long int.size=64 +type.long long int.typeclass=Signed Integral +type.long long signed=q +type.long long signed int=q +type.long long signed int.size=64 +type.long long signed int.typeclass=Signed Integral +type.long long signed.size=64 +type.long long signed.typeclass=Signed Integral +type.long long unsigned=q +type.long long unsigned int=q +type.long long unsigned int.size=64 +type.long long unsigned int.typeclass=Unsigned Integral +type.long long unsigned.size=64 +type.long long unsigned.typeclass=Unsigned Integral +type.long long.size=64 +type.long long.typeclass=Signed Integral +type.long signed int=d +type.long signed int.size=32 +type.long signed int.typeclass=Signed Integral +type.long unsigned=q +type.long unsigned int=q +type.long unsigned int.size=64 +type.long unsigned int.typeclass=Unsigned Integral +type.long unsigned.size=64 +type.long unsigned.typeclass=Unsigned Integral +type.long.size=64 +type.long.typeclass=Signed Integral +type.pid_t=q +type.pid_t.size=64 +type.pid_t.typeclass=Integral +type.ptrdiff_t=q +type.ptrdiff_t.size=64 +type.ptrdiff_t.typeclass=Integral +type.short=w +type.short int=w +type.short int.size=16 +type.short int.typeclass=Signed Integral +type.short signed int=w +type.short signed int.size=16 +type.short signed int.typeclass=Signed Integral +type.short unsigned int=w +type.short unsigned int.size=16 +type.short unsigned int.typeclass=Unsigned Integral +type.short.size=16 +type.short.typeclass=Signed Integral +type.signed char=b +type.signed char.size=8 +type.signed char.typeclass=Signed Integral +type.signed int=i +type.signed int.size=32 +type.signed int.typeclass=Signed Integral +type.signed long=d +type.signed long int=d +type.signed long int.size=32 +type.signed long int.typeclass=Signed Integral +type.signed long long=q +type.signed long long int=q +type.signed long long int.size=64 +type.signed long long int.typeclass=Signed Integral +type.signed long long.size=64 +type.signed long long.typeclass=Signed Integral +type.signed long.size=32 +type.signed long.typeclass=Signed Integral +type.signed short=w +type.signed short int=w +type.signed short int.size=16 +type.signed short int.typeclass=Signed Integral +type.signed short.size=16 +type.signed short.typeclass=Signed Integral +type.size_t=q +type.size_t.size=64 +type.size_t.typeclass=Unsigned Integral +type.ssize_t=q +type.ssize_t.size=64 +type.ssize_t.typeclass=Signed Integral +type.uid_t=q +type.uid_t.size=64 +type.uid_t.typeclass=Integral +type.uint16_t=w +type.uint16_t.size=16 +type.uint16_t.typeclass=Unsigned Integral +type.uint32_t=d +type.uint32_t.size=32 +type.uint32_t.typeclass=Unsigned Integral +type.uint64_t=q +type.uint64_t.size=64 +type.uint64_t.typeclass=Unsigned Integral +type.uint8_t=b +type.uint8_t.size=8 +type.uint8_t.typeclass=Unsigned Integral +type.uint_fast16_t=w +type.uint_fast16_t.size=16 +type.uint_fast16_t.typeclass=Unsigned Integral +type.uint_fast32_t=d +type.uint_fast32_t.size=32 +type.uint_fast32_t.typeclass=Unsigned Integral +type.uint_fast64_t=q +type.uint_fast64_t.size=64 +type.uint_fast64_t.typeclass=Unsigned Integral +type.uint_fast8_t=b +type.uint_fast8_t.size=8 +type.uint_fast8_t.typeclass=Unsigned Integral +type.uint_least16_t=w +type.uint_least16_t.size=16 +type.uint_least16_t.typeclass=Unsigned Integral +type.uint_least32_t=d +type.uint_least32_t.size=32 +type.uint_least32_t.typeclass=Unsigned Integral +type.uint_least64_t=q +type.uint_least64_t.size=64 +type.uint_least64_t.typeclass=Unsigned Integral +type.uint_least8_t=b +type.uint_least8_t.size=8 +type.uint_least8_t.typeclass=Unsigned Integral +type.uintmax_t=q +type.uintmax_t.size=64 +type.uintmax_t.typeclass=Unsigned Integral +type.uintptr_t=q +type.uintptr_t.size=64 +type.uintptr_t.typeclass=Unsigned Integral +type.unknown_t=q +type.unknown_t.size=64 +type.unknown_t.typeclass=Integral +type.unsigned char=b +type.unsigned char.size=8 +type.unsigned char.typeclass=Unsigned Integral +type.unsigned int=i +type.unsigned int.size=32 +type.unsigned int.typeclass=Unsigned Integral +type.unsigned long=q +type.unsigned long int=q +type.unsigned long int.size=64 +type.unsigned long int.typeclass=Unsigned Integral +type.unsigned long long=q +type.unsigned long long int=q +type.unsigned long long int.size=64 +type.unsigned long long int.typeclass=Unsigned Integral +type.unsigned long long.size=64 +type.unsigned long long.typeclass=Unsigned Integral +type.unsigned long.size=64 +type.unsigned long.typeclass=Unsigned Integral +type.unsigned short=w +type.unsigned short int=w +type.unsigned short int.size=16 +type.unsigned short int.typeclass=Unsigned Integral +type.unsigned short.size=16 +type.unsigned short.typeclass=Unsigned Integral +type.void *=p +type.void *.size=64 +type.void *.typeclass=None +type.void.size=0 +type.void.typeclass=None +typedef.FILE=void +typedef.clock_t=void +typedef.div_t=struct __div_t +typedef.fd_mask=long int +typedef.fd_set=struct _fd_set +typedef.fenv_t=void +typedef.fexcept_t=void +typedef.fpos_t=void +typedef.idtype_t=enum __idtype +typedef.imaxdiv_t=struct __imaxdiv_t +typedef.jmp_buf=void +typedef.ldiv_t=struct __ldiv_t +typedef.lldiv_t=struct __lldiv_t +typedef.locale_t=void +typedef.mbstate_t=void +typedef.nl_item=int +typedef.siginfo_t=struct __siginfo_t +typedef.sigset_t=struct __sigset_t +typedef.socklen_t=int +typedef.suseconds_t=long +typedef.time_t=long +typedef.va_list=char * +typedef.wchar_t=int +typedef.wctrans_t=unsigned int +typedef.wctype_t=int +typedef.wint_t=int +uid_t=type +uint16_t=type +uint32_t=type +uint64_t=type +uint8_t=type +uint_fast16_t=type +uint_fast32_t=type +uint_fast64_t=type +uint_fast8_t=type +uint_least16_t=type +uint_least32_t=type +uint_least64_t=type +uint_least8_t=type +uintmax_t=type +uintptr_t=type +union.sigval=sival_int,sival_ptr +union.sigval.sival_int=int,0,0 +union.sigval.sival_ptr=void *,0,0 +unknown_t=type +unsigned char=type +unsigned int=type +unsigned long=type +unsigned long int=type +unsigned long long=type +unsigned long long int=type +unsigned short=type +unsigned short int=type +va_list=typedef +void=type +void *=type +wchar_t=typedef +wctrans_t=typedef +wctype_t=typedef +wint_t=typedef + +/core/analysis/vars + +/core/analysis/xrefs + +/core/config +analysis.apply.signature=true +analysis.arch=x86 +analysis.armthumb=false +analysis.autoname=false +analysis.bb.maxsize=512K +analysis.brokenrefs=false +analysis.calls=false +analysis.cpp.abi=itanium +analysis.cpu=x86 +analysis.datarefs=false +analysis.delay=true +analysis.depth=64 +analysis.detectwrites=false +analysis.esil=false +analysis.fcnprefix=fcn +analysis.from=0xffffffffffffffff +analysis.gp=0 +analysis.gpfixed=true +analysis.graph_depth=256 +analysis.hasnext=false +analysis.hpskip=false +analysis.ignbithints=false +analysis.in=io.maps.x +analysis.jmp.above=true +analysis.jmp.after=true +analysis.jmp.cref=false +analysis.jmp.indir=false +analysis.jmp.mid=true +analysis.jmp.ref=true +analysis.jmp.retpoline=true +analysis.jmp.tbl=true +analysis.jmp.tblmax=512 +analysis.jmp.tblmaxoffset=0x00001000 +analysis.limits=false +analysis.loads=false +analysis.nonull=0 +analysis.nopskip=true +analysis.norevisit=false +analysis.prelude.limit=0x01400000 +analysis.ptrdepth=3 +analysis.pushret=false +analysis.recont=false +analysis.refstr=false +analysis.resolve.pointers=true +analysis.rnr=false +analysis.roregs=gp,zero +analysis.sleep=0 +analysis.strings=false +analysis.timeout=0 +analysis.to=0xffffffffffffffff +analysis.trap.after=false +analysis.trycatch=false +analysis.types.constraint=false +analysis.types.spec=gcc +analysis.types.verbose=false +analysis.vars=true +analysis.vinfun=true +analysis.vinfunrange=false +asm.analysis=false +asm.arch=x86 +asm.bb.line=false +asm.bb.middle=true +asm.bits=64 +asm.bytes=false +asm.bytes.right=false +asm.bytes.space=false +asm.calls=true +asm.capitalize=false +asm.cmt.col=71 +asm.cmt.esil=false +asm.cmt.flgrefs=true +asm.cmt.il=false +asm.cmt.off=nodup +asm.cmt.patch=false +asm.cmt.refs=false +asm.cmt.right=true +asm.comments=true +asm.cpu=generic +asm.cycles=false +asm.cyclespace=false +asm.debuginfo=false +asm.debuginfo.abspath=false +asm.debuginfo.file=true +asm.debuginfo.lines=true +asm.decode=false +asm.decoff=false +asm.demangle=true +asm.describe=false +asm.emu=false +asm.esil=false +asm.family=false +asm.fcn.signature=true +asm.fcn.size=false +asm.flags=true +asm.flags.inbytes=false +asm.flags.inline=false +asm.flags.limit=0 +asm.flags.maxname=0 +asm.flags.middle=2 +asm.flags.offset=false +asm.flags.real=false +asm.functions=true +asm.hint.call=true +asm.hint.call.indirect=true +asm.hint.cdiv=false +asm.hint.emu=false +asm.hint.jmp=false +asm.hint.lea=false +asm.hint.pos=1 +asm.hints=true +asm.imm.hash=0 +asm.imm.str=true +asm.imm.trim=false +asm.indent=false +asm.indentspace=2 +asm.instr=true +asm.invhex=false +asm.lbytes=true +asm.lines=true +asm.lines.bb=true +asm.lines.call=false +asm.lines.fcn=true +asm.lines.maxref=0 +asm.lines.out=true +asm.lines.ret=false +asm.lines.right=false +asm.lines.wide=false +asm.lines.width=7 +asm.marks=true +asm.meta=true +asm.midcursor=false +asm.middle=false +asm.minicols=false +asm.nbytes=6 +asm.nodup=false +asm.noisy=true +asm.offset=true +asm.optype=false +asm.os=linux +asm.parser=x86.pseudo +asm.payloads=false +asm.pcalign=0 +asm.pseudo=false +asm.refptr=true +asm.reloff=false +asm.reloff.flags=false +asm.section=false +asm.section.col=30 +asm.section.name=true +asm.section.perm=false +asm.seggrn=4 +asm.segoff=false +asm.size=false +asm.slow=true +asm.stackptr=false +asm.sub.jmp=true +asm.sub.names=true +asm.sub.reg=false +asm.sub.rel=true +asm.sub.section=false +asm.sub.tail=false +asm.sub.var=true +asm.sub.varmin=256 +asm.sub.varonly=true +asm.symbol=false +asm.symbol.col=40 +asm.syntax=intel +asm.tabs=6 +asm.tabs.off=0 +asm.tabs.once=true +asm.trace=false +asm.tracespace=false +asm.types=1 +asm.ucase=false +asm.usercomments=false +asm.var=true +asm.var.access=false +asm.var.fold=none +asm.var.summary=0 +asm.xrefs=true +asm.xrefs.code=true +asm.xrefs.fold=5 +asm.xrefs.max=20 +basefind.alignment=0x00001000 +basefind.max.threads=0 +basefind.min.score=1 +basefind.min.string=10 +basefind.progress=false +basefind.search.end=0xf0000000 +basefind.search.start=0 +bin.at=false +bin.b64str=false +bin.baddr=0 +bin.classes=true +bin.dbginfo=true +bin.dbginfo.debug_file_directory=/usr/lib/debug +bin.dbginfo.debuginfod=false +bin.dbginfo.debuginfod_urls=http://debuginfod.elfutils.org/ +bin.debase64=false +bin.demangle=true +bin.demangle.flags=base +bin.demangle.libs=false +bin.filter=true +bin.hashes.default=md5,sha1,sha256,crc32,entropy +bin.hashlimit=10M +bin.laddr=0 +bin.lang=c +bin.libs=false +bin.relocs=true +bin.strings=true +bin.usextr=true +bin.verbose=false +cfg.bigendian=false +cfg.cpuaffinity=0 +cfg.debug=false +cfg.editor=/usr/bin/nano +cfg.fortunes=true +cfg.fortunes.clippy=false +cfg.fortunes.file=tips +cfg.plugins=true +cfg.prefixdump=dump +cfg.seek.histsize=63 +cfg.seek.silent=false +cfg.user=pid426538 +cfg.wseek=false +cmd.depth=10 +cmd.hitinfo=1 +cmd.repeat=false +dbg.aftersyscall=true +dbg.backend=native +dbg.bep=loader +dbg.bpinmaps=true +dbg.bpsysign=false +dbg.btalgo=fuzzy +dbg.btdepth=128 +dbg.clone=false +dbg.consbreak=false +dbg.create_new_console=true +dbg.execs=false +dbg.exitkills=true +dbg.follow=32 +dbg.follow.child=false +dbg.forks=false +dbg.funcarg=false +dbg.gdb.page_size=0x00001000 +dbg.gdb.retries=10 +dbg.glibc.fastbinmax=10 +dbg.glibc.fc_offset=640 +dbg.glibc.ma_offset=0 +dbg.glibc.tcache=true +dbg.hwbp=false +dbg.malloc=glibc +dbg.rebase=true +dbg.skipover=false +dbg.slow=false +dbg.status=false +dbg.swstep=false +dbg.threads=false +dbg.trace=false +dbg.trace.inrange=false +dbg.trace.libs=true +dbg.trace.tag=0 +dbg.trace_continue=true +dbg.verbose=false +diff.bare=false +diff.from=0 +diff.sort=addr +diff.to=0 +dir.depth=10 +dir.home=/home/user +dir.magic=/usr/local/share/rizin/magic +dir.plugins=/usr/local/lib64/rizin/plugins +dir.prefix=/usr/local +dir.projects=/home/user/.local/share/rizin/projects +dir.types=/usr/include +elf.checks.sections=true +elf.checks.segments=true +elf.load.sections=true +emu.lazy=false +emu.pre=false +emu.skip=ds +emu.ssa=false +emu.stack=false +emu.str=false +emu.str.flag=true +emu.str.inv=true +emu.str.lea=true +emu.str.off=false +emu.write=false +esil.addr.size=64 +esil.breakoninvalid=false +esil.exectrap=false +esil.gotolimit=0x00001000 +esil.iotrap=true +esil.nonull=false +esil.prestep=true +esil.romem=false +esil.stack.addr=0x00100000 +esil.stack.depth=256 +esil.stack.pattern=0 +esil.stack.size=0x000f0000 +esil.stats=false +esil.timeout=0 +esil.verbose=0 +file.info=true +file.lastpath=/usr/bin/ls +file.loadalign=0x00000400 +file.openmany=1 +file.path=/usr/bin/ls +file.type=elf +flirt.ignore.unknown=true +flirt.node.optimize=2 +flirt.sig.deflate=false +flirt.sig.file=all +flirt.sig.library=Built with rizin 0.8.0 +flirt.sig.os=all +flirt.sig.version=10 +flirt.sigdb.load.extra=true +flirt.sigdb.load.home=true +flirt.sigdb.load.system=true +graph.aeab=false +graph.body=true +graph.bytes=false +graph.cmtright=false +graph.comments=true +graph.dotted=false +graph.dummy=true +graph.edges=2 +graph.few=false +graph.font=Courier +graph.from=0xffffffffffffffff +graph.gv.current=false +graph.gv.format=gif +graph.hints=true +graph.invscroll=false +graph.json.usenames=true +graph.layout=0 +graph.linemode=1 +graph.nodejmps=true +graph.ntitles=true +graph.offset=false +graph.refs=false +graph.scroll=5 +graph.to=0xffffffffffffffff +graph.trace=false +hex.align=false +hex.ascii=true +hex.bytes=true +hex.cols=16 +hex.comments=true +hex.compact=false +hex.depth=5 +hex.flagsz=0 +hex.hdroff=false +hex.header=true +hex.offset=true +hex.onechar=false +hex.pairs=true +hex.section=false +hex.stride=0 +hex.style=false +http.auth=false +http.bind=localhost +http.browser=xdg-open +http.colon=false +http.cors=false +http.dirlist=false +http.homeroot=/home/user/.local/share/rizin/www +http.index=index.html +http.log=true +http.maxsize=0 +http.port=9090 +http.root=/usr/local/share/rizin/www +http.stop.after=0 +http.timeout=3 +http.upget=false +http.upload=false +http.uproot=/tmp +http.verbose=false +io.0xff=255 +io.aslr=false +io.autofd=true +io.cache=false +io.cache.auto=false +io.cache.read=false +io.cache.write=false +io.exec=true +io.ff=true +io.pava=false +io.pcache=false +io.pcache.read=false +io.pcache.write=false +io.unalloc=false +io.unalloc.ch=. +io.va=true +log.abortlevel=5 +log.colors=false +log.events=false +log.level=3 +log.show.sources=false +magic.depth=100 +pdb.autoload=0 +pdb.extract=1 +pdb.server=https://msdl.microsoft.com/download/symbols +pdb.symstore=/home/user/.local/share/rizin/pdb +prj.compress=false +prj.file=v18-str-config.rzdb +rap.loop=true +rop.cache=false +rop.comments=false +rop.conditional=false +rop.len=5 +rop.subchains=false +rzil.step.events.read=false +rzil.step.events.write=true +scr.bgfill=false +scr.breaklines=false +scr.color=3 +scr.color.args=true +scr.color.bytes=true +scr.color.grep=false +scr.color.ops=true +scr.color.pipe=false +scr.columns=0 +scr.confirmquit=false +scr.dumpcols=false +scr.echo=false +scr.feedback=1 +scr.fgets=false +scr.fix.columns=0 +scr.fix.rows=0 +scr.flush=false +scr.gadgets=true +scr.highlight.grep=false +scr.hist.block=true +scr.histsave=true +scr.html=false +scr.interactive=true +scr.last=true +scr.linesleep=0 +scr.maxtab=0x00001000 +scr.nkey=flag +scr.null=false +scr.pagesize=1 +scr.panelborder=false +scr.prompt=true +scr.prompt.file=false +scr.prompt.flag=false +scr.prompt.flag.only=false +scr.prompt.mode=false +scr.prompt.popup=false +scr.prompt.sect=false +scr.prompt.vi=false +scr.randpal=false +scr.responsive=false +scr.rows=0 +scr.scrollbar=0 +scr.slow=true +scr.square=true +scr.strconv=asciiesc +scr.utf8=true +scr.utf8.curvy=false +scr.visual.mode=0 +scr.wheel=true +scr.wheel.nkey=false +scr.wheel.speed=4 +scr.wideoff=false +search.align=0 +search.case_sensitive=smart +search.chunk=0 +search.contiguous=true +search.distance=0 +search.esilcombo=8 +search.flags=true +search.from=0 +search.in=io.maps +search.kwidx=0 +search.maxhits=0 +search.overlap=false +search.prefix=hit +search.show=true +search.to=0xffffffffffffffff +stack.anotated=false +stack.bytes=true +stack.delta=0 +stack.reg=SP +stack.size=64 +str.escbslash=false +str.search.buffer_size=5 +str.search.check_ascii_freq=false +str.search.encoding=utf32be +str.search.max_region_size=0x005555555 +str.search.max_threads=5 +str.search.max_uni_blocks=5 +str.search.min_length=5 +str.search.mode=auto +str.search.raw_alignment=55 +str.search.reload=true +tcp.islocal=false +time.fmt=%Y-%m-%d %H:%M:%S %z +time.zone=0 +zoom.byte=h +zoom.from=0 +zoom.in=io.map +zoom.maxsz=512 +zoom.to=0 + +/core/debug + +/core/debug/breakpoints + +/core/file +absolute=/usr/bin/ls +raw=/bin/ls +relative=../../../../usr/bin/ls + +/core/flags +realnames=0 + +/core/flags/flags +entry.fini0={"realname":"entry.fini0","demangled":false,"offset":24464,"size":1,"space":"symbols"} +entry.init0={"realname":"entry.init0","demangled":false,"offset":24528,"size":1,"space":"symbols"} +entry0={"realname":"entry0","demangled":false,"offset":24304,"size":1,"space":"symbols"} +main={"realname":"main","demangled":false,"offset":16000,"size":256,"space":"symbols"} +obj.obstack_alloc_failed_handler={"realname":"obstack_alloc_failed_handler","demangled":false,"offset":143520,"size":8,"space":"symbols"} +reloc._ITM_deregisterTMCloneTable={"realname":"_ITM_deregisterTMCloneTable","demangled":false,"offset":143240,"size":8,"space":"relocs"} +reloc._ITM_registerTMCloneTable={"realname":"_ITM_registerTMCloneTable","demangled":false,"offset":143304,"size":8,"space":"relocs"} +reloc.__assert_fail={"realname":"__assert_fail","demangled":false,"offset":142696,"size":8,"space":"relocs"} +reloc.__ctype_b_loc={"realname":"__ctype_b_loc","demangled":false,"offset":143208,"size":8,"space":"relocs"} +reloc.__ctype_get_mb_cur_max={"realname":"__ctype_get_mb_cur_max","demangled":false,"offset":142592,"size":8,"space":"relocs"} +reloc.__ctype_tolower_loc={"realname":"__ctype_tolower_loc","demangled":false,"offset":143200,"size":8,"space":"relocs"} +reloc.__ctype_toupper_loc={"realname":"__ctype_toupper_loc","demangled":false,"offset":142336,"size":8,"space":"relocs"} +reloc.__cxa_atexit={"realname":"__cxa_atexit","demangled":false,"offset":143080,"size":8,"space":"relocs"} +reloc.__cxa_finalize={"realname":"__cxa_finalize","demangled":false,"offset":143184,"size":8,"space":"relocs"} +reloc.__cxa_finalize.22fd8={"realname":"__cxa_finalize","demangled":false,"offset":143320,"size":8,"space":"relocs"} +reloc.__errno_location={"realname":"__errno_location","demangled":false,"offset":142408,"size":8,"space":"relocs"} +reloc.__fpending={"realname":"__fpending","demangled":false,"offset":142448,"size":8,"space":"relocs"} +reloc.__fprintf_chk={"realname":"__fprintf_chk","demangled":false,"offset":143136,"size":8,"space":"relocs"} +reloc.__freading={"realname":"__freading","demangled":false,"offset":142952,"size":8,"space":"relocs"} +reloc.__gmon_start={"realname":"__gmon_start__","demangled":false,"offset":143280,"size":8,"space":"relocs"} +reloc.__isoc23_strtoumax={"realname":"__isoc23_strtoumax","demangled":false,"offset":142864,"size":8,"space":"relocs"} +reloc.__libc_start_main={"realname":"__libc_start_main","demangled":false,"offset":143232,"size":8,"space":"relocs"} +reloc.__mbstowcs_chk={"realname":"__mbstowcs_chk","demangled":false,"offset":142440,"size":8,"space":"relocs"} +reloc.__memcpy_chk={"realname":"__memcpy_chk","demangled":false,"offset":142832,"size":8,"space":"relocs"} +reloc.__mempcpy_chk={"realname":"__mempcpy_chk","demangled":false,"offset":142392,"size":8,"space":"relocs"} +reloc.__overflow={"realname":"__overflow","demangled":false,"offset":142664,"size":8,"space":"relocs"} +reloc.__printf_chk={"realname":"__printf_chk","demangled":false,"offset":142992,"size":8,"space":"relocs"} +reloc.__readlink_chk={"realname":"__readlink_chk","demangled":false,"offset":142800,"size":8,"space":"relocs"} +reloc.__snprintf_chk={"realname":"__snprintf_chk","demangled":false,"offset":142368,"size":8,"space":"relocs"} +reloc.__sprintf_chk={"realname":"__sprintf_chk","demangled":false,"offset":143216,"size":8,"space":"relocs"} +reloc.__stack_chk_fail={"realname":"__stack_chk_fail","demangled":false,"offset":142608,"size":8,"space":"relocs"} +reloc.__strcpy_chk={"realname":"__strcpy_chk","demangled":false,"offset":142976,"size":8,"space":"relocs"} +reloc._exit={"realname":"_exit","demangled":false,"offset":142432,"size":8,"space":"relocs"} +reloc._setjmp={"realname":"_setjmp","demangled":false,"offset":142760,"size":8,"space":"relocs"} +reloc.abort={"realname":"abort","demangled":false,"offset":142400,"size":8,"space":"relocs"} +reloc.bindtextdomain={"realname":"bindtextdomain","demangled":false,"offset":142568,"size":8,"space":"relocs"} +reloc.calloc={"realname":"calloc","demangled":false,"offset":142784,"size":8,"space":"relocs"} +reloc.cap_free={"realname":"cap_free","demangled":false,"offset":143072,"size":8,"space":"relocs"} +reloc.cap_get_file={"realname":"cap_get_file","demangled":false,"offset":143056,"size":8,"space":"relocs"} +reloc.cap_to_text={"realname":"cap_to_text","demangled":false,"offset":142352,"size":8,"space":"relocs"} +reloc.clock_gettime={"realname":"clock_gettime","demangled":false,"offset":142520,"size":8,"space":"relocs"} +reloc.closedir={"realname":"closedir","demangled":false,"offset":142744,"size":8,"space":"relocs"} +reloc.dcgettext={"realname":"dcgettext","demangled":false,"offset":142584,"size":8,"space":"relocs"} +reloc.dirfd={"realname":"dirfd","demangled":false,"offset":142816,"size":8,"space":"relocs"} +reloc.error={"realname":"error","demangled":false,"offset":143040,"size":8,"space":"relocs"} +reloc.exit={"realname":"exit","demangled":false,"offset":143120,"size":8,"space":"relocs"} +reloc.fclose={"realname":"fclose","demangled":false,"offset":142544,"size":8,"space":"relocs"} +reloc.fflush={"realname":"fflush","demangled":false,"offset":142920,"size":8,"space":"relocs"} +reloc.fflush_unlocked={"realname":"fflush_unlocked","demangled":false,"offset":143152,"size":8,"space":"relocs"} +reloc.fileno={"realname":"fileno","demangled":false,"offset":142880,"size":8,"space":"relocs"} +reloc.fnmatch={"realname":"fnmatch","demangled":false,"offset":142704,"size":8,"space":"relocs"} +reloc.fputc_unlocked={"realname":"fputc_unlocked","demangled":false,"offset":142824,"size":8,"space":"relocs"} +reloc.fputs_unlocked={"realname":"fputs_unlocked","demangled":false,"offset":142768,"size":8,"space":"relocs"} +reloc.free={"realname":"free","demangled":false,"offset":142384,"size":8,"space":"relocs"} +reloc.free.22f78={"realname":"free","demangled":false,"offset":143224,"size":8,"space":"relocs"} +reloc.freecon={"realname":"freecon","demangled":false,"offset":142632,"size":8,"space":"relocs"} +reloc.fseeko={"realname":"fseeko","demangled":false,"offset":143048,"size":8,"space":"relocs"} +reloc.fwrite={"realname":"fwrite","demangled":false,"offset":143128,"size":8,"space":"relocs"} +reloc.fwrite_unlocked={"realname":"fwrite_unlocked","demangled":false,"offset":142960,"size":8,"space":"relocs"} +reloc.getcwd={"realname":"getcwd","demangled":false,"offset":142728,"size":8,"space":"relocs"} +reloc.getenv={"realname":"getenv","demangled":false,"offset":142344,"size":8,"space":"relocs"} +reloc.getfilecon={"realname":"getfilecon","demangled":false,"offset":143144,"size":8,"space":"relocs"} +reloc.getgrgid={"realname":"getgrgid","demangled":false,"offset":142648,"size":8,"space":"relocs"} +reloc.gethostname={"realname":"gethostname","demangled":false,"offset":143104,"size":8,"space":"relocs"} +reloc.getopt_long={"realname":"getopt_long","demangled":false,"offset":142616,"size":8,"space":"relocs"} +reloc.getpwuid={"realname":"getpwuid","demangled":false,"offset":142560,"size":8,"space":"relocs"} +reloc.getxattr={"realname":"getxattr","demangled":false,"offset":143096,"size":8,"space":"relocs"} +reloc.gmtime_r={"realname":"gmtime_r","demangled":false,"offset":142680,"size":8,"space":"relocs"} +reloc.ioctl={"realname":"ioctl","demangled":false,"offset":142720,"size":8,"space":"relocs"} +reloc.isatty={"realname":"isatty","demangled":false,"offset":142456,"size":8,"space":"relocs"} +reloc.iswcntrl={"realname":"iswcntrl","demangled":false,"offset":142472,"size":8,"space":"relocs"} +reloc.iswprint={"realname":"iswprint","demangled":false,"offset":143176,"size":8,"space":"relocs"} +reloc.lgetfilecon={"realname":"lgetfilecon","demangled":false,"offset":143168,"size":8,"space":"relocs"} +reloc.listxattr={"realname":"listxattr","demangled":false,"offset":142576,"size":8,"space":"relocs"} +reloc.localeconv={"realname":"localeconv","demangled":false,"offset":142496,"size":8,"space":"relocs"} +reloc.localtime_r={"realname":"localtime_r","demangled":false,"offset":142424,"size":8,"space":"relocs"} +reloc.lseek={"realname":"lseek","demangled":false,"offset":142688,"size":8,"space":"relocs"} +reloc.malloc={"realname":"malloc","demangled":false,"offset":142912,"size":8,"space":"relocs"} +reloc.malloc.22fc0={"realname":"malloc","demangled":false,"offset":143296,"size":8,"space":"relocs"} +reloc.mbrtoc32={"realname":"mbrtoc32","demangled":false,"offset":142736,"size":8,"space":"relocs"} +reloc.mbrtowc={"realname":"mbrtowc","demangled":false,"offset":142624,"size":8,"space":"relocs"} +reloc.mbsinit={"realname":"mbsinit","demangled":false,"offset":143160,"size":8,"space":"relocs"} +reloc.mbstowcs={"realname":"mbstowcs","demangled":false,"offset":142504,"size":8,"space":"relocs"} +reloc.memcmp={"realname":"memcmp","demangled":false,"offset":142752,"size":8,"space":"relocs"} +reloc.memcpy={"realname":"memcpy","demangled":false,"offset":142856,"size":8,"space":"relocs"} +reloc.memmove={"realname":"memmove","demangled":false,"offset":143032,"size":8,"space":"relocs"} +reloc.mempcpy={"realname":"mempcpy","demangled":false,"offset":143024,"size":8,"space":"relocs"} +reloc.memset={"realname":"memset","demangled":false,"offset":142712,"size":8,"space":"relocs"} +reloc.mktime={"realname":"mktime","demangled":false,"offset":142944,"size":8,"space":"relocs"} +reloc.nl_langinfo={"realname":"nl_langinfo","demangled":false,"offset":142928,"size":8,"space":"relocs"} +reloc.opendir={"realname":"opendir","demangled":false,"offset":142552,"size":8,"space":"relocs"} +reloc.optarg={"realname":"optarg","demangled":false,"offset":143272,"size":8,"space":"relocs"} +reloc.optind={"realname":"optind","demangled":false,"offset":143256,"size":8,"space":"relocs"} +reloc.program_invocation_name={"realname":"program_invocation_name","demangled":false,"offset":143288,"size":8,"space":"relocs"} +reloc.program_invocation_short_name={"realname":"program_invocation_short_name","demangled":false,"offset":143312,"size":8,"space":"relocs"} +reloc.raise={"realname":"raise","demangled":false,"offset":142376,"size":8,"space":"relocs"} +reloc.rawmemchr={"realname":"rawmemchr","demangled":false,"offset":142776,"size":8,"space":"relocs"} +reloc.readdir={"realname":"readdir","demangled":false,"offset":142896,"size":8,"space":"relocs"} +reloc.readlink={"realname":"readlink","demangled":false,"offset":142512,"size":8,"space":"relocs"} +reloc.realloc={"realname":"realloc","demangled":false,"offset":142968,"size":8,"space":"relocs"} +reloc.reallocarray={"realname":"reallocarray","demangled":false,"offset":142480,"size":8,"space":"relocs"} +reloc.setenv={"realname":"setenv","demangled":false,"offset":142528,"size":8,"space":"relocs"} +reloc.setlocale={"realname":"setlocale","demangled":false,"offset":142984,"size":8,"space":"relocs"} +reloc.sigaction={"realname":"sigaction","demangled":false,"offset":142464,"size":8,"space":"relocs"} +reloc.sigaddset={"realname":"sigaddset","demangled":false,"offset":143192,"size":8,"space":"relocs"} +reloc.sigemptyset={"realname":"sigemptyset","demangled":false,"offset":142840,"size":8,"space":"relocs"} +reloc.sigismember={"realname":"sigismember","demangled":false,"offset":143112,"size":8,"space":"relocs"} +reloc.signal={"realname":"signal","demangled":false,"offset":142808,"size":8,"space":"relocs"} +reloc.sigprocmask={"realname":"sigprocmask","demangled":false,"offset":142360,"size":8,"space":"relocs"} +reloc.snprintf={"realname":"snprintf","demangled":false,"offset":142656,"size":8,"space":"relocs"} +reloc.stat={"realname":"stat","demangled":false,"offset":142848,"size":8,"space":"relocs"} +reloc.statx={"realname":"statx","demangled":false,"offset":143000,"size":8,"space":"relocs"} +reloc.stderr={"realname":"stderr","demangled":false,"offset":143328,"size":8,"space":"relocs"} +reloc.stdout={"realname":"stdout","demangled":false,"offset":143248,"size":8,"space":"relocs"} +reloc.strchr={"realname":"strchr","demangled":false,"offset":142640,"size":8,"space":"relocs"} +reloc.strcmp={"realname":"strcmp","demangled":false,"offset":142792,"size":8,"space":"relocs"} +reloc.strcmp.22fa0={"realname":"strcmp","demangled":false,"offset":143264,"size":8,"space":"relocs"} +reloc.strcoll={"realname":"strcoll","demangled":false,"offset":142936,"size":8,"space":"relocs"} +reloc.strftime={"realname":"strftime","demangled":false,"offset":143016,"size":8,"space":"relocs"} +reloc.strlen={"realname":"strlen","demangled":false,"offset":142600,"size":8,"space":"relocs"} +reloc.strncmp={"realname":"strncmp","demangled":false,"offset":142416,"size":8,"space":"relocs"} +reloc.strrchr={"realname":"strrchr","demangled":false,"offset":142672,"size":8,"space":"relocs"} +reloc.target._ITM_deregisterTMCloneTable={"realname":"_ITM_deregisterTMCloneTable","demangled":false,"offset":149672,"size":8,"space":"relocs"} +reloc.target._ITM_registerTMCloneTable={"realname":"_ITM_registerTMCloneTable","demangled":false,"offset":149720,"size":8,"space":"relocs"} +reloc.target.__assert_fail={"realname":"__assert_fail","demangled":false,"offset":149136,"size":8,"space":"relocs"} +reloc.target.__ctype_b_loc={"realname":"__ctype_b_loc","demangled":false,"offset":149648,"size":8,"space":"relocs"} +reloc.target.__ctype_get_mb_cur_max={"realname":"__ctype_get_mb_cur_max","demangled":false,"offset":149032,"size":8,"space":"relocs"} +reloc.target.__ctype_tolower_loc={"realname":"__ctype_tolower_loc","demangled":false,"offset":149640,"size":8,"space":"relocs"} +reloc.target.__ctype_toupper_loc={"realname":"__ctype_toupper_loc","demangled":false,"offset":148776,"size":8,"space":"relocs"} +reloc.target.__cxa_atexit={"realname":"__cxa_atexit","demangled":false,"offset":149520,"size":8,"space":"relocs"} +reloc.target.__cxa_finalize={"realname":"__cxa_finalize","demangled":false,"offset":149624,"size":8,"space":"relocs"} +reloc.target.__errno_location={"realname":"__errno_location","demangled":false,"offset":148848,"size":8,"space":"relocs"} +reloc.target.__fpending={"realname":"__fpending","demangled":false,"offset":148888,"size":8,"space":"relocs"} +reloc.target.__fprintf_chk={"realname":"__fprintf_chk","demangled":false,"offset":149576,"size":8,"space":"relocs"} +reloc.target.__freading={"realname":"__freading","demangled":false,"offset":149392,"size":8,"space":"relocs"} +reloc.target.__gmon_start={"realname":"__gmon_start__","demangled":false,"offset":149704,"size":8,"space":"relocs"} +reloc.target.__isoc23_strtoumax={"realname":"__isoc23_strtoumax","demangled":false,"offset":149304,"size":8,"space":"relocs"} +reloc.target.__libc_start_main={"realname":"__libc_start_main","demangled":false,"offset":149664,"size":8,"space":"relocs"} +reloc.target.__mbstowcs_chk={"realname":"__mbstowcs_chk","demangled":false,"offset":148880,"size":8,"space":"relocs"} +reloc.target.__memcpy_chk={"realname":"__memcpy_chk","demangled":false,"offset":149272,"size":8,"space":"relocs"} +reloc.target.__mempcpy_chk={"realname":"__mempcpy_chk","demangled":false,"offset":148832,"size":8,"space":"relocs"} +reloc.target.__overflow={"realname":"__overflow","demangled":false,"offset":149104,"size":8,"space":"relocs"} +reloc.target.__printf_chk={"realname":"__printf_chk","demangled":false,"offset":149432,"size":8,"space":"relocs"} +reloc.target.__readlink_chk={"realname":"__readlink_chk","demangled":false,"offset":149240,"size":8,"space":"relocs"} +reloc.target.__snprintf_chk={"realname":"__snprintf_chk","demangled":false,"offset":148808,"size":8,"space":"relocs"} +reloc.target.__sprintf_chk={"realname":"__sprintf_chk","demangled":false,"offset":149656,"size":8,"space":"relocs"} +reloc.target.__stack_chk_fail={"realname":"__stack_chk_fail","demangled":false,"offset":149048,"size":8,"space":"relocs"} +reloc.target.__strcpy_chk={"realname":"__strcpy_chk","demangled":false,"offset":149416,"size":8,"space":"relocs"} +reloc.target._exit={"realname":"_exit","demangled":false,"offset":148872,"size":8,"space":"relocs"} +reloc.target._setjmp={"realname":"_setjmp","demangled":false,"offset":149200,"size":8,"space":"relocs"} +reloc.target.abort={"realname":"abort","demangled":false,"offset":148840,"size":8,"space":"relocs"} +reloc.target.bindtextdomain={"realname":"bindtextdomain","demangled":false,"offset":149008,"size":8,"space":"relocs"} +reloc.target.calloc={"realname":"calloc","demangled":false,"offset":149224,"size":8,"space":"relocs"} +reloc.target.cap_free={"realname":"cap_free","demangled":false,"offset":149512,"size":8,"space":"relocs"} +reloc.target.cap_get_file={"realname":"cap_get_file","demangled":false,"offset":149496,"size":8,"space":"relocs"} +reloc.target.cap_to_text={"realname":"cap_to_text","demangled":false,"offset":148792,"size":8,"space":"relocs"} +reloc.target.clock_gettime={"realname":"clock_gettime","demangled":false,"offset":148960,"size":8,"space":"relocs"} +reloc.target.closedir={"realname":"closedir","demangled":false,"offset":149184,"size":8,"space":"relocs"} +reloc.target.dcgettext={"realname":"dcgettext","demangled":false,"offset":149024,"size":8,"space":"relocs"} +reloc.target.dirfd={"realname":"dirfd","demangled":false,"offset":149256,"size":8,"space":"relocs"} +reloc.target.error={"realname":"error","demangled":false,"offset":149480,"size":8,"space":"relocs"} +reloc.target.exit={"realname":"exit","demangled":false,"offset":149560,"size":8,"space":"relocs"} +reloc.target.fclose={"realname":"fclose","demangled":false,"offset":148984,"size":8,"space":"relocs"} +reloc.target.fflush={"realname":"fflush","demangled":false,"offset":149360,"size":8,"space":"relocs"} +reloc.target.fflush_unlocked={"realname":"fflush_unlocked","demangled":false,"offset":149592,"size":8,"space":"relocs"} +reloc.target.fileno={"realname":"fileno","demangled":false,"offset":149320,"size":8,"space":"relocs"} +reloc.target.fnmatch={"realname":"fnmatch","demangled":false,"offset":149144,"size":8,"space":"relocs"} +reloc.target.fputc_unlocked={"realname":"fputc_unlocked","demangled":false,"offset":149264,"size":8,"space":"relocs"} +reloc.target.fputs_unlocked={"realname":"fputs_unlocked","demangled":false,"offset":149208,"size":8,"space":"relocs"} +reloc.target.free={"realname":"free","demangled":false,"offset":148824,"size":8,"space":"relocs"} +reloc.target.freecon={"realname":"freecon","demangled":false,"offset":149072,"size":8,"space":"relocs"} +reloc.target.fseeko={"realname":"fseeko","demangled":false,"offset":149488,"size":8,"space":"relocs"} +reloc.target.fwrite={"realname":"fwrite","demangled":false,"offset":149568,"size":8,"space":"relocs"} +reloc.target.fwrite_unlocked={"realname":"fwrite_unlocked","demangled":false,"offset":149400,"size":8,"space":"relocs"} +reloc.target.getcwd={"realname":"getcwd","demangled":false,"offset":149168,"size":8,"space":"relocs"} +reloc.target.getenv={"realname":"getenv","demangled":false,"offset":148784,"size":8,"space":"relocs"} +reloc.target.getfilecon={"realname":"getfilecon","demangled":false,"offset":149584,"size":8,"space":"relocs"} +reloc.target.getgrgid={"realname":"getgrgid","demangled":false,"offset":149088,"size":8,"space":"relocs"} +reloc.target.gethostname={"realname":"gethostname","demangled":false,"offset":149544,"size":8,"space":"relocs"} +reloc.target.getopt_long={"realname":"getopt_long","demangled":false,"offset":149056,"size":8,"space":"relocs"} +reloc.target.getpwuid={"realname":"getpwuid","demangled":false,"offset":149000,"size":8,"space":"relocs"} +reloc.target.getxattr={"realname":"getxattr","demangled":false,"offset":149536,"size":8,"space":"relocs"} +reloc.target.gmtime_r={"realname":"gmtime_r","demangled":false,"offset":149120,"size":8,"space":"relocs"} +reloc.target.ioctl={"realname":"ioctl","demangled":false,"offset":149160,"size":8,"space":"relocs"} +reloc.target.isatty={"realname":"isatty","demangled":false,"offset":148896,"size":8,"space":"relocs"} +reloc.target.iswcntrl={"realname":"iswcntrl","demangled":false,"offset":148912,"size":8,"space":"relocs"} +reloc.target.iswprint={"realname":"iswprint","demangled":false,"offset":149616,"size":8,"space":"relocs"} +reloc.target.lgetfilecon={"realname":"lgetfilecon","demangled":false,"offset":149608,"size":8,"space":"relocs"} +reloc.target.listxattr={"realname":"listxattr","demangled":false,"offset":149016,"size":8,"space":"relocs"} +reloc.target.localeconv={"realname":"localeconv","demangled":false,"offset":148936,"size":8,"space":"relocs"} +reloc.target.localtime_r={"realname":"localtime_r","demangled":false,"offset":148864,"size":8,"space":"relocs"} +reloc.target.lseek={"realname":"lseek","demangled":false,"offset":149128,"size":8,"space":"relocs"} +reloc.target.malloc={"realname":"malloc","demangled":false,"offset":149352,"size":8,"space":"relocs"} +reloc.target.mbrtoc32={"realname":"mbrtoc32","demangled":false,"offset":149176,"size":8,"space":"relocs"} +reloc.target.mbrtowc={"realname":"mbrtowc","demangled":false,"offset":149064,"size":8,"space":"relocs"} +reloc.target.mbsinit={"realname":"mbsinit","demangled":false,"offset":149600,"size":8,"space":"relocs"} +reloc.target.mbstowcs={"realname":"mbstowcs","demangled":false,"offset":148944,"size":8,"space":"relocs"} +reloc.target.memcmp={"realname":"memcmp","demangled":false,"offset":149192,"size":8,"space":"relocs"} +reloc.target.memcpy={"realname":"memcpy","demangled":false,"offset":149296,"size":8,"space":"relocs"} +reloc.target.memmove={"realname":"memmove","demangled":false,"offset":149472,"size":8,"space":"relocs"} +reloc.target.mempcpy={"realname":"mempcpy","demangled":false,"offset":149464,"size":8,"space":"relocs"} +reloc.target.memset={"realname":"memset","demangled":false,"offset":149152,"size":8,"space":"relocs"} +reloc.target.mktime={"realname":"mktime","demangled":false,"offset":149384,"size":8,"space":"relocs"} +reloc.target.nl_langinfo={"realname":"nl_langinfo","demangled":false,"offset":149368,"size":8,"space":"relocs"} +reloc.target.opendir={"realname":"opendir","demangled":false,"offset":148992,"size":8,"space":"relocs"} +reloc.target.optarg={"realname":"optarg","demangled":false,"offset":149696,"size":8,"space":"relocs"} +reloc.target.optind={"realname":"optind","demangled":false,"offset":149688,"size":8,"space":"relocs"} +reloc.target.program_invocation_name={"realname":"program_invocation_name","demangled":false,"offset":149712,"size":8,"space":"relocs"} +reloc.target.program_invocation_short_name={"realname":"program_invocation_short_name","demangled":false,"offset":149728,"size":8,"space":"relocs"} +reloc.target.raise={"realname":"raise","demangled":false,"offset":148816,"size":8,"space":"relocs"} +reloc.target.rawmemchr={"realname":"rawmemchr","demangled":false,"offset":149216,"size":8,"space":"relocs"} +reloc.target.readdir={"realname":"readdir","demangled":false,"offset":149336,"size":8,"space":"relocs"} +reloc.target.readlink={"realname":"readlink","demangled":false,"offset":148952,"size":8,"space":"relocs"} +reloc.target.realloc={"realname":"realloc","demangled":false,"offset":149408,"size":8,"space":"relocs"} +reloc.target.reallocarray={"realname":"reallocarray","demangled":false,"offset":148920,"size":8,"space":"relocs"} +reloc.target.setenv={"realname":"setenv","demangled":false,"offset":148968,"size":8,"space":"relocs"} +reloc.target.setlocale={"realname":"setlocale","demangled":false,"offset":149424,"size":8,"space":"relocs"} +reloc.target.sigaction={"realname":"sigaction","demangled":false,"offset":148904,"size":8,"space":"relocs"} +reloc.target.sigaddset={"realname":"sigaddset","demangled":false,"offset":149632,"size":8,"space":"relocs"} +reloc.target.sigemptyset={"realname":"sigemptyset","demangled":false,"offset":149280,"size":8,"space":"relocs"} +reloc.target.sigismember={"realname":"sigismember","demangled":false,"offset":149552,"size":8,"space":"relocs"} +reloc.target.signal={"realname":"signal","demangled":false,"offset":149248,"size":8,"space":"relocs"} +reloc.target.sigprocmask={"realname":"sigprocmask","demangled":false,"offset":148800,"size":8,"space":"relocs"} +reloc.target.snprintf={"realname":"snprintf","demangled":false,"offset":149096,"size":8,"space":"relocs"} +reloc.target.stat={"realname":"stat","demangled":false,"offset":149288,"size":8,"space":"relocs"} +reloc.target.statx={"realname":"statx","demangled":false,"offset":149440,"size":8,"space":"relocs"} +reloc.target.stderr={"realname":"stderr","demangled":false,"offset":149736,"size":8,"space":"relocs"} +reloc.target.stdout={"realname":"stdout","demangled":false,"offset":149680,"size":8,"space":"relocs"} +reloc.target.strchr={"realname":"strchr","demangled":false,"offset":149080,"size":8,"space":"relocs"} +reloc.target.strcmp={"realname":"strcmp","demangled":false,"offset":149232,"size":8,"space":"relocs"} +reloc.target.strcoll={"realname":"strcoll","demangled":false,"offset":149376,"size":8,"space":"relocs"} +reloc.target.strftime={"realname":"strftime","demangled":false,"offset":149456,"size":8,"space":"relocs"} +reloc.target.strlen={"realname":"strlen","demangled":false,"offset":149040,"size":8,"space":"relocs"} +reloc.target.strncmp={"realname":"strncmp","demangled":false,"offset":148856,"size":8,"space":"relocs"} +reloc.target.strrchr={"realname":"strrchr","demangled":false,"offset":149112,"size":8,"space":"relocs"} +reloc.target.tcgetpgrp={"realname":"tcgetpgrp","demangled":false,"offset":149328,"size":8,"space":"relocs"} +reloc.target.textdomain={"realname":"textdomain","demangled":false,"offset":148976,"size":8,"space":"relocs"} +reloc.target.timegm={"realname":"timegm","demangled":false,"offset":149448,"size":8,"space":"relocs"} +reloc.target.tzset={"realname":"tzset","demangled":false,"offset":149312,"size":8,"space":"relocs"} +reloc.target.unsetenv={"realname":"unsetenv","demangled":false,"offset":149504,"size":8,"space":"relocs"} +reloc.target.wcstombs={"realname":"wcstombs","demangled":false,"offset":149528,"size":8,"space":"relocs"} +reloc.target.wcswidth={"realname":"wcswidth","demangled":false,"offset":148928,"size":8,"space":"relocs"} +reloc.target.wcwidth={"realname":"wcwidth","demangled":false,"offset":149344,"size":8,"space":"relocs"} +reloc.tcgetpgrp={"realname":"tcgetpgrp","demangled":false,"offset":142888,"size":8,"space":"relocs"} +reloc.textdomain={"realname":"textdomain","demangled":false,"offset":142536,"size":8,"space":"relocs"} +reloc.timegm={"realname":"timegm","demangled":false,"offset":143008,"size":8,"space":"relocs"} +reloc.tzset={"realname":"tzset","demangled":false,"offset":142872,"size":8,"space":"relocs"} +reloc.unsetenv={"realname":"unsetenv","demangled":false,"offset":143064,"size":8,"space":"relocs"} +reloc.wcstombs={"realname":"wcstombs","demangled":false,"offset":143088,"size":8,"space":"relocs"} +reloc.wcswidth={"realname":"wcswidth","demangled":false,"offset":142488,"size":8,"space":"relocs"} +reloc.wcwidth={"realname":"wcwidth","demangled":false,"offset":142904,"size":8,"space":"relocs"} +section..bss={"realname":"section..bss","demangled":false,"offset":144000,"size":4768,"space":"sections"} +section..data={"realname":"section..data","demangled":false,"offset":143360,"size":632,"space":"sections"} +section..data.rel.ro={"realname":"section..data.rel.ro","demangled":false,"offset":138848,"size":2888,"space":"sections"} +section..dynamic={"realname":"section..dynamic","demangled":false,"offset":141736,"size":576,"space":"sections"} +section..dynstr={"realname":"section..dynstr","demangled":false,"offset":4320,"size":1620,"space":"sections"} +section..dynsym={"realname":"section..dynsym","demangled":false,"offset":1176,"size":3144,"space":"sections"} +section..eh_frame={"realname":"section..eh_frame","demangled":false,"offset":124720,"size":6688,"space":"sections"} +section..eh_frame_hdr={"realname":"section..eh_frame_hdr","demangled":false,"offset":123216,"size":1500,"space":"sections"} +section..fini={"realname":"section..fini","demangled":false,"offset":102244,"size":13,"space":"sections"} +section..fini_array={"realname":"section..fini_array","demangled":false,"offset":138840,"size":8,"space":"sections"} +section..gnu.hash={"realname":"section..gnu.hash","demangled":false,"offset":1112,"size":64,"space":"sections"} +section..gnu.version={"realname":"section..gnu.version","demangled":false,"offset":5940,"size":262,"space":"sections"} +section..gnu.version_r={"realname":"section..gnu.version_r","demangled":false,"offset":6208,"size":256,"space":"sections"} +section..got={"realname":"section..got","demangled":false,"offset":142312,"size":1024,"space":"sections"} +section..init={"realname":"section..init","demangled":false,"offset":12288,"size":27,"space":"sections"} +section..init_array={"realname":"section..init_array","demangled":false,"offset":138832,"size":8,"space":"sections"} +section..interp={"realname":"section..interp","demangled":false,"offset":792,"size":28,"space":"sections"} +section..note.ABI_tag={"realname":"section..note.ABI_tag","demangled":false,"offset":940,"size":32,"space":"sections"} +section..note.gnu.build_id={"realname":"section..note.gnu.build_id","demangled":false,"offset":904,"size":36,"space":"sections"} +section..note.gnu.property={"realname":"section..note.gnu.property","demangled":false,"offset":824,"size":80,"space":"sections"} +section..note.package={"realname":"section..note.package","demangled":false,"offset":972,"size":140,"space":"sections"} +section..plt={"realname":"section..plt","demangled":false,"offset":12320,"size":1792,"space":"sections"} +section..plt.sec={"realname":"section..plt.sec","demangled":false,"offset":14112,"size":1776,"space":"sections"} +section..rela.dyn={"realname":"section..rela.dyn","demangled":false,"offset":6464,"size":336,"space":"sections"} +section..rela.plt={"realname":"section..rela.plt","demangled":false,"offset":6800,"size":2664,"space":"sections"} +section..relr.dyn={"realname":"section..relr.dyn","demangled":false,"offset":9464,"size":72,"space":"sections"} +section..rodata={"realname":"section..rodata","demangled":false,"offset":102400,"size":20815,"space":"sections"} +section..text={"realname":"section..text","demangled":false,"offset":15936,"size":86306,"space":"sections"} +segment.DYNAMIC={"realname":"segment.DYNAMIC","demangled":false,"offset":141736,"size":576,"space":"segments"} +segment.GNU_EH_FRAME={"realname":"segment.GNU_EH_FRAME","demangled":false,"offset":123216,"size":1500,"space":"segments"} +segment.GNU_RELRO={"realname":"segment.GNU_RELRO","demangled":false,"offset":138832,"size":4528,"space":"segments"} +segment.GNU_STACK={"realname":"segment.GNU_STACK","demangled":false,"offset":0,"size":0,"space":"segments"} +segment.INTERP={"realname":"segment.INTERP","demangled":false,"offset":792,"size":28,"space":"segments"} +segment.LOAD0={"realname":"segment.LOAD0","demangled":false,"offset":0,"size":9536,"space":"segments"} +segment.LOAD1={"realname":"segment.LOAD1","demangled":false,"offset":12288,"size":89969,"space":"segments"} +segment.LOAD2={"realname":"segment.LOAD2","demangled":false,"offset":102400,"size":29008,"space":"segments"} +segment.LOAD3={"realname":"segment.LOAD3","demangled":false,"offset":138832,"size":9936,"space":"segments"} +segment.NOTE={"realname":"segment.NOTE","demangled":false,"offset":824,"size":80,"space":"segments"} +segment.NOTE_0x388={"realname":"segment.NOTE_0x388","demangled":false,"offset":904,"size":208,"space":"segments"} +segment.PHDR={"realname":"segment.PHDR","demangled":false,"offset":64,"size":728,"space":"segments"} +segment.UNKNOWN={"realname":"segment.UNKNOWN","demangled":false,"offset":824,"size":80,"space":"segments"} +segment.ehdr={"realname":"segment.ehdr","demangled":false,"offset":0,"size":64,"space":"segments"} +str.={"realname":"str.","demangled":false,"offset":110873,"size":6,"space":"strings"} +str..._src_ls.c={"realname":"str..._src_ls.c","demangled":false,"offset":110352,"size":12,"space":"strings"} +str..0Lf={"realname":"str..0Lf","demangled":false,"offset":110302,"size":6,"space":"strings"} +str..1Lf={"realname":"str..1Lf","demangled":false,"offset":110308,"size":6,"space":"strings"} +str..7z_01_31={"realname":"str..7z_01_31","demangled":false,"offset":108517,"size":10,"space":"strings"} +str.._s_s_s={"realname":"str.._s_s_s","demangled":false,"offset":110021,"size":9,"space":"strings"} +str..aac_00_36={"realname":"str..aac_00_36","demangled":false,"offset":109248,"size":11,"space":"strings"} +str..ace_01_31={"realname":"str..ace_01_31","demangled":false,"offset":108483,"size":11,"space":"strings"} +str..alz_01_31={"realname":"str..alz_01_31","demangled":false,"offset":108472,"size":11,"space":"strings"} +str..arc_01_31={"realname":"str..arc_01_31","demangled":false,"offset":108114,"size":11,"space":"strings"} +str..arj_01_31={"realname":"str..arj_01_31","demangled":false,"offset":108125,"size":11,"space":"strings"} +str..asf_01_35={"realname":"str..asf_01_35","demangled":false,"offset":109003,"size":11,"space":"strings"} +str..au_00_36={"realname":"str..au_00_36","demangled":false,"offset":109259,"size":10,"space":"strings"} +str..avi_01_35={"realname":"str..avi_01_35","demangled":false,"offset":109047,"size":11,"space":"strings"} +str..avif_01_35={"realname":"str..avif_01_35","demangled":false,"offset":108608,"size":12,"space":"strings"} +str..bak_00_90={"realname":"str..bak_00_90","demangled":false,"offset":109514,"size":11,"space":"strings"} +str..bat_01_32={"realname":"str..bat_01_32","demangled":false,"offset":107925,"size":12,"space":"strings"} +str..bmp_01_35={"realname":"str..bmp_01_35","demangled":false,"offset":108679,"size":11,"space":"strings"} +str..btm_01_32={"realname":"str..btm_01_32","demangled":false,"offset":107913,"size":12,"space":"strings"} +str..bz2_01_31={"realname":"str..bz2_01_31","demangled":false,"offset":108341,"size":11,"space":"strings"} +str..bz_01_31={"realname":"str..bz_01_31","demangled":false,"offset":108352,"size":10,"space":"strings"} +str..cab_01_31={"realname":"str..cab_01_31","demangled":false,"offset":108537,"size":11,"space":"strings"} +str..cgm_01_35={"realname":"str..cgm_01_35","demangled":false,"offset":109133,"size":11,"space":"strings"} +str..cmd_01_32___executables__bright_green={"realname":"str..cmd_01_32___executables__bright_green","demangled":false,"offset":107848,"size":41,"space":"strings"} +str..com_01_32={"realname":"str..com_01_32","demangled":false,"offset":107901,"size":12,"space":"strings"} +str..cpio_01_31={"realname":"str..cpio_01_31","demangled":false,"offset":108505,"size":12,"space":"strings"} +str..crdownload_00_90={"realname":"str..crdownload_00_90","demangled":false,"offset":109525,"size":18,"space":"strings"} +str..csh_01_32={"realname":"str..csh_01_32","demangled":false,"offset":108042,"size":12,"space":"strings"} +str..deb_01_31={"realname":"str..deb_01_31","demangled":false,"offset":108395,"size":11,"space":"strings"} +str..dl_01_35={"realname":"str..dl_01_35","demangled":false,"offset":109090,"size":10,"space":"strings"} +str..dpkg_dist_00_90={"realname":"str..dpkg_dist_00_90","demangled":false,"offset":109543,"size":17,"space":"strings"} +str..dpkg_new_00_90={"realname":"str..dpkg_new_00_90","demangled":false,"offset":109560,"size":16,"space":"strings"} +str..dpkg_old_00_90={"realname":"str..dpkg_old_00_90","demangled":false,"offset":109576,"size":16,"space":"strings"} +str..dpkg_tmp_00_90={"realname":"str..dpkg_tmp_00_90","demangled":false,"offset":109592,"size":16,"space":"strings"} +str..dwm_01_31={"realname":"str..dwm_01_31","demangled":false,"offset":108570,"size":11,"space":"strings"} +str..dz_01_31={"realname":"str..dz_01_31","demangled":false,"offset":108256,"size":10,"space":"strings"} +str..ear_01_31={"realname":"str..ear_01_31","demangled":false,"offset":108439,"size":11,"space":"strings"} +str..emf_01_35={"realname":"str..emf_01_35","demangled":false,"offset":109144,"size":11,"space":"strings"} +str..esd_01_31={"realname":"str..esd_01_31","demangled":false,"offset":108581,"size":11,"space":"strings"} +str..exe_01_32={"realname":"str..exe_01_32","demangled":false,"offset":107889,"size":12,"space":"strings"} +str..flac_00_36={"realname":"str..flac_00_36","demangled":false,"offset":109269,"size":12,"space":"strings"} +str..flc_01_35={"realname":"str..flc_01_35","demangled":false,"offset":109036,"size":11,"space":"strings"} +str..fli_01_35={"realname":"str..fli_01_35","demangled":false,"offset":109058,"size":11,"space":"strings"} +str..flv_01_35={"realname":"str..flv_01_35","demangled":false,"offset":109069,"size":11,"space":"strings"} +str..gif_01_35={"realname":"str..gif_01_35","demangled":false,"offset":108668,"size":11,"space":"strings"} +str..gl_01_35={"realname":"str..gl_01_35","demangled":false,"offset":109080,"size":10,"space":"strings"} +str..gz_01_31={"realname":"str..gz_01_31","demangled":false,"offset":108266,"size":10,"space":"strings"} +str..jar_01_31={"realname":"str..jar_01_31","demangled":false,"offset":108417,"size":11,"space":"strings"} +str..jpeg_01_35={"realname":"str..jpeg_01_35","demangled":false,"offset":108631,"size":12,"space":"strings"} +str..jpg_01_35={"realname":"str..jpg_01_35","demangled":false,"offset":108620,"size":11,"space":"strings"} +str..lha_01_31={"realname":"str..lha_01_31","demangled":false,"offset":108147,"size":11,"space":"strings"} +str..libs={"realname":"str..libs","demangled":false,"offset":110624,"size":8,"space":"strings"} +str..lrz_01_31={"realname":"str..lrz_01_31","demangled":false,"offset":108276,"size":11,"space":"strings"} +str..lz4_01_31={"realname":"str..lz4_01_31","demangled":false,"offset":108158,"size":11,"space":"strings"} +str..lz_01_31={"realname":"str..lz_01_31","demangled":false,"offset":108287,"size":10,"space":"strings"} +str..lzh_01_31={"realname":"str..lzh_01_31","demangled":false,"offset":108169,"size":11,"space":"strings"} +str..lzma_01_31={"realname":"str..lzma_01_31","demangled":false,"offset":108180,"size":12,"space":"strings"} +str..lzo_01_31={"realname":"str..lzo_01_31","demangled":false,"offset":108297,"size":11,"space":"strings"} +str..m2v_01_35={"realname":"str..m2v_01_35","demangled":false,"offset":108869,"size":11,"space":"strings"} +str..m4a_00_36={"realname":"str..m4a_00_36","demangled":false,"offset":109281,"size":11,"space":"strings"} +str..m4v_01_35={"realname":"str..m4v_01_35","demangled":false,"offset":108937,"size":11,"space":"strings"} +str..mid_00_36={"realname":"str..mid_00_36","demangled":false,"offset":109292,"size":11,"space":"strings"} +str..midi_00_36={"realname":"str..midi_00_36","demangled":false,"offset":109303,"size":12,"space":"strings"} +str..mjpeg_01_35={"realname":"str..mjpeg_01_35","demangled":false,"offset":108655,"size":13,"space":"strings"} +str..mjpg_01_35={"realname":"str..mjpg_01_35","demangled":false,"offset":108643,"size":12,"space":"strings"} +str..mka_00_36={"realname":"str..mka_00_36","demangled":false,"offset":109315,"size":11,"space":"strings"} +str..mkv_01_35={"realname":"str..mkv_01_35","demangled":false,"offset":108880,"size":11,"space":"strings"} +str..mng_01_35={"realname":"str..mng_01_35","demangled":false,"offset":108813,"size":11,"space":"strings"} +str..mov_01_35={"realname":"str..mov_01_35","demangled":false,"offset":108835,"size":11,"space":"strings"} +str..mp3_00_36={"realname":"str..mp3_00_36","demangled":false,"offset":109326,"size":11,"space":"strings"} +str..mp4_01_35={"realname":"str..mp4_01_35","demangled":false,"offset":108926,"size":11,"space":"strings"} +str..mp4v_01_35={"realname":"str..mp4v_01_35","demangled":false,"offset":108948,"size":12,"space":"strings"} +str..mpc_00_36={"realname":"str..mpc_00_36","demangled":false,"offset":109337,"size":11,"space":"strings"} +str..mpeg_01_35={"realname":"str..mpeg_01_35","demangled":false,"offset":108857,"size":12,"space":"strings"} +str..mpg_01_35={"realname":"str..mpg_01_35","demangled":false,"offset":108846,"size":11,"space":"strings"} +str..nuv_01_35={"realname":"str..nuv_01_35","demangled":false,"offset":108981,"size":11,"space":"strings"} +str..oga_00_36={"realname":"str..oga_00_36","demangled":false,"offset":109435,"size":11,"space":"strings"} +str..ogg_00_36={"realname":"str..ogg_00_36","demangled":false,"offset":109348,"size":11,"space":"strings"} +str..ogm_01_35={"realname":"str..ogm_01_35","demangled":false,"offset":108915,"size":11,"space":"strings"} +str..ogv_01_35={"realname":"str..ogv_01_35","demangled":false,"offset":109210,"size":11,"space":"strings"} +str..ogx_01_35={"realname":"str..ogx_01_35","demangled":false,"offset":109221,"size":11,"space":"strings"} +str..old_00_90={"realname":"str..old_00_90","demangled":false,"offset":109608,"size":11,"space":"strings"} +str..opus_00_36={"realname":"str..opus_00_36","demangled":false,"offset":109446,"size":12,"space":"strings"} +str..orig_00_90={"realname":"str..orig_00_90","demangled":false,"offset":109619,"size":12,"space":"strings"} +str..part_00_90={"realname":"str..part_00_90","demangled":false,"offset":109631,"size":12,"space":"strings"} +str..pbm_01_35={"realname":"str..pbm_01_35","demangled":false,"offset":108690,"size":11,"space":"strings"} +str..pcx_01_35={"realname":"str..pcx_01_35","demangled":false,"offset":108824,"size":11,"space":"strings"} +str..pgm_01_35={"realname":"str..pgm_01_35","demangled":false,"offset":108701,"size":11,"space":"strings"} +str..png_01_35={"realname":"str..png_01_35","demangled":false,"offset":108779,"size":11,"space":"strings"} +str..ppm_01_35={"realname":"str..ppm_01_35","demangled":false,"offset":108712,"size":11,"space":"strings"} +str..qt_01_35={"realname":"str..qt_01_35","demangled":false,"offset":108971,"size":10,"space":"strings"} +str..ra_00_36={"realname":"str..ra_00_36","demangled":false,"offset":109359,"size":10,"space":"strings"} +str..rar_01_31={"realname":"str..rar_01_31","demangled":false,"offset":108461,"size":11,"space":"strings"} +str..rej_00_90={"realname":"str..rej_00_90","demangled":false,"offset":109643,"size":11,"space":"strings"} +str..rm_01_35={"realname":"str..rm_01_35","demangled":false,"offset":109014,"size":10,"space":"strings"} +str..rmvb_01_35={"realname":"str..rmvb_01_35","demangled":false,"offset":109024,"size":12,"space":"strings"} +str..rpm_01_31={"realname":"str..rpm_01_31","demangled":false,"offset":108406,"size":11,"space":"strings"} +str..rpmnew_00_90={"realname":"str..rpmnew_00_90","demangled":false,"offset":109654,"size":14,"space":"strings"} +str..rpmorig_00_90={"realname":"str..rpmorig_00_90","demangled":false,"offset":109668,"size":15,"space":"strings"} +str..rpmsave_00_90={"realname":"str..rpmsave_00_90","demangled":false,"offset":109683,"size":15,"space":"strings"} +str..rz_01_31={"realname":"str..rz_01_31","demangled":false,"offset":108527,"size":10,"space":"strings"} +str..sar_01_31={"realname":"str..sar_01_31","demangled":false,"offset":108450,"size":11,"space":"strings"} +str..sh_01_32={"realname":"str..sh_01_32","demangled":false,"offset":108031,"size":11,"space":"strings"} +str..spx_00_36={"realname":"str..spx_00_36","demangled":false,"offset":109458,"size":11,"space":"strings"} +str..svg_01_35={"realname":"str..svg_01_35","demangled":false,"offset":108790,"size":11,"space":"strings"} +str..svgz_01_35={"realname":"str..svgz_01_35","demangled":false,"offset":108801,"size":12,"space":"strings"} +str..swm_01_31={"realname":"str..swm_01_31","demangled":false,"offset":108559,"size":11,"space":"strings"} +str..swp_00_90={"realname":"str..swp_00_90","demangled":false,"offset":109698,"size":11,"space":"strings"} +str..t7z_01_31={"realname":"str..t7z_01_31","demangled":false,"offset":108225,"size":11,"space":"strings"} +str..tar_01_31={"realname":"str..tar_01_31","demangled":false,"offset":108092,"size":11,"space":"strings"} +str..taz_01_31={"realname":"str..taz_01_31","demangled":false,"offset":108136,"size":11,"space":"strings"} +str..tbz2_01_31={"realname":"str..tbz2_01_31","demangled":false,"offset":108373,"size":12,"space":"strings"} +str..tbz_01_31={"realname":"str..tbz_01_31","demangled":false,"offset":108362,"size":11,"space":"strings"} +str..tga_01_35={"realname":"str..tga_01_35","demangled":false,"offset":108723,"size":11,"space":"strings"} +str..tgz_01_31={"realname":"str..tgz_01_31","demangled":false,"offset":108103,"size":11,"space":"strings"} +str..tif_01_35={"realname":"str..tif_01_35","demangled":false,"offset":108756,"size":11,"space":"strings"} +str..tiff_01_35={"realname":"str..tiff_01_35","demangled":false,"offset":108767,"size":12,"space":"strings"} +str..tlz_01_31={"realname":"str..tlz_01_31","demangled":false,"offset":108192,"size":11,"space":"strings"} +str..tmp_00_90={"realname":"str..tmp_00_90","demangled":false,"offset":109709,"size":11,"space":"strings"} +str..txz_01_31={"realname":"str..txz_01_31","demangled":false,"offset":108203,"size":11,"space":"strings"} +str..tz_01_31={"realname":"str..tz_01_31","demangled":false,"offset":108385,"size":10,"space":"strings"} +str..tzo_01_31={"realname":"str..tzo_01_31","demangled":false,"offset":108214,"size":11,"space":"strings"} +str..tzst_01_31={"realname":"str..tzst_01_31","demangled":false,"offset":108329,"size":12,"space":"strings"} +str..ucf_dist_00_90={"realname":"str..ucf_dist_00_90","demangled":false,"offset":109720,"size":16,"space":"strings"} +str..ucf_new_00_90={"realname":"str..ucf_new_00_90","demangled":false,"offset":109736,"size":15,"space":"strings"} +str..ucf_old_00_90={"realname":"str..ucf_old_00_90","demangled":false,"offset":109751,"size":15,"space":"strings"} +str..vob_01_35={"realname":"str..vob_01_35","demangled":false,"offset":108960,"size":11,"space":"strings"} +str..war_01_31={"realname":"str..war_01_31","demangled":false,"offset":108428,"size":11,"space":"strings"} +str..wav_00_36={"realname":"str..wav_00_36","demangled":false,"offset":109369,"size":11,"space":"strings"} +str..webm_01_35={"realname":"str..webm_01_35","demangled":false,"offset":108891,"size":12,"space":"strings"} +str..webp_01_35={"realname":"str..webp_01_35","demangled":false,"offset":108903,"size":12,"space":"strings"} +str..wim_01_31={"realname":"str..wim_01_31","demangled":false,"offset":108548,"size":11,"space":"strings"} +str..wmv_01_35={"realname":"str..wmv_01_35","demangled":false,"offset":108992,"size":11,"space":"strings"} +str..xbm_01_35={"realname":"str..xbm_01_35","demangled":false,"offset":108734,"size":11,"space":"strings"} +str..xcf_01_35={"realname":"str..xcf_01_35","demangled":false,"offset":109100,"size":11,"space":"strings"} +str..xpm_01_35={"realname":"str..xpm_01_35","demangled":false,"offset":108745,"size":11,"space":"strings"} +str..xspf_00_36={"realname":"str..xspf_00_36","demangled":false,"offset":109469,"size":12,"space":"strings"} +str..xwd_01_35={"realname":"str..xwd_01_35","demangled":false,"offset":109111,"size":11,"space":"strings"} +str..xz_01_31={"realname":"str..xz_01_31","demangled":false,"offset":108308,"size":10,"space":"strings"} +str..yuv_01_35={"realname":"str..yuv_01_35","demangled":false,"offset":109122,"size":11,"space":"strings"} +str..z_01_31={"realname":"str..z_01_31","demangled":false,"offset":108247,"size":9,"space":"strings"} +str..zip_01_31={"realname":"str..zip_01_31","demangled":false,"offset":108236,"size":11,"space":"strings"} +str..zoo_01_31={"realname":"str..zoo_01_31","demangled":false,"offset":108494,"size":11,"space":"strings"} +str..zst_01_31={"realname":"str..zst_01_31","demangled":false,"offset":108318,"size":11,"space":"strings"} +str.00_90={"realname":"str.00_90","demangled":false,"offset":109505,"size":9,"space":"strings"} +str.00_none_01_bold_04_underscore_05_blink_07_reverse_08_concealed={"realname":"str.00_none_01_bold_04_underscore_05_blink_07_reverse_08_concealed","demangled":false,"offset":106035,"size":65,"space":"strings"} +str.01_32={"realname":"str.01_32","demangled":false,"offset":111752,"size":6,"space":"strings"} +str.01_33={"realname":"str.01_33","demangled":false,"offset":111746,"size":6,"space":"strings"} +str.01_34={"realname":"str.01_34","demangled":false,"offset":111728,"size":6,"space":"strings"} +str.01_35={"realname":"str.01_35","demangled":false,"offset":111740,"size":6,"space":"strings"} +str.01_36={"realname":"str.01_36","demangled":false,"offset":111734,"size":6,"space":"strings"} +str.02x={"realname":"str.02x","demangled":false,"offset":110390,"size":7,"space":"strings"} +str.30_42={"realname":"str.30_42","demangled":false,"offset":111782,"size":6,"space":"strings"} +str.30_43={"realname":"str.30_43","demangled":false,"offset":111764,"size":6,"space":"strings"} +str.30_black_31_red_32_green_33_yellow_34_blue_35_magenta_36_cyan_37_white={"realname":"str.30_black_31_red_32_green_33_yellow_34_blue_35_magenta_36_cyan_37_white","demangled":false,"offset":106120,"size":73,"space":"strings"} +str.34_42={"realname":"str.34_42","demangled":false,"offset":111776,"size":6,"space":"strings"} +str.37_41={"realname":"str.37_41","demangled":false,"offset":111758,"size":6,"space":"strings"} +str.37_44={"realname":"str.37_44","demangled":false,"offset":111770,"size":6,"space":"strings"} +str.40_black_41_red_42_green_43_yellow_44_blue_45_magenta_46_cyan_47_white={"realname":"str.40_black_41_red_42_green_43_yellow_44_blue_45_magenta_46_cyan_47_white","demangled":false,"offset":106219,"size":73,"space":"strings"} +str.8={"realname":"str.8","demangled":false,"offset":110417,"size":7,"space":"strings"} +str.8__file:___s_s_s={"realname":"str.8__file:___s_s_s","demangled":false,"offset":110397,"size":20,"space":"strings"} +str.ASCII={"realname":"str.ASCII","demangled":false,"offset":110030,"size":6,"space":"strings"} +str.A_NULL_argv_0__was_passed_through_an_exec_system_call.={"realname":"str.A_NULL_argv_0__was_passed_through_an_exec_system_call.","demangled":false,"offset":120288,"size":56,"space":"strings"} +str.Attribute_codes:={"realname":"str.Attribute_codes:","demangled":false,"offset":106016,"size":19,"space":"strings"} +str.BLK_40_33_01___block_device_driver={"realname":"str.BLK_40_33_01___block_device_driver","demangled":false,"offset":106671,"size":35,"space":"strings"} +str.BLOCKSIZE={"realname":"str.BLOCKSIZE","demangled":false,"offset":111897,"size":10,"space":"strings"} +str.B____ignore_backups_______do_not_list_implied_entries_ending_with={"realname":"str.B____ignore_backups_______do_not_list_implied_entries_ending_with","demangled":false,"offset":112888,"size":72,"space":"strings"} +str.Background_color_codes:={"realname":"str.Background_color_codes:","demangled":false,"offset":106193,"size":26,"space":"strings"} +str.Basic_file_attributes={"realname":"str.Basic_file_attributes","demangled":false,"offset":105655,"size":24,"space":"strings"} +str.Below_are_TERM_or_COLORTERM_entries__which_can_be_glob_patterns__which={"realname":"str.Below_are_TERM_or_COLORTERM_entries__which_can_be_glob_patterns__which","demangled":false,"offset":105117,"size":73,"space":"strings"} +str.Below_are_the_color_init_strings_for_the_basic_file_types.={"realname":"str.Below_are_the_color_init_strings_for_the_basic_file_types.","demangled":false,"offset":105749,"size":61,"space":"strings"} +str.CAPABILITY_00___file_with_capability__very_expensive_to_lookup={"realname":"str.CAPABILITY_00___file_with_capability__very_expensive_to_lookup","demangled":false,"offset":106945,"size":64,"space":"strings"} +str.CHR_40_33_01___character_device_driver={"realname":"str.CHR_40_33_01___character_device_driver","demangled":false,"offset":106706,"size":39,"space":"strings"} +str.COLORTERM={"realname":"str.COLORTERM","demangled":false,"offset":111027,"size":10,"space":"strings"} +str.COLUMNS={"realname":"str.COLUMNS","demangled":false,"offset":110843,"size":8,"space":"strings"} +str.C_________________________list_entries_by_columns_________color__WHEN__________color_the_output_WHEN__more_info_below____d____directory____________list_directories_themselves__not_their_contents____D____dired________________generate_output_designed_for_Emacs__dired_mode={"realname":"str.C_________________________list_entries_by_columns_________color__WHEN__________color_the_output_WHEN__more_info_below____d____directory____________list_directories_themselves__not_their_contents____D____dired________________generate_output_designed_for_Emacs__dired_mode","demangled":false,"offset":113240,"size":275,"space":"strings"} +str.Configuration_file_for_dircolors__a_utility_to_help_you_set_the={"realname":"str.Configuration_file_for_dircolors__a_utility_to_help_you_set_the","demangled":false,"offset":104416,"size":66,"space":"strings"} +str.Copying_and_distribution_of_this_file__with_or_without_modification={"realname":"str.Copying_and_distribution_of_this_file__with_or_without_modification","demangled":false,"offset":104612,"size":71,"space":"strings"} +str.Copyright__C__1996_2023_Free_Software_Foundation__Inc.={"realname":"str.Copyright__C__1996_2023_Free_Software_Foundation__Inc.","demangled":false,"offset":104555,"size":57,"space":"strings"} +str.Copyright__s__d_Free_Software_Foundation__Inc.={"realname":"str.Copyright__s__d_Free_Software_Foundation__Inc.","demangled":false,"offset":123168,"size":47,"space":"strings"} +str.DIRED={"realname":"str.DIRED","demangled":false,"offset":111080,"size":10,"space":"strings"} +str.DIRED_OPTIONS_____quoting_style__s={"realname":"str.DIRED_OPTIONS_____quoting_style__s","demangled":false,"offset":120880,"size":38,"space":"strings"} +str.DIR_01_34___directory={"realname":"str.DIR_01_34___directory","demangled":false,"offset":106405,"size":22,"space":"strings"} +str.DOOR_01_35___door={"realname":"str.DOOR_01_35___door","demangled":false,"offset":106653,"size":18,"space":"strings"} +str.David_MacKenzie={"realname":"str.David_MacKenzie","demangled":false,"offset":110789,"size":16,"space":"strings"} +str.EVERYONE={"realname":"str.EVERYONE","demangled":false,"offset":112100,"size":10,"space":"strings"} +str.EXEC_01_32={"realname":"str.EXEC_01_32","demangled":false,"offset":107273,"size":11,"space":"strings"} +str.Exit_status:__0__if_OK___1__if_minor_problems__e.g.__cannot_access_subdirectory____2__if_serious_trouble__e.g.__cannot_access_command_line_argument_.={"realname":"str.Exit_status:__0__if_OK___1__if_minor_problems__e.g.__cannot_access_subdirectory____2__if_serious_trouble__e.g.__cannot_access_command_line_argument_.","demangled":false,"offset":119840,"size":152,"space":"strings"} +str.FIFO_40_33___pipe={"realname":"str.FIFO_40_33___pipe","demangled":false,"offset":106615,"size":18,"space":"strings"} +str.FILE_00___regular_file:_use_no_color_at_all={"realname":"str.FILE_00___regular_file:_use_no_color_at_all","demangled":false,"offset":106326,"size":45,"space":"strings"} +str.FORMAT__e.g.____H:_M__for_a__date__style_format={"realname":"str.FORMAT__e.g.____H:_M__for_a__date__style_format","demangled":false,"offset":120632,"size":54,"space":"strings"} +str.File_extension_attributes={"realname":"str.File_extension_attributes","demangled":false,"offset":107354,"size":28,"space":"strings"} +str.Full_documentation___s_s={"realname":"str.Full_documentation___s_s","demangled":false,"offset":110176,"size":27,"space":"strings"} +str.GB18030={"realname":"str.GB18030","demangled":false,"offset":110331,"size":8,"space":"strings"} +str.GNU_coreutils={"realname":"str.GNU_coreutils","demangled":false,"offset":110158,"size":14,"space":"strings"} +str.GROUP={"realname":"str.GROUP","demangled":false,"offset":112093,"size":7,"space":"strings"} +str.G____no_group_____________in_a_long_listing__don_t_print_group_names={"realname":"str.G____no_group_____________in_a_long_listing__don_t_print_group_names","demangled":false,"offset":114256,"size":73,"space":"strings"} +str.Global_config_options_can_be_specified_before_TERM_or_COLORTERM_entries={"realname":"str.Global_config_options_can_be_specified_before_TERM_or_COLORTERM_entries","demangled":false,"offset":104884,"size":74,"space":"strings"} +str.H:_M:_S={"realname":"str.H:_M:_S","demangled":false,"offset":111995,"size":9,"space":"strings"} +str.H____dereference_command_line______________________________follow_symbolic_links_listed_on_the_command_line={"realname":"str.H____dereference_command_line______________________________follow_symbolic_links_listed_on_the_command_line","demangled":false,"offset":114488,"size":112,"space":"strings"} +str.If_you_use_DOS_style_suffixes__you_may_want_to_uncomment_the_following:={"realname":"str.If_you_use_DOS_style_suffixes__you_may_want_to_uncomment_the_following:","demangled":false,"offset":107774,"size":74,"space":"strings"} +str.KMGTPEZYRQ={"realname":"str.KMGTPEZYRQ","demangled":false,"offset":103913,"size":11,"space":"strings"} +str.LINK_01_36___symbolic_link.__If_you_set_this_to__target__instead_of_a={"realname":"str.LINK_01_36___symbolic_link.__If_you_set_this_to__target__instead_of_a","demangled":false,"offset":106427,"size":70,"space":"strings"} +str.LS_BLOCK_SIZE={"realname":"str.LS_BLOCK_SIZE","demangled":false,"offset":110829,"size":14,"space":"strings"} +str.LS_COLORS={"realname":"str.LS_COLORS","demangled":false,"offset":111017,"size":10,"space":"strings"} +str.LS_COLORS_environment_variable_used_by_GNU_ls_with_the___color_option.={"realname":"str.LS_COLORS_environment_variable_used_by_GNU_ls_with_the___color_option.","demangled":false,"offset":104482,"size":73,"space":"strings"} +str.L____dereference__________when_showing_file_information_for_a_symbolic______________________________link__show_information_for_the_file_the_link______________________________references_rather_than_for_the_link_itself={"realname":"str.L____dereference__________when_showing_file_information_for_a_symbolic______________________________link__show_information_for_the_file_the_link______________________________references_rather_than_for_the_link_itself","demangled":false,"offset":115576,"size":222,"space":"strings"} +str.License_GPLv3_:_GNU_GPL_version_3_or_later___s_._This_is_free_software:_you_are_free_to_change_and_redistribute_it._There_is_NO_WARRANTY__to_the_extent_permitted_by_law.={"realname":"str.License_GPLv3_:_GNU_GPL_version_3_or_later___s_._This_is_free_software:_you_are_free_to_change_and_redistribute_it._There_is_NO_WARRANTY__to_the_extent_permitted_by_law.","demangled":false,"offset":121008,"size":171,"space":"strings"} +str.List_any_file_extensions_like__.gz__or__.tar__that_you_would_like_ls={"realname":"str.List_any_file_extensions_like__.gz__or__.tar__that_you_would_like_ls","demangled":false,"offset":107452,"size":71,"space":"strings"} +str.List_information_about_the_FILEs__the_current_directory_by_default_._Sort_entries_alphabetically_if_none_of__cftuvSUX_nor___sort_is_specified.={"realname":"str.List_information_about_the_FILEs__the_current_directory_by_default_._Sort_entries_alphabetically_if_none_of__cftuvSUX_nor___sort_is_specified.","demangled":false,"offset":112232,"size":144,"space":"strings"} +str.MISSING_00___..._and_the_files_they_point_to={"realname":"str.MISSING_00___..._and_the_files_they_point_to","demangled":false,"offset":106818,"size":45,"space":"strings"} +str.MULTIHARDLINK_00___regular_file_with_more_than_one_link={"realname":"str.MULTIHARDLINK_00___regular_file_with_more_than_one_link","demangled":false,"offset":106559,"size":56,"space":"strings"} +str.Mandatory_arguments_to_long_options_are_mandatory_for_short_options_too.={"realname":"str.Mandatory_arguments_to_long_options_are_mandatory_for_short_options_too.","demangled":false,"offset":112376,"size":75,"space":"strings"} +str.Multi_call_invocation={"realname":"str.Multi_call_invocation","demangled":false,"offset":110073,"size":22,"space":"strings"} +str.NORMAL_00___no_color_code_at_all={"realname":"str.NORMAL_00___no_color_code_at_all","demangled":false,"offset":106292,"size":34,"space":"strings"} +str.ORPHAN_40_31_01___symlink_to_nonexistent_file__or_non_stat_able_file_...={"realname":"str.ORPHAN_40_31_01___symlink_to_nonexistent_file__or_non_stat_able_file_...","demangled":false,"offset":106745,"size":73,"space":"strings"} +str.OTHER_WRITABLE_34_42___dir_that_is_other_writable__o_w__and_not_sticky={"realname":"str.OTHER_WRITABLE_34_42___dir_that_is_other_writable__o_w__and_not_sticky","demangled":false,"offset":107086,"size":71,"space":"strings"} +str.OWNER={"realname":"str.OWNER","demangled":false,"offset":112086,"size":7,"space":"strings"} +str.One_can_use_codes_for_256_or_more_colors_supported_by_modern_terminals.={"realname":"str.One_can_use_codes_for_256_or_more_colors_supported_by_modern_terminals.","demangled":false,"offset":105810,"size":74,"space":"strings"} +str.Or_if_you_want_to_color_scripts_even_if_they_do_not_have_the={"realname":"str.Or_if_you_want_to_color_scripts_even_if_they_do_not_have_the","demangled":false,"offset":107937,"size":63,"space":"strings"} +str.POSIX={"realname":"str.POSIX","demangled":false,"offset":110294,"size":6,"space":"strings"} +str.POSIXLY_CORRECT={"realname":"str.POSIXLY_CORRECT","demangled":false,"offset":111907,"size":16,"space":"strings"} +str.QUOTING_STYLE={"realname":"str.QUOTING_STYLE","demangled":false,"offset":110859,"size":14,"space":"strings"} +str.Q____quote_name___________enclose_entry_names_in_double_quotes={"realname":"str.Q____quote_name___________enclose_entry_names_in_double_quotes","demangled":false,"offset":116416,"size":67,"space":"strings"} +str.RESET_0___reset_to__normal__color={"realname":"str.RESET_0___reset_to__normal__color","demangled":false,"offset":106371,"size":34,"space":"strings"} +str.Report_any_translation_bugs_to__https:__translationproject.org_team={"realname":"str.Report_any_translation_bugs_to__https:__translationproject.org_team","demangled":false,"offset":120032,"size":71,"space":"strings"} +str.Richard_M._Stallman={"realname":"str.Richard_M._Stallman","demangled":false,"offset":110805,"size":20,"space":"strings"} +str.SETGID_30_43___file_that_is_setgid__g_s={"realname":"str.SETGID_30_43___file_that_is_setgid__g_s","demangled":false,"offset":106904,"size":41,"space":"strings"} +str.SETUID_37_41___file_that_is_setuid__u_s={"realname":"str.SETUID_37_41___file_that_is_setuid__u_s","demangled":false,"offset":106863,"size":41,"space":"strings"} +str.SOCK_01_35___socket={"realname":"str.SOCK_01_35___socket","demangled":false,"offset":106633,"size":20,"space":"strings"} +str.STICKY_37_44___dir_with_the_sticky_bit_set___t__and_not_other_writable={"realname":"str.STICKY_37_44___dir_with_the_sticky_bit_set___t__and_not_other_writable","demangled":false,"offset":107157,"size":71,"space":"strings"} +str.STICKY_OTHER_WRITABLE_30_42___dir_that_is_sticky_and_other_writable___t_o_w={"realname":"str.STICKY_OTHER_WRITABLE_30_42___dir_that_is_sticky_and_other_writable___t_o_w","demangled":false,"offset":107009,"size":77,"space":"strings"} +str.SUBDIRED={"realname":"str.SUBDIRED","demangled":false,"offset":111090,"size":13,"space":"strings"} +str.S_________________________sort_by_file_size__largest_first={"realname":"str.S_________________________sort_by_file_size__largest_first","demangled":false,"offset":116976,"size":63,"space":"strings"} +str.Subsequent_TERM_or_COLORTERM_entries__can_be_used_to_add___override={"realname":"str.Subsequent_TERM_or_COLORTERM_entries__can_be_used_to_add___override","demangled":false,"offset":109768,"size":70,"space":"strings"} +str.Suffixes_are_matched_case_insensitively__but_if_you_define_different={"realname":"str.Suffixes_are_matched_case_insensitively__but_if_you_define_different","demangled":false,"offset":107643,"size":71,"space":"strings"} +str.TABSIZE={"realname":"str.TABSIZE","demangled":false,"offset":110851,"size":8,"space":"strings"} +str.TERM={"realname":"str.TERM","demangled":false,"offset":111037,"size":6,"space":"strings"} +str.TERM_Eterm={"realname":"str.TERM_Eterm","demangled":false,"offset":105279,"size":11,"space":"strings"} +str.TERM__color={"realname":"str.TERM__color","demangled":false,"offset":105300,"size":13,"space":"strings"} +str.TERM__direct={"realname":"str.TERM__direct","demangled":false,"offset":105372,"size":14,"space":"strings"} +str.TERM_ansi={"realname":"str.TERM_ansi","demangled":false,"offset":105290,"size":10,"space":"strings"} +str.TERM_con_0_9__x_0_9={"realname":"str.TERM_con_0_9__x_0_9","demangled":false,"offset":105313,"size":22,"space":"strings"} +str.TERM_cons25={"realname":"str.TERM_cons25","demangled":false,"offset":105335,"size":12,"space":"strings"} +str.TERM_console={"realname":"str.TERM_console","demangled":false,"offset":105347,"size":13,"space":"strings"} +str.TERM_cygwin={"realname":"str.TERM_cygwin","demangled":false,"offset":105360,"size":12,"space":"strings"} +str.TERM_dtterm={"realname":"str.TERM_dtterm","demangled":false,"offset":105386,"size":12,"space":"strings"} +str.TERM_gnome={"realname":"str.TERM_gnome","demangled":false,"offset":105398,"size":11,"space":"strings"} +str.TERM_hurd={"realname":"str.TERM_hurd","demangled":false,"offset":105409,"size":10,"space":"strings"} +str.TERM_jfbterm={"realname":"str.TERM_jfbterm","demangled":false,"offset":105419,"size":13,"space":"strings"} +str.TERM_konsole={"realname":"str.TERM_konsole","demangled":false,"offset":105432,"size":13,"space":"strings"} +str.TERM_kterm={"realname":"str.TERM_kterm","demangled":false,"offset":105445,"size":11,"space":"strings"} +str.TERM_linux={"realname":"str.TERM_linux","demangled":false,"offset":105456,"size":11,"space":"strings"} +str.TERM_linux_c={"realname":"str.TERM_linux_c","demangled":false,"offset":105467,"size":13,"space":"strings"} +str.TERM_mlterm={"realname":"str.TERM_mlterm","demangled":false,"offset":105480,"size":12,"space":"strings"} +str.TERM_putty={"realname":"str.TERM_putty","demangled":false,"offset":105492,"size":11,"space":"strings"} +str.TERM_rxvt={"realname":"str.TERM_rxvt","demangled":false,"offset":105503,"size":11,"space":"strings"} +str.TERM_screen={"realname":"str.TERM_screen","demangled":false,"offset":105514,"size":13,"space":"strings"} +str.TERM_st={"realname":"str.TERM_st","demangled":false,"offset":105527,"size":8,"space":"strings"} +str.TERM_terminator={"realname":"str.TERM_terminator","demangled":false,"offset":105535,"size":16,"space":"strings"} +str.TERM_tmux={"realname":"str.TERM_tmux","demangled":false,"offset":105551,"size":11,"space":"strings"} +str.TERM_vt100={"realname":"str.TERM_vt100","demangled":false,"offset":105562,"size":11,"space":"strings"} +str.TERM_xterm={"realname":"str.TERM_xterm","demangled":false,"offset":105573,"size":12,"space":"strings"} +str.TIME_STYLE={"realname":"str.TIME_STYLE","demangled":false,"offset":110879,"size":11,"space":"strings"} +str.Terminal_filters={"realname":"str.Terminal_filters","demangled":false,"offset":105028,"size":19,"space":"strings"} +str.Text_color_codes:={"realname":"str.Text_color_codes:","demangled":false,"offset":106100,"size":20,"space":"strings"} +str.The_SIZE_argument_is_an_integer_and_optional_unit__example:_10K_is_10_1024_._Units_are_K_M_G_T_P_E_Z_Y_R_Q__powers_of_1024__or_KB_MB_...__powers_of_1000_._Binary_prefixes_can_be_used__too:_KiB_K__MiB_M__and_so_on.={"realname":"str.The_SIZE_argument_is_an_integer_and_optional_unit__example:_10K_is_10_1024_._Units_are_K_M_G_T_P_E_Z_Y_R_Q__powers_of_1024__or_KB_MB_...__powers_of_1000_._Binary_prefixes_can_be_used__too:_KiB_K__MiB_M__and_so_on.","demangled":false,"offset":118872,"size":216,"space":"strings"} +str.The_TIME_STYLE_argument_can_be_full_iso__long_iso__iso__locale__or__FORMAT._FORMAT_is_interpreted_like_in_date_1_.__If_FORMAT_is_FORMAT1_newline_FORMAT2__then_FORMAT1_applies_to_non_recent_files_and_FORMAT2_to_recent_files._TIME_STYLE_prefixed_with__posix___takes_effect_only_outside_the_POSIX_locale._Also_the_TIME_STYLE_environment_variable_sets_the_default_style_to_use.={"realname":"str.The_TIME_STYLE_argument_can_be_full_iso__long_iso__iso__locale__or__FORMAT._FORMAT_is_interpreted_like_in_date_1_.__If_FORMAT_is_FORMAT1_newline_FORMAT2__then_FORMAT1_applies_to_non_recent_files_and_FORMAT2_to_recent_files._TIME_STYLE_prefixed_with__posix___takes_effect_only_outside_the_POSIX_locale._Also_the_TIME_STYLE_environment_variable_sets_the_default_style_to_use.","demangled":false,"offset":119088,"size":376,"space":"strings"} +str.The_WHEN_argument_defaults_to__always__and_can_also_be__auto__or__never_.={"realname":"str.The_WHEN_argument_defaults_to__always__and_can_also_be__auto__or__never_.","demangled":false,"offset":119464,"size":76,"space":"strings"} +str.The_default_color_codes_use_the_capabilities_of_an_8_color_terminal={"realname":"str.The_default_color_codes_use_the_capabilities_of_an_8_color_terminal","demangled":false,"offset":105884,"size":70,"space":"strings"} +str.The_keywords_COLOR__OPTIONS__and_EIGHTBIT__honored_by_the={"realname":"str.The_keywords_COLOR__OPTIONS__and_EIGHTBIT__honored_by_the","demangled":false,"offset":104762,"size":60,"space":"strings"} +str.This_is_for_files_with_execute_permission:={"realname":"str.This_is_for_files_with_execute_permission:","demangled":false,"offset":107228,"size":45,"space":"strings"} +str.Try___s___help__for_more_information.={"realname":"str.Try___s___help__for_more_information.","demangled":false,"offset":112144,"size":39,"space":"strings"} +str.UTF_8={"realname":"str.UTF_8","demangled":false,"offset":110036,"size":6,"space":"strings"} +str.U_________________________do_not_sort__list_entries_in_directory_order={"realname":"str.U_________________________do_not_sort__list_entries_in_directory_order","demangled":false,"offset":118192,"size":75,"space":"strings"} +str.Usage:__s__OPTION_...__FILE_...={"realname":"str.Usage:__s__OPTION_...__FILE_...","demangled":false,"offset":112192,"size":33,"space":"strings"} +str.Using_color_to_distinguish_file_types_is_disabled_both_by_default_and_with___color_never.__With___color_auto__ls_emits_color_codes_only_when_standard_output_is_connected_to_a_terminal.__The_LS_COLORS_environment_variable_can_change_the_settings.__Use_the_dircolors_1__command_to_set_it.={"realname":"str.Using_color_to_distinguish_file_types_is_disabled_both_by_default_and_with___color_never.__With___color_auto__ls_emits_color_codes_only_when_standard_output_is_connected_to_a_terminal.__The_LS_COLORS_environment_variable_can_change_the_settings.__Use_the_dircolors_1__command_to_set_it.","demangled":false,"offset":119544,"size":289,"space":"strings"} +str.Valid_arguments_are:={"realname":"str.Valid_arguments_are:","demangled":false,"offset":111943,"size":21,"space":"strings"} +str.Written_by__s.={"realname":"str.Written_by__s.","demangled":false,"offset":111830,"size":16,"space":"strings"} +str.Written_by__s___s___s___s___s___s___s___s___s__and_others.={"realname":"str.Written_by__s___s___s___s___s___s___s___s___s__and_others.","demangled":false,"offset":121224,"size":60,"space":"strings"} +str.Written_by__s___s___s___s___s___s___s___s__and__s.={"realname":"str.Written_by__s___s___s___s___s___s___s___s__and__s.","demangled":false,"offset":121496,"size":52,"space":"strings"} +str.Written_by__s___s___s___s___s___s___s__and__s.={"realname":"str.Written_by__s___s___s___s___s___s___s__and__s.","demangled":false,"offset":121448,"size":48,"space":"strings"} +str.Written_by__s___s___s___s___s___s__and__s.={"realname":"str.Written_by__s___s___s___s___s___s__and__s.","demangled":false,"offset":121400,"size":44,"space":"strings"} +str.Written_by__s___s___s___s___s__and__s.={"realname":"str.Written_by__s___s___s___s___s__and__s.","demangled":false,"offset":121360,"size":40,"space":"strings"} +str.Written_by__s___s___s___s__and__s.={"realname":"str.Written_by__s___s___s___s__and__s.","demangled":false,"offset":121320,"size":36,"space":"strings"} +str.Written_by__s___s___s__and__s.={"realname":"str.Written_by__s___s___s__and__s.","demangled":false,"offset":121288,"size":32,"space":"strings"} +str.Written_by__s___s__and__s.={"realname":"str.Written_by__s___s__and__s.","demangled":false,"offset":111869,"size":28,"space":"strings"} +str.Written_by__s_and__s.={"realname":"str.Written_by__s_and__s.","demangled":false,"offset":111846,"size":23,"space":"strings"} +str.Y__m__d={"realname":"str.Y__m__d","demangled":false,"offset":111986,"size":9,"space":"strings"} +str.Y__m__d__H:_M={"realname":"str.Y__m__d__H:_M","demangled":false,"offset":110992,"size":15,"space":"strings"} +str.Y__m__d__H:_M:_S._N__z={"realname":"str.Y__m__d__H:_M:_S._N__z","demangled":false,"offset":110968,"size":24,"space":"strings"} +str.a____all__________________do_not_ignore_entries_starting_with_.____A____almost_all___________do_not_list_implied_._and_.._________author_______________with__l__print_the_author_of_each_file____b____escape_______________print_C_style_escapes_for_nongraphic_characters={"realname":"str.a____all__________________do_not_ignore_entries_starting_with_.____A____almost_all___________do_not_list_implied_._and_.._________author_______________with__l__print_the_author_of_each_file____b____escape_______________print_C_style_escapes_for_nongraphic_characters","demangled":false,"offset":112456,"size":271,"space":"strings"} +str.abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1={"realname":"str.abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1","demangled":false,"offset":120344,"size":44,"space":"strings"} +str.across={"realname":"str.across","demangled":false,"offset":111164,"size":7,"space":"strings"} +str.almost_all={"realname":"str.almost_all","demangled":false,"offset":111425,"size":11,"space":"strings"} +str.ambiguous_argument__s_for__s={"realname":"str.ambiguous_argument__s_for__s","demangled":false,"offset":110265,"size":29,"space":"strings"} +str.and_any_comments_you_want_to_add_after_a_____.={"realname":"str.and_any_comments_you_want_to_add_after_a_____.","demangled":false,"offset":107593,"size":50,"space":"strings"} +str.archives_or_compressed__bright_red={"realname":"str.archives_or_compressed__bright_red","demangled":false,"offset":108054,"size":38,"space":"strings"} +str.are_permitted_provided_the_copyright_notice_and_this_notice_are_preserved.={"realname":"str.are_permitted_provided_the_copyright_notice_and_this_notice_are_preserved.","demangled":false,"offset":104683,"size":77,"space":"strings"} +str.atime={"realname":"str.atime","demangled":false,"offset":111194,"size":6,"space":"strings"} +str.audio_formats={"realname":"str.audio_formats","demangled":false,"offset":109232,"size":16,"space":"strings"} +str.author={"realname":"str.author","demangled":false,"offset":111594,"size":7,"space":"strings"} +str.auto={"realname":"str.auto","demangled":false,"offset":111280,"size":5,"space":"strings"} +str.b__e__H:_M={"realname":"str.b__e__H:_M","demangled":false,"offset":111802,"size":12,"space":"strings"} +str.b__e___Y={"realname":"str.b__e___Y","demangled":false,"offset":111792,"size":10,"space":"strings"} +str.backup_files={"realname":"str.backup_files","demangled":false,"offset":109481,"size":15,"space":"strings"} +str.birth={"realname":"str.birth","demangled":false,"offset":111236,"size":6,"space":"strings"} +str.block_size={"realname":"str.block_size","demangled":false,"offset":111575,"size":11,"space":"strings"} +str.block_size_SIZE______with__l__scale_sizes_by_SIZE_when_printing_them_______________________________e.g._____block_size_M___see_SIZE_format_below={"realname":"str.block_size_SIZE______with__l__scale_sizes_by_SIZE_when_printing_them_______________________________e.g._____block_size_M___see_SIZE_format_below","demangled":false,"offset":112728,"size":155,"space":"strings"} +str.c_________________________with__lt:_sort_by__and_show__ctime__time_of_last______________________________change_of_file_status_information________________________________with__l:_show_ctime_and_sort_by_name_______________________________otherwise:_sort_by_ctime__newest_first={"realname":"str.c_________________________with__lt:_sort_by__and_show__ctime__time_of_last______________________________change_of_file_status_information________________________________with__l:_show_ctime_and_sort_by_name_______________________________otherwise:_sort_by_ctime__newest_first","demangled":false,"offset":112960,"size":280,"space":"strings"} +str.c_maybe={"realname":"str.c_maybe","demangled":false,"offset":111709,"size":8,"space":"strings"} +str.cannot_access__s={"realname":"str.cannot_access__s","demangled":false,"offset":112069,"size":17,"space":"strings"} +str.cannot_determine_device_and_inode_of__s={"realname":"str.cannot_determine_device_and_inode_of__s","demangled":false,"offset":120160,"size":40,"space":"strings"} +str.cannot_open_directory__s={"realname":"str.cannot_open_directory__s","demangled":false,"offset":110456,"size":25,"space":"strings"} +str.cannot_read_symbolic_link__s={"realname":"str.cannot_read_symbolic_link__s","demangled":false,"offset":112110,"size":29,"space":"strings"} +str.classify={"realname":"str.classify","demangled":false,"offset":110684,"size":11,"space":"strings"} +str.clocale={"realname":"str.clocale","demangled":false,"offset":111717,"size":8,"space":"strings"} +str.closing_directory__s={"realname":"str.closing_directory__s","demangled":false,"offset":110526,"size":21,"space":"strings"} +str.color={"realname":"str.color","demangled":false,"offset":110735,"size":8,"space":"strings"} +str.commas={"realname":"str.commas","demangled":false,"offset":111146,"size":7,"space":"strings"} +str.config_specific_to_those_matching_environment_variables.={"realname":"str.config_specific_to_those_matching_environment_variables.","demangled":false,"offset":109838,"size":59,"space":"strings"} +str.context={"realname":"str.context","demangled":false,"offset":111586,"size":8,"space":"strings"} +str.creation={"realname":"str.creation","demangled":false,"offset":111242,"size":9,"space":"strings"} +str.ctime={"realname":"str.ctime","demangled":false,"offset":111204,"size":6,"space":"strings"} +str.dereference={"realname":"str.dereference","demangled":false,"offset":111491,"size":12,"space":"strings"} +str.dereference_command_line={"realname":"str.dereference_command_line","demangled":false,"offset":111454,"size":25,"space":"strings"} +str.dereference_command_line_symlink_to_dir={"realname":"str.dereference_command_line_symlink_to_dir","demangled":false,"offset":120968,"size":40,"space":"strings"} +str.dereference_command_line_symlink_to_dir______________________________follow_each_command_line_symbolic_link______________________________that_points_to_a_directory={"realname":"str.dereference_command_line_symlink_to_dir______________________________follow_each_command_line_symbolic_link______________________________that_points_to_a_directory","demangled":false,"offset":114600,"size":174,"space":"strings"} +str.dev_ino_pop={"realname":"str.dev_ino_pop","demangled":false,"offset":109904,"size":12,"space":"strings"} +str.dev_ino_size______extension______struct_obstack_const____o_____dev_ino_obstack____size_t_____o__next_free_____o__object_base={"realname":"str.dev_ino_size______extension______struct_obstack_const____o_____dev_ino_obstack____size_t_____o__next_free_____o__object_base","demangled":false,"offset":120744,"size":130,"space":"strings"} +str.directory={"realname":"str.directory","demangled":false,"offset":111292,"size":10,"space":"strings"} +str.dired={"realname":"str.dired","demangled":false,"offset":111302,"size":6,"space":"strings"} +str.dired_and___zero_are_incompatible={"realname":"str.dired_and___zero_are_incompatible","demangled":false,"offset":120592,"size":36,"space":"strings"} +str.eEgGkKmMpPtTyYzZ0={"realname":"str.eEgGkKmMpPtTyYzZ0","demangled":false,"offset":111923,"size":18,"space":"strings"} +str.error_canonicalizing__s={"realname":"str.error_canonicalizing__s","demangled":false,"offset":110481,"size":24,"space":"strings"} +str.executable_bit_actually_set.={"realname":"str.executable_bit_actually_set.","demangled":false,"offset":108000,"size":31,"space":"strings"} +str.extension={"realname":"str.extension","demangled":false,"offset":111251,"size":10,"space":"strings"} +str.f_________________________list_all_entries_in_directory_order____F____classify__WHEN_______append_indicator__one_of_________to_entries_WHEN_________file_type____________likewise__except_do_not_append={"realname":"str.f_________________________list_all_entries_in_directory_order____F____classify__WHEN_______append_indicator__one_of_________to_entries_WHEN_________file_type____________likewise__except_do_not_append","demangled":false,"offset":113520,"size":208,"space":"strings"} +str.fff={"realname":"str.fff","demangled":false,"offset":102407,"size":6,"space":"strings"} +str.file_type={"realname":"str.file_type","demangled":false,"offset":111123,"size":10,"space":"strings"} +str.force={"realname":"str.force","demangled":false,"offset":111265,"size":6,"space":"strings"} +str.format={"realname":"str.format","demangled":false,"offset":110726,"size":9,"space":"strings"} +str.format_WORD__________across__x__commas__m__horizontal__x__long__l_______________________________single_column__1__verbose__l__vertical__C={"realname":"str.format_WORD__________across__x__commas__m__horizontal__x__long__l_______________________________single_column__1__verbose__l__vertical__C","demangled":false,"offset":113728,"size":148,"space":"strings"} +str.found={"realname":"str.found","demangled":false,"offset":111074,"size":6,"space":"strings"} +str.full_iso={"realname":"str.full_iso","demangled":false,"offset":110612,"size":9,"space":"strings"} +str.full_time={"realname":"str.full_time","demangled":false,"offset":111308,"size":10,"space":"strings"} +str.full_time____________like__l___time_style_full_iso={"realname":"str.full_time____________like__l___time_style_full_iso","demangled":false,"offset":113880,"size":60,"space":"strings"} +str.g_________________________like__l__but_do_not_list_owner={"realname":"str.g_________________________like__l__but_do_not_list_owner","demangled":false,"offset":113944,"size":61,"space":"strings"} +str.group_directories_first={"realname":"str.group_directories_first","demangled":false,"offset":111318,"size":24,"space":"strings"} +str.group_directories_first______________________________group_directories_before_files_______________________________can_be_augmented_with_a___sort_option__but_any______________________________use_of___sort_none___U__disables_grouping={"realname":"str.group_directories_first______________________________group_directories_before_files_______________________________can_be_augmented_with_a___sort_option__but_any______________________________use_of___sort_none___U__disables_grouping","demangled":false,"offset":114008,"size":242,"space":"strings"} +str.h____human_readable_______with__l_and__s__print_sizes_like_1K_234M_2G_etc._________si___________________likewise__but_use_powers_of_1000_not_1024={"realname":"str.h____human_readable_______with__l_and__s__print_sizes_like_1K_234M_2G_etc._________si___________________likewise__but_use_powers_of_1000_not_1024","demangled":false,"offset":114336,"size":150,"space":"strings"} +str.hash_get_n_entries__active_dir_set_____0={"realname":"str.hash_get_n_entries__active_dir_set_____0","demangled":false,"offset":120920,"size":41,"space":"strings"} +str.help={"realname":"str.help","demangled":false,"offset":111601,"size":5,"space":"strings"} +str.help________display_this_help_and_exit={"realname":"str.help________display_this_help_and_exit","demangled":false,"offset":118760,"size":48,"space":"strings"} +str.hide={"realname":"str.hide","demangled":false,"offset":111479,"size":5,"space":"strings"} +str.hide_PATTERN_________do_not_list_implied_entries_matching_shell_PATTERN_______________________________overridden_by__a_or__A={"realname":"str.hide_PATTERN_________do_not_list_implied_entries_matching_shell_PATTERN_______________________________overridden_by__a_or__A","demangled":false,"offset":114776,"size":136,"space":"strings"} +str.hide_control_chars={"realname":"str.hide_control_chars","demangled":false,"offset":111398,"size":19,"space":"strings"} +str.horizontal={"realname":"str.horizontal","demangled":false,"offset":111153,"size":11,"space":"strings"} +str.https:__gnu.org_licenses_gpl.html={"realname":"str.https:__gnu.org_licenses_gpl.html","demangled":false,"offset":121184,"size":34,"space":"strings"} +str.https:__wiki.xiph.org_MIME_Types_and_File_Extensions={"realname":"str.https:__wiki.xiph.org_MIME_Types_and_File_Extensions","demangled":false,"offset":109380,"size":55,"space":"strings"} +str.https:__www.gnu.org_software_coreutils={"realname":"str.https:__www.gnu.org_software_coreutils","demangled":false,"offset":119992,"size":40,"space":"strings"} +str.human_readable={"realname":"str.human_readable","demangled":false,"offset":111342,"size":15,"space":"strings"} +str.hyperlink={"realname":"str.hyperlink","demangled":false,"offset":110743,"size":12,"space":"strings"} +str.hyperlink__WHEN______hyperlink_file_names_WHEN={"realname":"str.hyperlink__WHEN______hyperlink_file_names_WHEN","demangled":false,"offset":114912,"size":56,"space":"strings"} +str.i____inode________________print_the_index_number_of_each_file____I____ignore_PATTERN_______do_not_list_implied_entries_matching_shell_PATTERN={"realname":"str.i____inode________________print_the_index_number_of_each_file____I____ignore_PATTERN_______do_not_list_implied_entries_matching_shell_PATTERN","demangled":false,"offset":115208,"size":146,"space":"strings"} +str.if_tty={"realname":"str.if_tty","demangled":false,"offset":111285,"size":7,"space":"strings"} +str.ignore={"realname":"str.ignore","demangled":false,"offset":111484,"size":7,"space":"strings"} +str.ignore_backups={"realname":"str.ignore_backups","demangled":false,"offset":111436,"size":15,"space":"strings"} +str.ignoring_invalid_tab_size_in_environment_variable_TABSIZE:__s={"realname":"str.ignoring_invalid_tab_size_in_environment_variable_TABSIZE:__s","demangled":false,"offset":120456,"size":62,"space":"strings"} +str.ignoring_invalid_value_of_environment_variable_QUOTING_STYLE:__s={"realname":"str.ignoring_invalid_value_of_environment_variable_QUOTING_STYLE:__s","demangled":false,"offset":120520,"size":65,"space":"strings"} +str.ignoring_invalid_width_in_environment_variable_COLUMNS:__s={"realname":"str.ignoring_invalid_width_in_environment_variable_COLUMNS:__s","demangled":false,"offset":120392,"size":59,"space":"strings"} +str.image_formats={"realname":"str.image_formats","demangled":false,"offset":108592,"size":16,"space":"strings"} +str.indicator_style={"realname":"str.indicator_style","demangled":false,"offset":110755,"size":18,"space":"strings"} +str.indicator_style_WORD______________________________append_indicator_with_style_WORD_to_entry_names:______________________________none__default___slash___p________________________________file_type____file_type___classify___F={"realname":"str.indicator_style_WORD______________________________append_indicator_with_style_WORD_to_entry_names:______________________________none__default___slash___p________________________________file_type____file_type___classify___F","demangled":false,"offset":114968,"size":234,"space":"strings"} +str.init_strings_for_separate_cases__those_will_be_honored.={"realname":"str.init_strings_for_separate_cases__those_will_be_honored.","demangled":false,"offset":107714,"size":58,"space":"strings"} +str.inode={"realname":"str.inode","demangled":false,"offset":111357,"size":6,"space":"strings"} +str.invalid__s_s_argument___s={"realname":"str.invalid__s_s_argument___s","demangled":false,"offset":110553,"size":27,"space":"strings"} +str.invalid_argument__s_for__s={"realname":"str.invalid_argument__s_for__s","demangled":false,"offset":110238,"size":27,"space":"strings"} +str.invalid_line_width={"realname":"str.invalid_line_width","demangled":false,"offset":110654,"size":19,"space":"strings"} +str.invalid_suffix_in__s_s_argument___s={"realname":"str.invalid_suffix_in__s_s_argument___s","demangled":false,"offset":120248,"size":37,"space":"strings"} +str.invalid_tab_size={"realname":"str.invalid_tab_size","demangled":false,"offset":110695,"size":17,"space":"strings"} +str.invalid_time_style_format__s={"realname":"str.invalid_time_style_format__s","demangled":false,"offset":110890,"size":29,"space":"strings"} +str.k____kibibytes____________default_to_1024_byte_blocks_for_file_system_usage_______________________________used_only_with__s_and_per_directory_totals={"realname":"str.k____kibibytes____________default_to_1024_byte_blocks_for_file_system_usage_______________________________used_only_with__s_and_per_directory_totals","demangled":false,"offset":115360,"size":154,"space":"strings"} +str.kibibytes={"realname":"str.kibibytes","demangled":false,"offset":111363,"size":10,"space":"strings"} +str.l_________________________use_a_long_listing_format={"realname":"str.l_________________________use_a_long_listing_format","demangled":false,"offset":115520,"size":56,"space":"strings"} +str.ld={"realname":"str.ld","demangled":false,"offset":110016,"size":5,"space":"strings"} +str.literal={"realname":"str.literal","demangled":false,"offset":111503,"size":8,"space":"strings"} +str.long={"realname":"str.long","demangled":false,"offset":111141,"size":5,"space":"strings"} +str.long_iso={"realname":"str.long_iso","demangled":false,"offset":111103,"size":9,"space":"strings"} +str.lu={"realname":"str.lu","demangled":false,"offset":110220,"size":6,"space":"strings"} +str.m_________________________fill_width_with_a_comma_separated_list_of_entries={"realname":"str.m_________________________fill_width_with_a_comma_separated_list_of_entries","demangled":false,"offset":115800,"size":80,"space":"strings"} +str.m__d__y={"realname":"str.m__d__y","demangled":false,"offset":111977,"size":9,"space":"strings"} +str.main={"realname":"str.main","demangled":false,"offset":109916,"size":5,"space":"strings"} +str.memory_exhausted={"realname":"str.memory_exhausted","demangled":false,"offset":110203,"size":17,"space":"strings"} +str.modification={"realname":"str.modification","demangled":false,"offset":111223,"size":13,"space":"strings"} +str.mtime={"realname":"str.mtime","demangled":false,"offset":111217,"size":6,"space":"strings"} +str.n____numeric_uid_gid______like__l__but_list_numeric_user_and_group_IDs____N____literal______________print_entry_names_without_quoting____o_________________________like__l__but_do_not_list_group_information____p____indicator_style_slash______________________________append___indicator_to_directories={"realname":"str.n____numeric_uid_gid______like__l__but_list_numeric_user_and_group_IDs____N____literal______________print_entry_names_without_quoting____o_________________________like__l__but_do_not_list_group_information____p____indicator_style_slash______________________________append___indicator_to_directories","demangled":false,"offset":115880,"size":303,"space":"strings"} +str.never={"realname":"str.never","demangled":false,"offset":111271,"size":6,"space":"strings"} +str.no_group={"realname":"str.no_group","demangled":false,"offset":111389,"size":9,"space":"strings"} +str.none={"realname":"str.none","demangled":false,"offset":111112,"size":5,"space":"strings"} +str.numeric_uid_gid={"realname":"str.numeric_uid_gid","demangled":false,"offset":111373,"size":16,"space":"strings"} +str.numerical_value__the_color_is_as_for_the_file_pointed_to.={"realname":"str.numerical_value__the_color_is_as_for_the_file_pointed_to.","demangled":false,"offset":106497,"size":62,"space":"strings"} +str.or_available_locally_via:_info___coreutils___s_s={"realname":"str.or_available_locally_via:_info___coreutils___s_s","demangled":false,"offset":120104,"size":51,"space":"strings"} +str.pcdb_lswd={"realname":"str.pcdb_lswd","demangled":false,"offset":104008,"size":11,"space":"strings"} +str.posix={"realname":"str.posix","demangled":false,"offset":104144,"size":7,"space":"strings"} +str.posix___s={"realname":"str.posix___s","demangled":false,"offset":110952,"size":16,"space":"strings"} +str.q____hide_control_chars___print___instead_of_nongraphic_characters={"realname":"str.q____hide_control_chars___print___instead_of_nongraphic_characters","demangled":false,"offset":116184,"size":71,"space":"strings"} +str.quote_name={"realname":"str.quote_name","demangled":false,"offset":111511,"size":11,"space":"strings"} +str.quoting_style={"realname":"str.quoting_style","demangled":false,"offset":110773,"size":16,"space":"strings"} +str.quoting_style_WORD___use_quoting_style_WORD_for_entry_names:______________________________literal__locale__shell__shell_always_______________________________shell_escape__shell_escape_always__c__escape_______________________________overrides_QUOTING_STYLE_environment_variable={"realname":"str.quoting_style_WORD___use_quoting_style_WORD_for_entry_names:______________________________literal__locale__shell__shell_always_______________________________shell_escape__shell_escape_always__c__escape_______________________________overrides_QUOTING_STYLE_environment_variable","demangled":false,"offset":116488,"size":288,"space":"strings"} +str.r____reverse______________reverse_order_while_sorting____R____recursive____________list_subdirectories_recursively____s____size_________________print_the_allocated_size_of_each_file__in_blocks={"realname":"str.r____reverse______________reverse_order_while_sorting____R____recursive____________list_subdirectories_recursively____s____size_________________print_the_allocated_size_of_each_file__in_blocks","demangled":false,"offset":116776,"size":197,"space":"strings"} +str.reading_directory__s={"realname":"str.reading_directory__s","demangled":false,"offset":110505,"size":21,"space":"strings"} +str.recursive={"realname":"str.recursive","demangled":false,"offset":111522,"size":10,"space":"strings"} +str.restrict_following_config_to_systems_with_matching_environment_variables.={"realname":"str.restrict_following_config_to_systems_with_matching_environment_variables.","demangled":false,"offset":105190,"size":76,"space":"strings"} +str.reverse={"realname":"str.reverse","demangled":false,"offset":111417,"size":8,"space":"strings"} +str.s={"realname":"str.s","demangled":false,"offset":111972,"size":5,"space":"strings"} +str.s:__s={"realname":"str.s:__s","demangled":false,"offset":110673,"size":7,"space":"strings"} +str.s:_not_listing_already_listed_directory={"realname":"str.s:_not_listing_already_listed_directory","demangled":false,"offset":120200,"size":41,"space":"strings"} +str.s____s={"realname":"str.s____s","demangled":false,"offset":110441,"size":10,"space":"strings"} +str.s___s={"realname":"str.s___s","demangled":false,"offset":110430,"size":8,"space":"strings"} +str.s___s___s={"realname":"str.s___s___s","demangled":false,"offset":111814,"size":12,"space":"strings"} +str.s_online_help:___s={"realname":"str.s_online_help:___s","demangled":false,"offset":110135,"size":23,"space":"strings"} +str.s_s_argument___s__too_large={"realname":"str.s_s_argument___s__too_large","demangled":false,"offset":110580,"size":29,"space":"strings"} +str.sha224sum={"realname":"str.sha224sum","demangled":false,"offset":110095,"size":10,"space":"strings"} +str.sha256sum={"realname":"str.sha256sum","demangled":false,"offset":110105,"size":10,"space":"strings"} +str.sha2_utilities={"realname":"str.sha2_utilities","demangled":false,"offset":110042,"size":15,"space":"strings"} +str.sha384sum={"realname":"str.sha384sum","demangled":false,"offset":110115,"size":10,"space":"strings"} +str.sha512sum={"realname":"str.sha512sum","demangled":false,"offset":110125,"size":10,"space":"strings"} +str.shell={"realname":"str.shell","demangled":false,"offset":111657,"size":6,"space":"strings"} +str.shell_always={"realname":"str.shell_always","demangled":false,"offset":111663,"size":13,"space":"strings"} +str.shell_escape={"realname":"str.shell_escape","demangled":false,"offset":111676,"size":13,"space":"strings"} +str.shell_escape_always={"realname":"str.shell_escape_always","demangled":false,"offset":111689,"size":20,"space":"strings"} +str.show_control_chars={"realname":"str.show_control_chars","demangled":false,"offset":111532,"size":19,"space":"strings"} +str.show_control_chars___show_nongraphic_characters_as_is__the_default_______________________________unless_program_is__ls__and_output_is_a_terminal={"realname":"str.show_control_chars___show_nongraphic_characters_as_is__the_default_______________________________unless_program_is__ls__and_output_is_a_terminal","demangled":false,"offset":116256,"size":156,"space":"strings"} +str.single_column={"realname":"str.single_column","demangled":false,"offset":111180,"size":14,"space":"strings"} +str.slackware_version_of_dircolors__are_recognized_but_ignored.={"realname":"str.slackware_version_of_dircolors__are_recognized_but_ignored.","demangled":false,"offset":104822,"size":62,"space":"strings"} +str.slash={"realname":"str.slash","demangled":false,"offset":111117,"size":6,"space":"strings"} +str.sort={"realname":"str.sort","demangled":false,"offset":110712,"size":7,"space":"strings"} +str.sort_WORD____________sort_by_WORD_instead_of_name:_none___U___size___S________________________________time___t___version___v___extension___X___width={"realname":"str.sort_WORD____________sort_by_WORD_instead_of_name:_none___U___size___S________________________________time___t___version___v___extension___X___width","demangled":false,"offset":117040,"size":159,"space":"strings"} +str.sort_files={"realname":"str.sort_files","demangled":false,"offset":104024,"size":11,"space":"strings"} +str.sort_type____sort_version={"realname":"str.sort_type____sort_version","demangled":false,"offset":110364,"size":26,"space":"strings"} +str.status={"realname":"str.status","demangled":false,"offset":111210,"size":7,"space":"strings"} +str.system.nfs4_acl={"realname":"str.system.nfs4_acl","demangled":false,"offset":112004,"size":16,"space":"strings"} +str.system.posix_acl_access={"realname":"str.system.posix_acl_access","demangled":false,"offset":112020,"size":24,"space":"strings"} +str.system.posix_acl_default={"realname":"str.system.posix_acl_default","demangled":false,"offset":112044,"size":25,"space":"strings"} +str.t_________________________sort_by_time__newest_first__see___time____T____tabsize_COLS_________assume_tab_stops_at_each_COLS_instead_of_8={"realname":"str.t_________________________sort_by_time__newest_first__see___time____T____tabsize_COLS_________assume_tab_stops_at_each_COLS_instead_of_8","demangled":false,"offset":117824,"size":141,"space":"strings"} +str.tabsize={"realname":"str.tabsize","demangled":false,"offset":111551,"size":8,"space":"strings"} +str.target={"realname":"str.target","demangled":false,"offset":111067,"size":7,"space":"strings"} +str.test_invocation={"realname":"str.test_invocation","demangled":false,"offset":110057,"size":16,"space":"strings"} +str.time={"realname":"str.time","demangled":false,"offset":110719,"size":7,"space":"strings"} +str.time_WORD____________select_which_timestamp_used_to_display_or_sort_________________________________access_time___u_:_atime__access__use_________________________________metadata_change_time___c_:_ctime__status_________________________________modified_time__default_:_mtime__modification_________________________________birth_time:_birth__creation_______________________________with__l__WORD_determines_which_time_to_show_______________________________with___sort_time__sort_by_WORD__newest_first={"realname":"str.time_WORD____________select_which_timestamp_used_to_display_or_sort_________________________________access_time___u_:_atime__access__use_________________________________metadata_change_time___c_:_ctime__status_________________________________modified_time__default_:_mtime__modification_________________________________birth_time:_birth__creation_______________________________with__l__WORD_determines_which_time_to_show_______________________________with___sort_time__sort_by_WORD__newest_first","demangled":false,"offset":117200,"size":507,"space":"strings"} +str.time_style={"realname":"str.time_style","demangled":false,"offset":111559,"size":11,"space":"strings"} +str.time_style_TIME_STYLE______________________________time_date_format_with__l__see_TIME_STYLE_below={"realname":"str.time_style_TIME_STYLE______________________________time_date_format_with__l__see_TIME_STYLE_below","demangled":false,"offset":117712,"size":107,"space":"strings"} +str.to_color_below._Put_the_suffix__a_space__and_the_color_init_string.={"realname":"str.to_color_below._Put_the_suffix__a_space__and_the_color_init_string.","demangled":false,"offset":107523,"size":70,"space":"strings"} +str.total={"realname":"str.total","demangled":false,"offset":110547,"size":6,"space":"strings"} +str.u_________________________with__lt:_sort_by__and_show__access_time_______________________________with__l:_show_access_time_and_sort_by_name_______________________________otherwise:_sort_by_access_time__newest_first={"realname":"str.u_________________________with__lt:_sort_by__and_show__access_time_______________________________with__l:_show_access_time_and_sort_by_name_______________________________otherwise:_sort_by_access_time__newest_first","demangled":false,"offset":117968,"size":220,"space":"strings"} +str.unlabeled={"realname":"str.unlabeled","demangled":false,"offset":110339,"size":10,"space":"strings"} +str.unparsable_value_for_LS_COLORS_environment_variable={"realname":"str.unparsable_value_for_LS_COLORS_environment_variable","demangled":false,"offset":120688,"size":52,"space":"strings"} +str.unrecognized_prefix:__s={"realname":"str.unrecognized_prefix:__s","demangled":false,"offset":111043,"size":24,"space":"strings"} +str.usr_share_locale={"realname":"str.usr_share_locale","demangled":false,"offset":110636,"size":18,"space":"strings"} +str.v_________________________natural_sort_of__version__numbers_within_text={"realname":"str.v_________________________natural_sort_of__version__numbers_within_text","demangled":false,"offset":118272,"size":76,"space":"strings"} +str.verbose={"realname":"str.verbose","demangled":false,"offset":111133,"size":8,"space":"strings"} +str.version_____output_version_information_and_exit={"realname":"str.version_____output_version_information_and_exit","demangled":false,"offset":118808,"size":57,"space":"strings"} +str.vertical={"realname":"str.vertical","demangled":false,"offset":111171,"size":9,"space":"strings"} +str.w____width_COLS___________set_output_width_to_COLS.__0_means_no_limit____x_________________________list_entries_by_lines_instead_of_by_columns____X_________________________sort_alphabetically_by_entry_extension____Z____context______________print_any_security_context_of_each_file_________zero_________________end_each_output_line_with_NUL__not_newline____1_________________________list_one_file_per_line={"realname":"str.w____width_COLS___________set_output_width_to_COLS.__0_means_no_limit____x_________________________list_entries_by_lines_instead_of_by_columns____X_________________________sort_alphabetically_by_entry_extension____Z____context______________print_any_security_context_of_each_file_________zero_________________end_each_output_line_with_NUL__not_newline____1_________________________list_one_file_per_line","demangled":false,"offset":118352,"size":408,"space":"strings"} +str.with_some_additional_attributes_as_per_the_following_codes:={"realname":"str.with_some_additional_attributes_as_per_the_following_codes:","demangled":false,"offset":105954,"size":62,"space":"strings"} +str.write_error={"realname":"str.write_error","demangled":false,"offset":110226,"size":12,"space":"strings"} +str.zero={"realname":"str.zero","demangled":false,"offset":111570,"size":5,"space":"strings"} +sym.__argmatch_die={"realname":"__argmatch_die","demangled":false,"offset":35920,"size":18,"space":"symbols"} +sym.__do_global_dtors_aux={"realname":"__do_global_dtors_aux","demangled":false,"offset":24464,"size":0,"space":"symbols"} +sym.__strftime_internal.isra.0={"realname":"__strftime_internal.isra.0","demangled":false,"offset":83408,"size":8650,"space":"symbols"} +sym.__xargmatch_internal.constprop.0={"realname":"__xargmatch_internal.constprop.0","demangled":false,"offset":80784,"size":347,"space":"symbols"} +sym._fini={"realname":"_fini","demangled":false,"offset":102244,"size":0,"space":"symbols"} +sym._init={"realname":"_init","demangled":false,"offset":12288,"size":0,"space":"symbols"} +sym._obstack_allocated_p={"realname":"_obstack_allocated_p","demangled":false,"offset":54256,"size":55,"space":"symbols"} +sym._obstack_begin={"realname":"_obstack_begin","demangled":false,"offset":45104,"size":32,"space":"symbols"} +sym._obstack_begin_1={"realname":"_obstack_begin_1","demangled":false,"offset":53792,"size":36,"space":"symbols"} +sym._obstack_begin_worker.isra.0={"realname":"_obstack_begin_worker.isra.0","demangled":false,"offset":83216,"size":177,"space":"symbols"} +sym._obstack_free={"realname":"_obstack_free","demangled":false,"offset":54320,"size":142,"space":"symbols"} +sym._obstack_free.cold={"realname":"_obstack_free.cold","demangled":false,"offset":15956,"size":5,"space":"symbols"} +sym._obstack_memory_used={"realname":"_obstack_memory_used","demangled":false,"offset":54464,"size":54,"space":"symbols"} +sym._obstack_newchunk={"realname":"_obstack_newchunk","demangled":false,"offset":53840,"size":321,"space":"symbols"} +sym._start={"realname":"_start","demangled":false,"offset":24304,"size":38,"space":"symbols"} +sym.abformat_init={"realname":"abformat_init","demangled":false,"offset":29696,"size":2285,"space":"symbols"} +sym.add_ignore_pattern={"realname":"add_ignore_pattern","demangled":false,"offset":55856,"size":60,"space":"symbols"} +sym.argmatch.constprop.0={"realname":"argmatch.constprop.0","demangled":false,"offset":71232,"size":238,"space":"symbols"} +sym.argmatch_invalid={"realname":"argmatch_invalid","demangled":false,"offset":46208,"size":211,"space":"symbols"} +sym.atexit={"realname":"atexit","demangled":false,"offset":102224,"size":18,"space":"symbols"} +sym.c_strncasecmp.part.0={"realname":"c_strncasecmp.part.0","demangled":false,"offset":28528,"size":127,"space":"symbols"} +sym.calc_req_mask.lto_priv.0={"realname":"calc_req_mask.lto_priv.0","demangled":false,"offset":44304,"size":193,"space":"symbols"} +sym.calc_req_mask.lto_priv.0.cold={"realname":"calc_req_mask.lto_priv.0.cold","demangled":false,"offset":15951,"size":0,"space":"symbols"} +sym.calculate_columns={"realname":"calculate_columns","demangled":false,"offset":59456,"size":719,"space":"symbols"} +sym.canonicalize_filename_mode.constprop.0={"realname":"canonicalize_filename_mode.constprop.0","demangled":false,"offset":92640,"size":2832,"space":"symbols"} +sym.canonicalize_filename_mode.constprop.0.cold={"realname":"canonicalize_filename_mode.constprop.0.cold","demangled":false,"offset":15966,"size":5,"space":"symbols"} +sym.check_tuning.lto_priv.0={"realname":"check_tuning.lto_priv.0","demangled":false,"offset":48192,"size":134,"space":"symbols"} +sym.clear_files={"realname":"clear_files","demangled":false,"offset":37280,"size":251,"space":"symbols"} +sym.clone_quoting_options.constprop.0={"realname":"clone_quoting_options.constprop.0","demangled":false,"offset":71136,"size":96,"space":"symbols"} +sym.close_stdout={"realname":"close_stdout","demangled":false,"offset":44160,"size":132,"space":"symbols"} +sym.close_stream={"realname":"close_stream","demangled":false,"offset":44048,"size":102,"space":"symbols"} +sym.cmp_extension={"realname":"cmp_extension","demangled":false,"offset":36768,"size":121,"space":"symbols"} +sym.compute_bucket_size.isra.0={"realname":"compute_bucket_size.isra.0","demangled":false,"offset":92064,"size":306,"space":"symbols"} +sym.decode_line_length={"realname":"decode_line_length","demangled":false,"offset":33536,"size":100,"space":"symbols"} +sym.deregister_tm_clones={"realname":"deregister_tm_clones","demangled":false,"offset":24352,"size":0,"space":"symbols"} +sym.dev_ino_compare={"realname":"dev_ino_compare","demangled":false,"offset":24592,"size":28,"space":"symbols"} +sym.dev_ino_free={"realname":"dev_ino_free","demangled":false,"offset":24688,"size":9,"space":"symbols"} +sym.dev_ino_hash={"realname":"dev_ino_hash","demangled":false,"offset":24576,"size":16,"space":"symbols"} +sym.dired_dump_obstack={"realname":"dired_dump_obstack","demangled":false,"offset":29440,"size":242,"space":"symbols"} +sym.dired_outbuf={"realname":"dired_outbuf","demangled":false,"offset":29408,"size":30,"space":"symbols"} +sym.do_statx.lto_priv.0={"realname":"do_statx.lto_priv.0","demangled":false,"offset":44512,"size":466,"space":"symbols"} +sym.extract_dirs_from_files={"realname":"extract_dirs_from_files","demangled":false,"offset":66288,"size":1104,"space":"symbols"} +sym.file_escape={"realname":"file_escape","demangled":false,"offset":56784,"size":357,"space":"symbols"} +sym.file_failure.lto_priv.0={"realname":"file_failure.lto_priv.0","demangled":false,"offset":45136,"size":171,"space":"symbols"} +sym.file_prefixlen.lto_priv.0={"realname":"file_prefixlen.lto_priv.0","demangled":false,"offset":46432,"size":218,"space":"symbols"} +sym.filenvercmp.constprop.0={"realname":"filenvercmp.constprop.0","demangled":false,"offset":73216,"size":393,"space":"symbols"} +sym.format_user_or_group={"realname":"format_user_or_group","demangled":false,"offset":41696,"size":196,"space":"symbols"} +sym.format_user_width.lto_priv.0={"realname":"format_user_width.lto_priv.0","demangled":false,"offset":60368,"size":108,"space":"symbols"} +sym.frame_dummy={"realname":"frame_dummy","demangled":false,"offset":24528,"size":0,"space":"symbols"} +sym.get_funky_string={"realname":"get_funky_string","demangled":false,"offset":24704,"size":629,"space":"symbols"} +sym.get_type_indicator.lto_priv.0={"realname":"get_type_indicator.lto_priv.0","demangled":false,"offset":45488,"size":273,"space":"symbols"} +sym.getgroup={"realname":"getgroup","demangled":false,"offset":60480,"size":177,"space":"symbols"} +sym.gettext_quote.part.0.lto_priv.0={"realname":"gettext_quote.part.0.lto_priv.0","demangled":false,"offset":54528,"size":249,"space":"symbols"} +sym.getuser={"realname":"getuser","demangled":false,"offset":60176,"size":177,"space":"symbols"} +sym.gl_scratch_buffer_grow_preserve={"realname":"gl_scratch_buffer_grow_preserve","demangled":false,"offset":47744,"size":170,"space":"symbols"} +sym.gobble_file.constprop.0={"realname":"gobble_file.constprop.0","demangled":false,"offset":95472,"size":6099,"space":"symbols"} +sym.hard_locale={"realname":"hard_locale","demangled":false,"offset":47920,"size":271,"space":"symbols"} +sym.hash_find_entry={"realname":"hash_find_entry","demangled":false,"offset":36032,"size":305,"space":"symbols"} +sym.hash_find_entry.cold={"realname":"hash_find_entry.cold","demangled":false,"offset":15936,"size":5,"space":"symbols"} +sym.hash_free={"realname":"hash_free","demangled":false,"offset":48336,"size":276,"space":"symbols"} +sym.hash_initialize.constprop.0={"realname":"hash_initialize.constprop.0","demangled":false,"offset":92384,"size":247,"space":"symbols"} +sym.hash_insert_if_absent={"realname":"hash_insert_if_absent","demangled":false,"offset":48624,"size":553,"space":"symbols"} +sym.hash_insert_if_absent.cold={"realname":"hash_insert_if_absent.cold","demangled":false,"offset":15951,"size":5,"space":"symbols"} +sym.hash_rehash={"realname":"hash_rehash","demangled":false,"offset":43360,"size":394,"space":"symbols"} +sym.hash_rehash.cold={"realname":"hash_rehash.cold","demangled":false,"offset":15946,"size":5,"space":"symbols"} +sym.human_options.constprop.0={"realname":"human_options.constprop.0","demangled":false,"offset":72736,"size":475,"space":"symbols"} +sym.human_readable={"realname":"human_readable","demangled":false,"offset":49184,"size":3530,"space":"symbols"} +sym.imp.__assert_fail={"realname":"__assert_fail","demangled":false,"offset":14832,"size":16,"space":"imports"} +sym.imp.__ctype_b_loc={"realname":"__ctype_b_loc","demangled":false,"offset":15856,"size":16,"space":"imports"} +sym.imp.__ctype_get_mb_cur_max={"realname":"__ctype_get_mb_cur_max","demangled":false,"offset":14624,"size":16,"space":"imports"} +sym.imp.__ctype_tolower_loc={"realname":"__ctype_tolower_loc","demangled":false,"offset":15840,"size":16,"space":"imports"} +sym.imp.__ctype_toupper_loc={"realname":"__ctype_toupper_loc","demangled":false,"offset":14112,"size":16,"space":"imports"} +sym.imp.__cxa_atexit={"realname":"__cxa_atexit","demangled":false,"offset":15600,"size":16,"space":"imports"} +sym.imp.__cxa_finalize={"realname":"__cxa_finalize","demangled":false,"offset":15808,"size":16,"space":"imports"} +sym.imp.__errno_location={"realname":"__errno_location","demangled":false,"offset":14256,"size":16,"space":"imports"} +sym.imp.__fpending={"realname":"__fpending","demangled":false,"offset":14336,"size":16,"space":"imports"} +sym.imp.__fprintf_chk={"realname":"__fprintf_chk","demangled":false,"offset":15712,"size":16,"space":"imports"} +sym.imp.__freading={"realname":"__freading","demangled":false,"offset":15344,"size":16,"space":"imports"} +sym.imp.__isoc23_strtoumax={"realname":"__isoc23_strtoumax","demangled":false,"offset":15168,"size":16,"space":"imports"} +sym.imp.__mbstowcs_chk={"realname":"__mbstowcs_chk","demangled":false,"offset":14320,"size":16,"space":"imports"} +sym.imp.__memcpy_chk={"realname":"__memcpy_chk","demangled":false,"offset":15104,"size":16,"space":"imports"} +sym.imp.__mempcpy_chk={"realname":"__mempcpy_chk","demangled":false,"offset":14224,"size":16,"space":"imports"} +sym.imp.__overflow={"realname":"__overflow","demangled":false,"offset":14768,"size":16,"space":"imports"} +sym.imp.__printf_chk={"realname":"__printf_chk","demangled":false,"offset":15424,"size":16,"space":"imports"} +sym.imp.__readlink_chk={"realname":"__readlink_chk","demangled":false,"offset":15040,"size":16,"space":"imports"} +sym.imp.__snprintf_chk={"realname":"__snprintf_chk","demangled":false,"offset":14176,"size":16,"space":"imports"} +sym.imp.__sprintf_chk={"realname":"__sprintf_chk","demangled":false,"offset":15872,"size":16,"space":"imports"} +sym.imp.__stack_chk_fail={"realname":"__stack_chk_fail","demangled":false,"offset":14656,"size":16,"space":"imports"} +sym.imp.__strcpy_chk={"realname":"__strcpy_chk","demangled":false,"offset":15392,"size":16,"space":"imports"} +sym.imp._exit={"realname":"_exit","demangled":false,"offset":14304,"size":16,"space":"imports"} +sym.imp._setjmp={"realname":"_setjmp","demangled":false,"offset":14960,"size":16,"space":"imports"} +sym.imp.abort={"realname":"abort","demangled":false,"offset":14240,"size":16,"space":"imports"} +sym.imp.bindtextdomain={"realname":"bindtextdomain","demangled":false,"offset":14576,"size":16,"space":"imports"} +sym.imp.calloc={"realname":"calloc","demangled":false,"offset":15008,"size":16,"space":"imports"} +sym.imp.cap_free={"realname":"cap_free","demangled":false,"offset":15584,"size":16,"space":"imports"} +sym.imp.cap_get_file={"realname":"cap_get_file","demangled":false,"offset":15552,"size":16,"space":"imports"} +sym.imp.cap_to_text={"realname":"cap_to_text","demangled":false,"offset":14144,"size":16,"space":"imports"} +sym.imp.clock_gettime={"realname":"clock_gettime","demangled":false,"offset":14480,"size":16,"space":"imports"} +sym.imp.closedir={"realname":"closedir","demangled":false,"offset":14928,"size":16,"space":"imports"} +sym.imp.dcgettext={"realname":"dcgettext","demangled":false,"offset":14608,"size":16,"space":"imports"} +sym.imp.dirfd={"realname":"dirfd","demangled":false,"offset":15072,"size":16,"space":"imports"} +sym.imp.error={"realname":"error","demangled":false,"offset":15520,"size":16,"space":"imports"} +sym.imp.exit={"realname":"exit","demangled":false,"offset":15680,"size":16,"space":"imports"} +sym.imp.fclose={"realname":"fclose","demangled":false,"offset":14528,"size":16,"space":"imports"} +sym.imp.fflush={"realname":"fflush","demangled":false,"offset":15280,"size":16,"space":"imports"} +sym.imp.fflush_unlocked={"realname":"fflush_unlocked","demangled":false,"offset":15744,"size":16,"space":"imports"} +sym.imp.fileno={"realname":"fileno","demangled":false,"offset":15200,"size":16,"space":"imports"} +sym.imp.fnmatch={"realname":"fnmatch","demangled":false,"offset":14848,"size":16,"space":"imports"} +sym.imp.fputc_unlocked={"realname":"fputc_unlocked","demangled":false,"offset":15088,"size":16,"space":"imports"} +sym.imp.fputs_unlocked={"realname":"fputs_unlocked","demangled":false,"offset":14976,"size":16,"space":"imports"} +sym.imp.free={"realname":"free","demangled":false,"offset":14208,"size":16,"space":"imports"} +sym.imp.freecon={"realname":"freecon","demangled":false,"offset":14704,"size":16,"space":"imports"} +sym.imp.fseeko={"realname":"fseeko","demangled":false,"offset":15536,"size":16,"space":"imports"} +sym.imp.fwrite={"realname":"fwrite","demangled":false,"offset":15696,"size":16,"space":"imports"} +sym.imp.fwrite_unlocked={"realname":"fwrite_unlocked","demangled":false,"offset":15360,"size":16,"space":"imports"} +sym.imp.getcwd={"realname":"getcwd","demangled":false,"offset":14896,"size":16,"space":"imports"} +sym.imp.getenv={"realname":"getenv","demangled":false,"offset":14128,"size":16,"space":"imports"} +sym.imp.getfilecon={"realname":"getfilecon","demangled":false,"offset":15728,"size":16,"space":"imports"} +sym.imp.getgrgid={"realname":"getgrgid","demangled":false,"offset":14736,"size":16,"space":"imports"} +sym.imp.gethostname={"realname":"gethostname","demangled":false,"offset":15648,"size":16,"space":"imports"} +sym.imp.getopt_long={"realname":"getopt_long","demangled":false,"offset":14672,"size":16,"space":"imports"} +sym.imp.getpwuid={"realname":"getpwuid","demangled":false,"offset":14560,"size":16,"space":"imports"} +sym.imp.getxattr={"realname":"getxattr","demangled":false,"offset":15632,"size":16,"space":"imports"} +sym.imp.gmtime_r={"realname":"gmtime_r","demangled":false,"offset":14800,"size":16,"space":"imports"} +sym.imp.ioctl={"realname":"ioctl","demangled":false,"offset":14880,"size":16,"space":"imports"} +sym.imp.isatty={"realname":"isatty","demangled":false,"offset":14352,"size":16,"space":"imports"} +sym.imp.iswcntrl={"realname":"iswcntrl","demangled":false,"offset":14384,"size":16,"space":"imports"} +sym.imp.iswprint={"realname":"iswprint","demangled":false,"offset":15792,"size":16,"space":"imports"} +sym.imp.lgetfilecon={"realname":"lgetfilecon","demangled":false,"offset":15776,"size":16,"space":"imports"} +sym.imp.listxattr={"realname":"listxattr","demangled":false,"offset":14592,"size":16,"space":"imports"} +sym.imp.localeconv={"realname":"localeconv","demangled":false,"offset":14432,"size":16,"space":"imports"} +sym.imp.localtime_r={"realname":"localtime_r","demangled":false,"offset":14288,"size":16,"space":"imports"} +sym.imp.lseek={"realname":"lseek","demangled":false,"offset":14816,"size":16,"space":"imports"} +sym.imp.malloc={"realname":"malloc","demangled":false,"offset":15264,"size":16,"space":"imports"} +sym.imp.mbrtoc32={"realname":"mbrtoc32","demangled":false,"offset":14912,"size":16,"space":"imports"} +sym.imp.mbrtowc={"realname":"mbrtowc","demangled":false,"offset":14688,"size":16,"space":"imports"} +sym.imp.mbsinit={"realname":"mbsinit","demangled":false,"offset":15760,"size":16,"space":"imports"} +sym.imp.mbstowcs={"realname":"mbstowcs","demangled":false,"offset":14448,"size":16,"space":"imports"} +sym.imp.memcmp={"realname":"memcmp","demangled":false,"offset":14944,"size":16,"space":"imports"} +sym.imp.memcpy={"realname":"memcpy","demangled":false,"offset":15152,"size":16,"space":"imports"} +sym.imp.memmove={"realname":"memmove","demangled":false,"offset":15504,"size":16,"space":"imports"} +sym.imp.mempcpy={"realname":"mempcpy","demangled":false,"offset":15488,"size":16,"space":"imports"} +sym.imp.memset={"realname":"memset","demangled":false,"offset":14864,"size":16,"space":"imports"} +sym.imp.mktime={"realname":"mktime","demangled":false,"offset":15328,"size":16,"space":"imports"} +sym.imp.nl_langinfo={"realname":"nl_langinfo","demangled":false,"offset":15296,"size":16,"space":"imports"} +sym.imp.opendir={"realname":"opendir","demangled":false,"offset":14544,"size":16,"space":"imports"} +sym.imp.raise={"realname":"raise","demangled":false,"offset":14192,"size":16,"space":"imports"} +sym.imp.rawmemchr={"realname":"rawmemchr","demangled":false,"offset":14992,"size":16,"space":"imports"} +sym.imp.readdir={"realname":"readdir","demangled":false,"offset":15232,"size":16,"space":"imports"} +sym.imp.readlink={"realname":"readlink","demangled":false,"offset":14464,"size":16,"space":"imports"} +sym.imp.realloc={"realname":"realloc","demangled":false,"offset":15376,"size":16,"space":"imports"} +sym.imp.reallocarray={"realname":"reallocarray","demangled":false,"offset":14400,"size":16,"space":"imports"} +sym.imp.setenv={"realname":"setenv","demangled":false,"offset":14496,"size":16,"space":"imports"} +sym.imp.setlocale={"realname":"setlocale","demangled":false,"offset":15408,"size":16,"space":"imports"} +sym.imp.sigaction={"realname":"sigaction","demangled":false,"offset":14368,"size":16,"space":"imports"} +sym.imp.sigaddset={"realname":"sigaddset","demangled":false,"offset":15824,"size":16,"space":"imports"} +sym.imp.sigemptyset={"realname":"sigemptyset","demangled":false,"offset":15120,"size":16,"space":"imports"} +sym.imp.sigismember={"realname":"sigismember","demangled":false,"offset":15664,"size":16,"space":"imports"} +sym.imp.signal={"realname":"signal","demangled":false,"offset":15056,"size":16,"space":"imports"} +sym.imp.sigprocmask={"realname":"sigprocmask","demangled":false,"offset":14160,"size":16,"space":"imports"} +sym.imp.snprintf={"realname":"snprintf","demangled":false,"offset":14752,"size":16,"space":"imports"} +sym.imp.stat={"realname":"stat","demangled":false,"offset":15136,"size":16,"space":"imports"} +sym.imp.statx={"realname":"statx","demangled":false,"offset":15440,"size":16,"space":"imports"} +sym.imp.strchr={"realname":"strchr","demangled":false,"offset":14720,"size":16,"space":"imports"} +sym.imp.strcmp={"realname":"strcmp","demangled":false,"offset":15024,"size":16,"space":"imports"} +sym.imp.strcoll={"realname":"strcoll","demangled":false,"offset":15312,"size":16,"space":"imports"} +sym.imp.strftime={"realname":"strftime","demangled":false,"offset":15472,"size":16,"space":"imports"} +sym.imp.strlen={"realname":"strlen","demangled":false,"offset":14640,"size":16,"space":"imports"} +sym.imp.strncmp={"realname":"strncmp","demangled":false,"offset":14272,"size":16,"space":"imports"} +sym.imp.strrchr={"realname":"strrchr","demangled":false,"offset":14784,"size":16,"space":"imports"} +sym.imp.tcgetpgrp={"realname":"tcgetpgrp","demangled":false,"offset":15216,"size":16,"space":"imports"} +sym.imp.textdomain={"realname":"textdomain","demangled":false,"offset":14512,"size":16,"space":"imports"} +sym.imp.timegm={"realname":"timegm","demangled":false,"offset":15456,"size":16,"space":"imports"} +sym.imp.tzset={"realname":"tzset","demangled":false,"offset":15184,"size":16,"space":"imports"} +sym.imp.unsetenv={"realname":"unsetenv","demangled":false,"offset":15568,"size":16,"space":"imports"} +sym.imp.wcstombs={"realname":"wcstombs","demangled":false,"offset":15616,"size":16,"space":"imports"} +sym.imp.wcswidth={"realname":"wcswidth","demangled":false,"offset":14416,"size":16,"space":"imports"} +sym.imp.wcwidth={"realname":"wcwidth","demangled":false,"offset":15248,"size":16,"space":"imports"} +sym.indent={"realname":"indent","demangled":false,"offset":29184,"size":209,"space":"symbols"} +sym.is_colored.lto_priv.0={"realname":"is_colored.lto_priv.0","demangled":false,"offset":44992,"size":103,"space":"symbols"} +sym.length_of_file_name_and_frills={"realname":"length_of_file_name_and_frills","demangled":false,"offset":52720,"size":571,"space":"symbols"} +sym.localtime_rz={"realname":"localtime_rz","demangled":false,"offset":55632,"size":155,"space":"symbols"} +sym.main={"realname":"main","demangled":false,"offset":16000,"size":8302,"space":"symbols"} +sym.map_to_failure.lto_priv.0={"realname":"map_to_failure.lto_priv.0","demangled":false,"offset":54784,"size":125,"space":"symbols"} +sym.mbsnwidth.constprop.0={"realname":"mbsnwidth.constprop.0","demangled":false,"offset":81248,"size":429,"space":"symbols"} +sym.mpsort_with_tmp.part.0={"realname":"mpsort_with_tmp.part.0","demangled":false,"offset":32624,"size":733,"space":"symbols"} +sym.needs_quoting.lto_priv.0={"realname":"needs_quoting.lto_priv.0","demangled":false,"offset":45312,"size":176,"space":"symbols"} +sym.print_and_abort={"realname":"print_and_abort","demangled":false,"offset":35952,"size":70,"space":"symbols"} +sym.print_current_files={"realname":"print_current_files","demangled":false,"offset":64720,"size":1097,"space":"symbols"} +sym.print_dir={"realname":"print_dir","demangled":false,"offset":67392,"size":1873,"space":"symbols"} +sym.print_file_name_and_frills.isra.0={"realname":"print_file_name_and_frills.isra.0","demangled":false,"offset":101584,"size":634,"space":"symbols"} +sym.print_long_format={"realname":"print_long_format","demangled":false,"offset":60672,"size":4048,"space":"symbols"} +sym.print_name_with_quoting.lto_priv.0={"realname":"print_name_with_quoting.lto_priv.0","demangled":false,"offset":58096,"size":1350,"space":"symbols"} +sym.print_with_separator={"realname":"print_with_separator","demangled":false,"offset":53296,"size":486,"space":"symbols"} +sym.process_signals={"realname":"process_signals","demangled":false,"offset":45952,"size":254,"space":"symbols"} +sym.proper_name_lite={"realname":"proper_name_lite","demangled":false,"offset":32432,"size":191,"space":"symbols"} +sym.push_current_dired_pos.part.0={"realname":"push_current_dired_pos.part.0","demangled":false,"offset":54176,"size":72,"space":"symbols"} +sym.put_indicator.lto_priv.0={"realname":"put_indicator.lto_priv.0","demangled":false,"offset":45776,"size":169,"space":"symbols"} +sym.queue_directory={"realname":"queue_directory","demangled":false,"offset":66160,"size":113,"space":"symbols"} +sym.quote={"realname":"quote","demangled":false,"offset":36736,"size":17,"space":"symbols"} +sym.quote_name={"realname":"quote_name","demangled":false,"offset":57152,"size":934,"space":"symbols"} +sym.quote_name_buf.constprop.0={"realname":"quote_name_buf.constprop.0","demangled":false,"offset":81680,"size":1524,"space":"symbols"} +sym.quote_name_width={"realname":"quote_name_width","demangled":false,"offset":41904,"size":167,"space":"symbols"} +sym.quotearg_buffer_restyled.constprop.0={"realname":"quotearg_buffer_restyled.constprop.0","demangled":false,"offset":73616,"size":6668,"space":"symbols"} +sym.quotearg_buffer_restyled.constprop.0.cold={"realname":"quotearg_buffer_restyled.constprop.0.cold","demangled":false,"offset":15961,"size":5,"space":"symbols"} +sym.quotearg_n_options.constprop.0={"realname":"quotearg_n_options.constprop.0","demangled":false,"offset":80288,"size":489,"space":"symbols"} +sym.quotearg_n_style_colon.constprop.0={"realname":"quotearg_n_style_colon.constprop.0","demangled":false,"offset":81136,"size":97,"space":"symbols"} +sym.raw_comparator.lto_priv.0={"realname":"raw_comparator.lto_priv.0","demangled":false,"offset":28688,"size":11,"space":"symbols"} +sym.raw_hasher.lto_priv.0={"realname":"raw_hasher.lto_priv.0","demangled":false,"offset":28656,"size":20,"space":"symbols"} +sym.register_tm_clones={"realname":"register_tm_clones","demangled":false,"offset":24400,"size":0,"space":"symbols"} +sym.rev_strcmp_atime={"realname":"rev_strcmp_atime","demangled":false,"offset":26560,"size":73,"space":"symbols"} +sym.rev_strcmp_btime={"realname":"rev_strcmp_btime","demangled":false,"offset":27136,"size":73,"space":"symbols"} +sym.rev_strcmp_ctime={"realname":"rev_strcmp_ctime","demangled":false,"offset":25344,"size":81,"space":"symbols"} +sym.rev_strcmp_df_atime={"realname":"rev_strcmp_df_atime","demangled":false,"offset":26928,"size":196,"space":"symbols"} +sym.rev_strcmp_df_btime={"realname":"rev_strcmp_df_btime","demangled":false,"offset":27504,"size":196,"space":"symbols"} +sym.rev_strcmp_df_ctime={"realname":"rev_strcmp_df_ctime","demangled":false,"offset":25760,"size":212,"space":"symbols"} +sym.rev_strcmp_df_extension={"realname":"rev_strcmp_df_extension","demangled":false,"offset":37088,"size":140,"space":"symbols"} +sym.rev_strcmp_df_mtime={"realname":"rev_strcmp_df_mtime","demangled":false,"offset":26352,"size":196,"space":"symbols"} +sym.rev_strcmp_df_name={"realname":"rev_strcmp_df_name","demangled":false,"offset":28384,"size":140,"space":"symbols"} +sym.rev_strcmp_df_size={"realname":"rev_strcmp_df_size","demangled":false,"offset":28016,"size":164,"space":"symbols"} +sym.rev_strcmp_df_width={"realname":"rev_strcmp_df_width","demangled":false,"offset":42240,"size":132,"space":"symbols"} +sym.rev_strcmp_extension={"realname":"rev_strcmp_extension","demangled":false,"offset":36912,"size":25,"space":"symbols"} +sym.rev_strcmp_mtime={"realname":"rev_strcmp_mtime","demangled":false,"offset":25984,"size":73,"space":"symbols"} +sym.rev_strcmp_name={"realname":"rev_strcmp_name","demangled":false,"offset":28208,"size":18,"space":"symbols"} +sym.rev_strcmp_size={"realname":"rev_strcmp_size","demangled":false,"offset":27712,"size":49,"space":"symbols"} +sym.rev_strcmp_width={"realname":"rev_strcmp_width","demangled":false,"offset":42080,"size":159,"space":"symbols"} +sym.rev_xstrcoll_atime={"realname":"rev_xstrcoll_atime","demangled":false,"offset":38848,"size":97,"space":"symbols"} +sym.rev_xstrcoll_btime={"realname":"rev_xstrcoll_btime","demangled":false,"offset":39360,"size":97,"space":"symbols"} +sym.rev_xstrcoll_ctime={"realname":"rev_xstrcoll_ctime","demangled":false,"offset":37808,"size":113,"space":"symbols"} +sym.rev_xstrcoll_df_atime={"realname":"rev_xstrcoll_df_atime","demangled":false,"offset":38960,"size":132,"space":"symbols"} +sym.rev_xstrcoll_df_btime={"realname":"rev_xstrcoll_df_btime","demangled":false,"offset":39472,"size":132,"space":"symbols"} +sym.rev_xstrcoll_df_ctime={"realname":"rev_xstrcoll_df_ctime","demangled":false,"offset":37936,"size":132,"space":"symbols"} +sym.rev_xstrcoll_df_extension={"realname":"rev_xstrcoll_df_extension","demangled":false,"offset":41040,"size":132,"space":"symbols"} +sym.rev_xstrcoll_df_mtime={"realname":"rev_xstrcoll_df_mtime","demangled":false,"offset":38448,"size":132,"space":"symbols"} +sym.rev_xstrcoll_df_name={"realname":"rev_xstrcoll_df_name","demangled":false,"offset":40432,"size":164,"space":"symbols"} +sym.rev_xstrcoll_df_size={"realname":"rev_xstrcoll_df_size","demangled":false,"offset":39968,"size":188,"space":"symbols"} +sym.rev_xstrcoll_df_version={"realname":"rev_xstrcoll_df_version","demangled":false,"offset":41504,"size":188,"space":"symbols"} +sym.rev_xstrcoll_df_width={"realname":"rev_xstrcoll_df_width","demangled":false,"offset":43216,"size":132,"space":"symbols"} +sym.rev_xstrcoll_extension={"realname":"rev_xstrcoll_extension","demangled":false,"offset":40896,"size":137,"space":"symbols"} +sym.rev_xstrcoll_mtime={"realname":"rev_xstrcoll_mtime","demangled":false,"offset":38336,"size":97,"space":"symbols"} +sym.rev_xstrcoll_name={"realname":"rev_xstrcoll_name","demangled":false,"offset":40208,"size":43,"space":"symbols"} +sym.rev_xstrcoll_size={"realname":"rev_xstrcoll_size","demangled":false,"offset":39696,"size":73,"space":"symbols"} +sym.rev_xstrcoll_version={"realname":"rev_xstrcoll_version","demangled":false,"offset":41184,"size":53,"space":"symbols"} +sym.rev_xstrcoll_width={"realname":"rev_xstrcoll_width","demangled":false,"offset":43024,"size":177,"space":"symbols"} +sym.revert_tz.part.0.lto_priv.0={"realname":"revert_tz.part.0.lto_priv.0","demangled":false,"offset":55488,"size":134,"space":"symbols"} +sym.rpl_fclose={"realname":"rpl_fclose","demangled":false,"offset":43760,"size":286,"space":"symbols"} +sym.rpl_mbrtoc32={"realname":"rpl_mbrtoc32","demangled":false,"offset":69312,"size":135,"space":"symbols"} +sym.save_abbr.lto_priv.0={"realname":"save_abbr.lto_priv.0","demangled":false,"offset":54912,"size":317,"space":"symbols"} +sym.set_tz.lto_priv.0={"realname":"set_tz.lto_priv.0","demangled":false,"offset":55232,"size":245,"space":"symbols"} +sym.sighandler={"realname":"sighandler","demangled":false,"offset":24624,"size":21,"space":"symbols"} +sym.signal_setup={"realname":"signal_setup","demangled":false,"offset":31984,"size":444,"space":"symbols"} +sym.sort_files={"realname":"sort_files","demangled":false,"offset":55920,"size":859,"space":"symbols"} +sym.stdout_isatty={"realname":"stdout_isatty","demangled":false,"offset":37232,"size":41,"space":"symbols"} +sym.stophandler={"realname":"stophandler","demangled":false,"offset":24656,"size":30,"space":"symbols"} +sym.strcaseeq7={"realname":"strcaseeq7","demangled":false,"offset":28928,"size":248,"space":"symbols"} +sym.strcmp_atime={"realname":"strcmp_atime","demangled":false,"offset":26640,"size":73,"space":"symbols"} +sym.strcmp_btime={"realname":"strcmp_btime","demangled":false,"offset":27216,"size":73,"space":"symbols"} +sym.strcmp_ctime={"realname":"strcmp_ctime","demangled":false,"offset":25440,"size":81,"space":"symbols"} +sym.strcmp_df_atime={"realname":"strcmp_df_atime","demangled":false,"offset":26720,"size":196,"space":"symbols"} +sym.strcmp_df_btime={"realname":"strcmp_df_btime","demangled":false,"offset":27296,"size":196,"space":"symbols"} +sym.strcmp_df_ctime={"realname":"strcmp_df_ctime","demangled":false,"offset":25536,"size":212,"space":"symbols"} +sym.strcmp_df_extension={"realname":"strcmp_df_extension","demangled":false,"offset":36944,"size":140,"space":"symbols"} +sym.strcmp_df_mtime={"realname":"strcmp_df_mtime","demangled":false,"offset":26144,"size":196,"space":"symbols"} +sym.strcmp_df_name={"realname":"strcmp_df_name","demangled":false,"offset":28240,"size":132,"space":"symbols"} +sym.strcmp_df_size={"realname":"strcmp_df_size","demangled":false,"offset":27840,"size":164,"space":"symbols"} +sym.strcmp_df_width={"realname":"strcmp_df_width","demangled":false,"offset":42880,"size":132,"space":"symbols"} +sym.strcmp_extension={"realname":"strcmp_extension","demangled":false,"offset":36896,"size":16,"space":"symbols"} +sym.strcmp_mtime={"realname":"strcmp_mtime","demangled":false,"offset":26064,"size":73,"space":"symbols"} +sym.strcmp_name={"realname":"strcmp_name","demangled":false,"offset":28192,"size":15,"space":"symbols"} +sym.strcmp_size={"realname":"strcmp_size","demangled":false,"offset":27776,"size":49,"space":"symbols"} +sym.strcmp_width={"realname":"strcmp_width","demangled":false,"offset":42720,"size":159,"space":"symbols"} +sym.transfer_entries={"realname":"transfer_entries","demangled":false,"offset":36352,"size":373,"space":"symbols"} +sym.transfer_entries.cold={"realname":"transfer_entries.cold","demangled":false,"offset":15941,"size":5,"space":"symbols"} +sym.triple_compare_ino_str={"realname":"triple_compare_ino_str","demangled":false,"offset":28816,"size":56,"space":"symbols"} +sym.triple_free={"realname":"triple_free","demangled":false,"offset":28880,"size":37,"space":"symbols"} +sym.triple_hash={"realname":"triple_hash","demangled":false,"offset":28704,"size":98,"space":"symbols"} +sym.tzalloc={"realname":"tzalloc","demangled":false,"offset":33360,"size":171,"space":"symbols"} +sym.usage={"realname":"usage","demangled":false,"offset":33648,"size":2264,"space":"symbols"} +sym.verrevcmp.lto_priv.0={"realname":"verrevcmp.lto_priv.0","demangled":false,"offset":46656,"size":1074,"space":"symbols"} +sym.version_etc.constprop.0={"realname":"version_etc.constprop.0","demangled":false,"offset":69456,"size":1676,"space":"symbols"} +sym.xalloc_die={"realname":"xalloc_die","demangled":false,"offset":55792,"size":64,"space":"symbols"} +sym.xpalloc={"realname":"xpalloc","demangled":false,"offset":65824,"size":268,"space":"symbols"} +sym.xstrcoll_atime={"realname":"xstrcoll_atime","demangled":false,"offset":38592,"size":97,"space":"symbols"} +sym.xstrcoll_btime={"realname":"xstrcoll_btime","demangled":false,"offset":39104,"size":97,"space":"symbols"} +sym.xstrcoll_ctime={"realname":"xstrcoll_ctime","demangled":false,"offset":37536,"size":113,"space":"symbols"} +sym.xstrcoll_df_atime={"realname":"xstrcoll_df_atime","demangled":false,"offset":38704,"size":132,"space":"symbols"} +sym.xstrcoll_df_btime={"realname":"xstrcoll_df_btime","demangled":false,"offset":39216,"size":132,"space":"symbols"} +sym.xstrcoll_df_ctime={"realname":"xstrcoll_df_ctime","demangled":false,"offset":37664,"size":132,"space":"symbols"} +sym.xstrcoll_df_extension={"realname":"xstrcoll_df_extension","demangled":false,"offset":40752,"size":132,"space":"symbols"} +sym.xstrcoll_df_mtime={"realname":"xstrcoll_df_mtime","demangled":false,"offset":38192,"size":132,"space":"symbols"} +sym.xstrcoll_df_name={"realname":"xstrcoll_df_name","demangled":false,"offset":40256,"size":164,"space":"symbols"} +sym.xstrcoll_df_size={"realname":"xstrcoll_df_size","demangled":false,"offset":39776,"size":188,"space":"symbols"} +sym.xstrcoll_df_version={"realname":"xstrcoll_df_version","demangled":false,"offset":41312,"size":188,"space":"symbols"} +sym.xstrcoll_df_width={"realname":"xstrcoll_df_width","demangled":false,"offset":42576,"size":132,"space":"symbols"} +sym.xstrcoll_extension={"realname":"xstrcoll_extension","demangled":false,"offset":40608,"size":137,"space":"symbols"} +sym.xstrcoll_mtime={"realname":"xstrcoll_mtime","demangled":false,"offset":38080,"size":97,"space":"symbols"} +sym.xstrcoll_name={"realname":"xstrcoll_name","demangled":false,"offset":40160,"size":43,"space":"symbols"} +sym.xstrcoll_size={"realname":"xstrcoll_size","demangled":false,"offset":39616,"size":73,"space":"symbols"} +sym.xstrcoll_version={"realname":"xstrcoll_version","demangled":false,"offset":41248,"size":53,"space":"symbols"} +sym.xstrcoll_width={"realname":"xstrcoll_width","demangled":false,"offset":42384,"size":177,"space":"symbols"} +sym.xstrdup={"realname":"xstrdup","demangled":false,"offset":66096,"size":62,"space":"symbols"} +sym.xstrtoumax.constprop.0={"realname":"xstrtoumax.constprop.0","demangled":false,"offset":71472,"size":1259,"space":"symbols"} + +/core/flags/spaces +name=fs +spacestack=["*"] + +/core/flags/spaces/spaces +classes=s +imports=s +relocs=s +sections=s +segments=s +strings=s +symbols=s + +/core/flags/tags +tag.alloc=malloc free$ calloc kalloc realloc +tag.dylib=dlopen dlsym dlclose mmap LoadLibrary GetProcAddress +tag.env=getenv putenv unsetenv setenv GetEnvironmentVariable SetEnvironmentVariable ExpandEnvironmentStrings +tag.fs=open$ close read$ write CloseHandle FindFirstFileW _wfopen _wstat ftruncate lseek _chsize GetFullPathName realpath RemoveDirectory DeleteFile CreateFile WriteFile UnmapViewOfFile CreateFileMapping MapViewOfFile readlink chmod fchmod chown stat fstat lstat fstatat lstat64 stat64 chflags fchflags lchflags +tag.network=socket connect bind$ listen accept sendto recvfrom gethostbyname htons ntohs +tag.process=getpid getppid kill exit abort assert gethostid sethostid sysctl +tag.stdout=^printf puts write +tag.string=strcat strcpy strncpy strlen strtok strstr strlcpy asprintf sprintf snprintf +tag.threads=pthread_create pthread_mutex_init pthread_cond_init CreateThread TerminateThread WaitForSingleObject GetCurrentThreadId +tag.time=settimeofday gettimeofday time adjtime ctime timed date$ sleep Sleep usleep clock_nanosleep localtime asctime difftime gmtime mktime timelocal timegm tzfile tzset + +/core/flags/zones + +/core/seek +0={"offset":24304,"cursor":0,"current":true} From 88683b3e0097ee4e866831839c830d0b1e029c92 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 4 Feb 2025 13:17:34 -0500 Subject: [PATCH 097/157] Add /xr regex byte search. --- librz/core/cmd/cmd_search.c | 78 +++++++++++++++++++++++++++- librz/core/cmd_descs/cmd_descs.c | 40 ++++++++++++-- librz/core/cmd_descs/cmd_descs.h | 2 + librz/core/cmd_descs/cmd_search.yaml | 71 +++++++++++++++++-------- librz/include/rz_search.h | 2 +- librz/include/rz_util/rz_regex.h | 2 + librz/search/bytes_search.c | 32 ++++++++++-- librz/search/search_internal.h | 1 + librz/util/hex.c | 3 +- librz/util/regex.c | 44 ++++++++++++++++ test/db/cmd/cmd_search_x | 34 ++++++++++++ 11 files changed, 276 insertions(+), 33 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 637075fc96f..6450ed78ca0 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -12,6 +12,7 @@ #include "cmd_search_rop.c" #include "rz_cons.h" +#include #include #include #include @@ -2823,7 +2824,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char CMD_SEARCH_BEGIN(); RzList *hits = NULL; - RzSearchBytesPattern *pattern = rz_search_parse_byte_pattern(argv[1], "bytes"); + const char *arg = argv[1]; + RzSearchBytesPattern *pattern = rz_search_parse_byte_pattern(arg, "bytes"); if (!pattern) { RZ_LOG_ERROR("Failed to parse given pattern.\n"); @@ -2852,6 +2854,80 @@ RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char return RZ_CMD_STATUS_ERROR; } +static bool parse_pattern_arg(const char *arg, RZ_OUT ut8 *re, RZ_OUT size_t *len) { + *len = 0; + size_t arg_len = strlen(arg); + // Convert to real bytes. + for (size_t i = 0; i < arg_len;) { + if (arg[i] == 'x') { + if (i + 2 >= arg_len) { + RZ_LOG_ERROR("'x' in the pattern must be followed by two hexadecimal nibbles (N = [a-fA-F0-9]): xNN.\n"); + return false; + } + if (!IS_HEXCHAR(arg[i + 1]) || !IS_HEXCHAR(arg[i + 2])) { + RZ_LOG_ERROR("Bytes with non-hexadecimal nibbles are not allowed. Got: 'x%c%c'.\n", arg[i + 1], arg[i + 2]); + return false; + } + ut16 byte = rz_hex_digit_pair_to_byte(arg + i + 1); + re[*len] = byte; + i += 3; + } else { + // Just copy normal character. + re[*len] = arg[i]; + i++; + } + *len += 1; + } + return true; +} + +// "/xr" +RZ_IPI RzCmdStatus rz_cmd_search_hex_regex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + ut8 *re = RZ_NEWS0(ut8, strlen(argv[1])); + RzSearchOpt *search_opts = setup_search_options(core); + if (!search_opts) { + goto error; + } + + CMD_SEARCH_BEGIN(); + + RzList *hits = NULL; + const char *arg = argv[1]; + size_t r = 0; + if (!parse_pattern_arg(arg, re, &r)) { + goto error; + } + RzSearchBytesPattern *pattern = rz_search_bytes_pattern_new(rz_new_copy(r, re), NULL, r, "bytes", true); + + if (!pattern) { + RZ_LOG_ERROR("Failed to parse given pattern.\n"); + goto error; + } + + bool progress = rz_config_get_b(core->config, "search.show_progress"); + if (!rz_search_opt_set_cancel_cb(search_opts, cmd_search_progress_cancel, progress ? state : NULL)) { + RZ_LOG_ERROR("code: Failed to setup default search options.\n"); + goto error; + } + hits = rz_core_search_bytes(core, search_opts, pattern); + if (!hits) { + RZ_LOG_ERROR("Failed to perform search.\n"); + goto error; + } + + CMD_SEARCH_END(); + free(re); + rz_search_opt_free(search_opts); + return cmd_core_handle_search_hits(core, state, hits); + +error: + free(re); + rz_list_free(hits); + rz_search_opt_free(search_opts); + CMD_SEARCH_END(); + return RZ_CMD_STATUS_ERROR; +} + static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, const char *encoding, RzRegexFlags flags, RzCmdStateOutput *state) { RzSearchOpt *search_opts = setup_search_options(core); if (!search_opts) { diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 9f1e7e51aef..22478559b1b 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -19,6 +19,7 @@ static const RzCmdDescDetail cmd_search_hash_block_details[2]; static const RzCmdDescDetail slash_v_details[2]; static const RzCmdDescDetail slash_V_details[2]; static const RzCmdDescDetail cmd_search_hex_details[2]; +static const RzCmdDescDetail cmd_search_hex_regex_details[2]; static const RzCmdDescDetail slash_z_details[3]; static const RzCmdDescDetail base64_encode_details[2]; static const RzCmdDescDetail base64_decode_details[2]; @@ -159,6 +160,7 @@ static const RzCmdDescArg cmd_search_value_16be_args[3]; static const RzCmdDescArg cmd_search_value_32be_args[3]; static const RzCmdDescArg cmd_search_value_64be_args[3]; static const RzCmdDescArg cmd_search_hex_args[2]; +static const RzCmdDescArg cmd_search_hex_regex_args[2]; static const RzCmdDescArg cmd_search_string_sensitive_args[4]; static const RzCmdDescArg remote_args[3]; static const RzCmdDescArg remote_send_args[3]; @@ -2338,6 +2340,9 @@ static const RzCmdDescHelp cmd_search_value_64be_help = { .args = cmd_search_value_64be_args, }; +static const RzCmdDescHelp slash_x_help = { + .summary = "Raw hexadecimal search.", +}; static const RzCmdDescDetailEntry cmd_search_hex_Usage_space_example_detail_entries[] = { { .text = "Hexadecimal search for the exact bytes 'ffcc33'.", .arg_str = NULL, .comment = "/x ffcc33" }, { .text = "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits.", .arg_str = NULL, .comment = "/x ff..33.0" }, @@ -2364,6 +2369,32 @@ static const RzCmdDescHelp cmd_search_hex_help = { .args = cmd_search_hex_args, }; +static const RzCmdDescDetailEntry cmd_search_hex_regex_Usage_space_examples_detail_entries[] = { + { .text = " Bytes are prefixed with a 'x'. Search exact match '\\x99\\x0a'.", .arg_str = NULL, .comment = "/xr x99x0a" }, + { .text = "Search 2-8 NUL bytes, then '\\x99' and '\\x0a'", .arg_str = NULL, .comment = "/xr x00{2,8}x99x0a" }, + { .text = "A '.' matches one byte. Search matches: '\\x72\\xNN\\x00'. '\\xNN' can appear 0-1 times.", .arg_str = NULL, .comment = "/xr x72.?x00" }, + { .text = "Using simple ASCII is allowed. Search matches: '\\x61\\x41'", .arg_str = NULL, .comment = "/xr aA" }, + { 0 }, +}; +static const RzCmdDescDetail cmd_search_hex_regex_details[] = { + { .name = "Usage examples", .entries = cmd_search_hex_regex_Usage_space_examples_detail_entries }, + { 0 }, +}; +static const RzCmdDescArg cmd_search_hex_regex_args[] = { + { + .name = "regex_pattern", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_search_hex_regex_help = { + .summary = "Regex bytes search.", + .details = cmd_search_hex_regex_details, + .args = cmd_search_hex_regex_args, +}; + static const RzCmdDescDetailEntry slash_z_Encodings_detail_entries[] = { { .text = "ascii", .arg_str = NULL, .comment = "ASCII encoding" }, { .text = "8bit", .arg_str = NULL, .comment = "8bit encoding. Alias: ASCII" }, @@ -21017,9 +21048,12 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_value_64be_cd); rz_cmd_desc_set_default_mode(cmd_search_value_64be_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *cmd_search_hex_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash__cd, "/x", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_hex_handler, &cmd_search_hex_help); - rz_warn_if_fail(cmd_search_hex_cd); - rz_cmd_desc_set_default_mode(cmd_search_hex_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *slash_x_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/x", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_hex_handler, &cmd_search_hex_help, &slash_x_help); + rz_warn_if_fail(slash_x_cd); + rz_cmd_desc_set_default_mode(slash_x_cd, RZ_OUTPUT_MODE_STANDARD); + RzCmdDesc *cmd_search_hex_regex_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_x_cd, "/xr", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_hex_regex_handler, &cmd_search_hex_regex_help); + rz_warn_if_fail(cmd_search_hex_regex_cd); + rz_cmd_desc_set_default_mode(cmd_search_hex_regex_cd, RZ_OUTPUT_MODE_STANDARD); RzCmdDesc *slash_z_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/z", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_string_sensitive_handler, &cmd_search_string_sensitive_help, &slash_z_help); rz_warn_if_fail(slash_z_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index b3fe0958305..e3e4e4f0999 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -177,6 +177,8 @@ RZ_IPI RzCmdStatus rz_cmd_search_value_32be_handler(RzCore *core, int argc, cons RZ_IPI RzCmdStatus rz_cmd_search_value_64be_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/x" RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "/xr" +RZ_IPI RzCmdStatus rz_cmd_search_hex_regex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/z" RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "R" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index bcf13b33113..1df7c6ef7d9 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -690,28 +690,55 @@ commands: comment: "/V4 512" - name: "/x" summary: Raw hexadecimal search. - cname: cmd_search_hex - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE - args: - - name: pattern - type: RZ_CMD_ARG_TYPE_STRING - details: - - name: Usage example - entries: - - text: "Hexadecimal search for the exact bytes 'ffcc33'." - comment: "/x ffcc33" - - text: "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits." - comment: "/x ff..33.0" - - text: "Hexadecimal search of the bytes with mask. Pattern: ':'" - comment: "/x ffd0:ff43" - - text: "Hexadecimal search with an odd number of nibbles." - comment: "'aabbc' is equivalent to '.aabbc'" + subcommands: + - name: "/x" + summary: Raw hexadecimal search. + cname: cmd_search_hex + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: pattern + type: RZ_CMD_ARG_TYPE_STRING + details: + - name: Usage example + entries: + - text: "Hexadecimal search for the exact bytes 'ffcc33'." + comment: "/x ffcc33" + - text: "Hexadecimal search for the byte pattern 'ff..33.0.'. The '.' is a wildcard for 4bits." + comment: "/x ff..33.0" + - text: "Hexadecimal search of the bytes with mask. Pattern: ':'" + comment: "/x ffd0:ff43" + - text: "Hexadecimal search with an odd number of nibbles." + comment: "'aabbc' is equivalent to '.aabbc'" + - name: "/xr" + summary: Regex bytes search. + cname: cmd_search_hex_regex + type: RZ_CMD_DESC_TYPE_ARGV_STATE + default_mode: RZ_OUTPUT_MODE_STANDARD + modes: + - RZ_OUTPUT_MODE_STANDARD + - RZ_OUTPUT_MODE_JSON + - RZ_OUTPUT_MODE_QUIET + - RZ_OUTPUT_MODE_TABLE + args: + - name: regex_pattern + type: RZ_CMD_ARG_TYPE_STRING + details: + - name: Usage examples + entries: + - text: " Bytes are prefixed with a 'x'. Search exact match '\\x99\\x0a'." + comment: "/xr x99x0a" + - text: "Search 2-8 NUL bytes, then '\\x99' and '\\x0a'" + comment: "/xr x00{2,8}x99x0a" + - text: "A '.' matches one byte. Search matches: '\\x72\\xNN\\x00'. '\\xNN' can appear 0-1 times." + comment: "/xr x72.?x00" + - text: "Using simple ASCII is allowed. Search matches: '\\x61\\x41'" + comment: "/xr aA" - name: "/z" summary: String search. details: diff --git a/librz/include/rz_search.h b/librz/include/rz_search.h index a5a557c7093..6c61c088468 100644 --- a/librz/include/rz_search.h +++ b/librz/include/rz_search.h @@ -159,7 +159,7 @@ RZ_API RZ_OWN char *rz_search_hit_flag_name(RZ_NONNULL const RzSearchHit *hit, s RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern *hp); RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp); -RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc); +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc, bool compile_regex); RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byte_pattern, RZ_NULLABLE const char *pattern_desc); RZ_API size_t rz_search_bytes_pattern_len(RZ_NONNULL const RzSearchBytesPattern *hp); RZ_API const char *rz_search_bytes_pattern_desc(RZ_NONNULL const RzSearchBytesPattern *bp); diff --git a/librz/include/rz_util/rz_regex.h b/librz/include/rz_util/rz_regex.h index 35159a5b8da..b1993804bc5 100644 --- a/librz/include/rz_util/rz_regex.h +++ b/librz/include/rz_util/rz_regex.h @@ -56,6 +56,8 @@ typedef void RzRegexMatchData; ///< PCRE2 internal match data type RZ_API RZ_OWN RzRegex *rz_regex_new(RZ_NONNULL const char *pattern, RzRegexFlags cflags, RzRegexFlags jflags, RzRegexCompContext *ccontext); +RZ_API RZ_OWN RzRegex *rz_regex_new_bytes(RZ_NONNULL const ut8 *pattern, size_t pattern_len, RzRegexFlags cflags, RzRegexFlags jflags, + RzRegexCompContext *ccontext); RZ_API void rz_regex_free(RZ_OWN RzRegex *regex); RZ_API void rz_regex_error_msg(RzRegexStatus errcode, RZ_OUT char *errbuf, RzRegexSize errbuf_size); RZ_API const ut8 *rz_regex_get_match_name(RZ_NONNULL const RzRegex *regex, ut32 name_idx); diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index a632fefa80f..1ef9682344d 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -18,10 +18,13 @@ * \param mask The mask to apply to the pattern and the data before comparison. (optional) * \param length Length of \p bytes and \p mask (if not NULL). * \param pattern_desc An optional description string of the pattern. + * \param compile_regex If true it compiles \p bytes as regex. + * This will make the search use the regex, instead of comparing the bytes. + * The \p mask is ignored in this case. * * \return The initalized pattern or NULL in case of failure. */ -RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc) { +RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *bytes, RZ_NULLABLE RZ_OWN ut8 *mask, size_t length, RZ_NULLABLE const char *pattern_desc, bool compile_regex) { rz_return_val_if_fail(bytes && length > 0, NULL); RzSearchBytesPattern *pat = RZ_NEW0(RzSearchBytesPattern); if (!pat) { @@ -29,6 +32,9 @@ RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *byte return NULL; } pat->bytes = bytes; + if (compile_regex) { + pat->regex = rz_regex_new_bytes(bytes, length, RZ_REGEX_DEFAULT, RZ_REGEX_DEFAULT, NULL); + } pat->mask = mask; pat->length = length; pat->pattern_desc = pattern_desc; @@ -40,6 +46,7 @@ RZ_API void rz_search_bytes_pattern_free(RZ_NULLABLE RZ_OWN RzSearchBytesPattern return; } free(hp->bytes); + rz_regex_free(hp->regex); free(hp->mask); free(hp); } @@ -66,7 +73,7 @@ RZ_API size_t rz_search_bytes_pattern_len(RZ_NONNULL const RzSearchBytesPattern RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_copy(RZ_NONNULL RZ_BORROW RzSearchBytesPattern *hp) { rz_return_val_if_fail(hp, NULL); - return rz_search_bytes_pattern_new(rz_new_copy(hp->length, hp->bytes), rz_new_copy(hp->length, hp->mask), hp->length, hp->pattern_desc); + return rz_search_bytes_pattern_new(rz_new_copy(hp->length, hp->bytes), rz_new_copy(hp->length, hp->mask), hp->length, hp->pattern_desc, hp->regex != NULL); } static bool parse_custom_mask(const char *bytes_pattern, const RzRegexMatch *mask_match, const RzRegexMatch *bytes_match, ut8 *mask) { @@ -159,7 +166,7 @@ RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byt free(byte_str); rz_pvector_free(matches); - RzSearchBytesPattern *pat = rz_search_bytes_pattern_new(bytes, use_mask ? mask : NULL, size, pattern_desc); + RzSearchBytesPattern *pat = rz_search_bytes_pattern_new(bytes, use_mask ? mask : NULL, size, pattern_desc, false); if (!use_mask) { free(mask); } @@ -205,6 +212,23 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const R RzPVector /**/ *patterns = (RzPVector *)user; rz_pvector_foreach (patterns, it) { RzSearchBytesPattern *hp = (RzSearchBytesPattern *)*it; + if (hp->regex) { + RzPVector *matches = rz_regex_match_all(hp->regex, (const char *)raw_buf, size, 0, RZ_REGEX_DEFAULT); + void **it; + RzPVector *match; + rz_pvector_foreach (matches, it) { + match = *it; + RzRegexMatch *group0 = rz_pvector_at(match, 0); + RzSearchHit *hit = rz_search_hit_new(hp->pattern_desc, group0->start, group0->len); + if (!hit || !rz_th_queue_push(hits, hit, true)) { + rz_search_hit_free(hit); + rz_pvector_free(matches); + return false; + } + } + rz_pvector_free(matches); + continue; + } for (size_t offset = 0; offset < size;) { size_t leftovers = size - offset; if (hp->length > leftovers) { @@ -298,7 +322,7 @@ RZ_API bool rz_search_collection_bytes_add(RZ_NONNULL RzSearchCollection *col, R return false; } - RzSearchBytesPattern *hp = rz_search_bytes_pattern_new(rz_new_copy(length, bytes), rz_new_copy(length, mask), length, pattern_desc); + RzSearchBytesPattern *hp = rz_search_bytes_pattern_new(rz_new_copy(length, bytes), rz_new_copy(length, mask), length, pattern_desc, false); if (!hp) { return false; } else if (!rz_pvector_push((RzPVector *)col->user, hp)) { diff --git a/librz/search/search_internal.h b/librz/search/search_internal.h index fa1e64683c6..1ba9a41291a 100644 --- a/librz/search/search_internal.h +++ b/librz/search/search_internal.h @@ -102,6 +102,7 @@ struct rz_search_bytes_pattern_t { const char *pattern_desc; ///< Pattern description string. ut8 *bytes; ///< Pattern bytes. ut8 *mask; ///< Pattern mask (when NULL full match) + RzRegex *regex; ///< Regex patterns of the bytes. Is optional. size_t length; ///< Pattern & mask length }; diff --git a/librz/util/hex.c b/librz/util/hex.c index e7365953033..d8a02cf3638 100644 --- a/librz/util/hex.c +++ b/librz/util/hex.c @@ -51,7 +51,7 @@ RZ_API ut8 rz_hex_digit_to_byte(const char c) { * \param The string to parse as hex digit pair. * * \return The byte value of the nibble pair. - * Or UT16_MAX if the nibble is no hexadecimal character. + * Or UT16_MAX if the first nibble is no hexadecimal character. */ RZ_API ut16 rz_hex_digit_pair_to_byte(const char *npair) { if (!isxdigit(npair[0])) { @@ -544,7 +544,6 @@ RZ_API int rz_hex_str2bin_msb(RZ_NONNULL const char *in, RZ_NONNULL RZ_OUT ut8 * j++; } - for (byte = rz_hex_digit_pair_to_byte(in + i); i < strlen(in) && byte <= UT8_MAX; j++, i += 2, byte = rz_hex_digit_pair_to_byte(in + i)) { out[j] = byte; } diff --git a/librz/util/regex.c b/librz/util/regex.c index ca12f007ab9..c2198c380db 100644 --- a/librz/util/regex.c +++ b/librz/util/regex.c @@ -91,6 +91,50 @@ RZ_API RZ_OWN RzRegex *rz_regex_new(RZ_NONNULL const char *pattern, RzRegexFlags return regex; } +/** + * \brief Compile a regex pattern with raw bytes. + * In case of an error, an error message is printed and NULL is returned. + * + * Unlike `rz_regex_new()` it doesn't compile the pattern with the PCRE2_UTF flag. + * So any byte can be part of a pattern, not just UTF-8 compatible ones. + * + * \param pattern The pattern. Bytes must not be escaped. + * \param pattern_len The pattern length. + * \param cflags The compilation flags. + * \param jflags The compilation flags for the JIT compiler. + * You can pass RZ_REGEX_JIT_PARTIAL_SOFT or RZ_REGEX_JIT_PARTIAL_HARD if you + * intend to use the pattern for partial matching. Otherwise set it to 0. + * \param ccontext A compile context or NULL. + * + * \return The compiled regex or NULL in case of failure. + */ +RZ_API RZ_OWN RzRegex *rz_regex_new_bytes(RZ_NONNULL const ut8 *pattern, size_t pattern_len, RzRegexFlags cflags, RzRegexFlags jflags, + RzRegexCompContext *ccontext) { + rz_return_val_if_fail(pattern, NULL); + + RzRegexStatus err_num; + RzRegexSize err_off; + + RzRegex *regex = pcre2_compile( + pattern, + pattern_len, + cflags, + &err_num, + &err_off, + ccontext); + if (!regex) { + print_pcre2_err((const char *)pattern, err_num, err_off); + return NULL; + } +#ifdef SUPPORTS_PCRE2_JIT + RzRegexStatus jit_err = pcre2_jit_compile(regex, jflags | PCRE2_JIT_COMPLETE); + if (jit_err < 0) { + print_pcre2_err((const char *)pattern, jit_err, 0); + } +#endif + return regex; +} + /** * \brief Frees a given RzRegex. * diff --git a/test/db/cmd/cmd_search_x b/test/db/cmd/cmd_search_x index 52624acfeab..b2716a2653c 100644 --- a/test/db/cmd/cmd_search_x +++ b/test/db/cmd/cmd_search_x @@ -41,6 +41,40 @@ ERROR: Failed to parse given pattern. EOF RUN +NAME=Search hex bytes regex - errors +FILE=bins/cmd/search/string_encodings/Chinese-Lipsum.utf32le +CMDS=< Date: Tue, 4 Feb 2025 14:38:13 -0500 Subject: [PATCH 098/157] Fix unit test for projecct loading. --- test/integration/test_project_migrate.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/integration/test_project_migrate.c b/test/integration/test_project_migrate.c index 13474bdb561..b3e6b5d4a69 100644 --- a/test/integration/test_project_migrate.c +++ b/test/integration/test_project_migrate.c @@ -1008,12 +1008,13 @@ static bool test_load_v15_seek_history() { mu_end; } -static bool test_load_v15_str_config() { +static bool test_load_v15_19_str_config() { RzCore *core = rz_core_new(); + // Load version 15 config but check if the v19 values were converted correctly. BEGIN_LOAD_TEST(core, 15, "prj/v15-str-config.rzdb"); - mu_assert_eq(rz_config_get_i(core->config, "str.search.min_length"), 6, "str.search.min_length"); - mu_assert_streq(rz_config_get(core->config, "str.search.encoding"), "utf8", "str.search.encoding"); - mu_assert_eq(rz_config_get_i(core->config, "str.search.buffer_size"), 0x00b00123, "str.search.buffer_size"); + mu_assert_eq(rz_config_get_i(core->config, "search.str.min_length"), 6, "search.str.min_length"); + mu_assert_streq(rz_config_get(core->config, "search.str.encoding"), "utf8", "search.str.encoding"); + mu_assert_eq(rz_config_get_i(core->config, "search.str.buffer_size"), 0x00b00123, "search.str.buffer_size"); rz_core_free(core); mu_end; } @@ -1076,7 +1077,7 @@ int all_tests() { mu_run_test(test_load_v12); mu_run_test(test_load_v14); mu_run_test(test_load_v15_seek_history); - mu_run_test(test_load_v15_str_config); + mu_run_test(test_load_v15_19_str_config); mu_run_test(test_load_v16); mu_run_test(test_load_v17); return tests_passed != tests_run; From 4aa571e5c1e7bba3d4296c87d663b76a58141cfe Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 4 Feb 2025 14:52:45 -0500 Subject: [PATCH 099/157] Add string encoding to hit flag. --- librz/search/string_search.c | 4 +- test/db/cmd/cmd_search_z | 276 +++++++++++++++++------------------ 2 files changed, 140 insertions(+), 140 deletions(-) diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 0a3c7dcc752..72b25b05847 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -93,7 +93,9 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs ut64 str_mem_len; ut64 str_mem_offset; align_offsets(options, detected->type, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); - RzSearchHit *hit = rz_search_hit_new("string", str_mem_offset, str_mem_len); + char *hit_type = rz_str_newf("string.%s", rz_str_enc_as_string(detected->type)); + RzSearchHit *hit = rz_search_hit_new(hit_type, str_mem_offset, str_mem_len); + free(hit_type); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); ht_uu_free(options.utf8_to_mem_offset_map); diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index ca1b95376b6..a06fe11f356 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -13,13 +13,12 @@ RUN NAME=search escaped string FILE== CMDS=< Date: Tue, 4 Feb 2025 14:54:14 -0500 Subject: [PATCH 100/157] Change to new hit flag format --- test/db/cmd/cmd_search | 61 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index f5721347732..cddf1107f18 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -130,7 +130,7 @@ e search.show_progress=false /zj hello EOF EXPECT=< Date: Tue, 4 Feb 2025 14:54:36 -0500 Subject: [PATCH 101/157] Fix tests which emit more due to increased block size for search. --- test/db/cmd/cmd_ps | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/db/cmd/cmd_ps b/test/db/cmd/cmd_ps index 6006537dde9..1c7721ed89f 100644 --- a/test/db/cmd/cmd_ps +++ b/test/db/cmd/cmd_ps @@ -19,7 +19,6 @@ EOF EXPECT=< Date: Tue, 4 Feb 2025 15:07:59 -0500 Subject: [PATCH 102/157] Fixup cmd_search_hint --- test/db/cmd/cmd_search_hit | 93 ++++++++------------------------------ 1 file changed, 19 insertions(+), 74 deletions(-) diff --git a/test/db/cmd/cmd_search_hit b/test/db/cmd/cmd_search_hit index 1af8c8b51fe..5948921b70b 100644 --- a/test/db/cmd/cmd_search_hit +++ b/test/db/cmd/cmd_search_hit @@ -3,24 +3,24 @@ FILE=malloc://1024 CMDS=< Date: Tue, 4 Feb 2025 15:44:40 -0500 Subject: [PATCH 103/157] Fix: Add global address offset to hit. --- librz/search/string_search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 72b25b05847..4458837e23b 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -94,7 +94,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs ut64 str_mem_offset; align_offsets(options, detected->type, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); char *hit_type = rz_str_newf("string.%s", rz_str_enc_as_string(detected->type)); - RzSearchHit *hit = rz_search_hit_new(hit_type, str_mem_offset, str_mem_len); + RzSearchHit *hit = rz_search_hit_new(hit_type, str_mem_offset + offset, str_mem_len); free(hit_type); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); From 00c434b49f8e77450d6ca81487435cba75547a47 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 4 Feb 2025 15:45:05 -0500 Subject: [PATCH 104/157] Use new string search commands. --- test/db/cmd/cmd_search_in | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/test/db/cmd/cmd_search_in b/test/db/cmd/cmd_search_in index 94ebae8a588..f51628515f9 100644 --- a/test/db/cmd/cmd_search_in +++ b/test/db/cmd/cmd_search_in @@ -1,10 +1,11 @@ -NAME=/ search.in=io.maps without -m +NAME=/z search.in=io.maps without -m FILE=bins//wasm/inc.wast ARGS=-m 0x80000 CMDS=< Date: Thu, 6 Feb 2025 08:24:11 -0500 Subject: [PATCH 105/157] Rename search.str.buf_size to max_length. String length and buffer size are disconnected in future search. The buffer sizes are not controllable by the user. --- librz/arch/data.c | 2 +- librz/bin/bfile_string.c | 6 +++--- librz/core/canalysis.c | 2 +- librz/core/cconfig.c | 12 ++++++------ librz/core/cmd/cmd_print.c | 4 ++-- librz/core/cmeta.c | 2 +- librz/core/core.c | 2 +- librz/core/csearch.c | 8 ++++---- librz/core/project_migrate.c | 2 +- librz/include/rz_bin.h | 2 +- librz/include/rz_util/rz_str_search.h | 2 +- librz/main/rz-bin.c | 6 +++--- librz/search/search.c | 2 +- librz/util/str_search.c | 8 ++++---- test/db/cmd/cmd_i | 4 ++-- test/integration/test_project_migrate.c | 4 ++-- .../prj/{v18-str-config.rzdb => v19-str-config.rzdb} | 2 +- test/unit/test_str_search.c | 2 +- 18 files changed, 36 insertions(+), 36 deletions(-) rename test/prj/{v18-str-config.rzdb => v19-str-config.rzdb} (99%) diff --git a/librz/arch/data.c b/librz/arch/data.c index 4911816e62f..fe6a06c4d23 100644 --- a/librz/arch/data.c +++ b/librz/arch/data.c @@ -10,7 +10,7 @@ static bool get_string(const ut8 *buf, int size, RzDetectedString **dstr, RzStrE } RzUtilStrScanOptions opt = { - .buf_size = size, + .max_str_length = size, .max_uni_blocks = 4, .min_str_length = 4, .prefer_big_endian = big_endian, diff --git a/librz/bin/bfile_string.c b/librz/bin/bfile_string.c index 9654253fae5..bd07de881bd 100644 --- a/librz/bin/bfile_string.c +++ b/librz/bin/bfile_string.c @@ -83,7 +83,7 @@ static RzList /**/ *string_scan_range(SharedData *shared, co size_t buffer_size = RZ_MIN(shared->buffer_size, interval_size); RzUtilStrScanOptions scan_opt = { - .buf_size = buffer_size, + .max_str_length = buffer_size, .max_uni_blocks = shared->max_uni_blocks, .min_str_length = shared->min_str_length, .prefer_big_endian = shared->prefer_big_endian, @@ -312,7 +312,7 @@ RZ_API void rz_bin_string_search_opt_init(RZ_NONNULL RzBinStringSearchOpt *opt) rz_return_if_fail(opt); opt->max_threads = RZ_THREAD_N_CORES_ALL_AVAILABLE; opt->min_length = RZ_BIN_STRING_SEARCH_MIN_STRING; - opt->buffer_size = RZ_BIN_STRING_SEARCH_BUFFER_SIZE; + opt->max_length = RZ_BIN_STRING_SEARCH_BUFFER_SIZE; opt->max_uni_blocks = RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS; opt->max_region_size = RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE; opt->raw_alignment = RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT; @@ -464,7 +464,7 @@ RZ_API RZ_OWN RzPVector /**/ *rz_bin_file_strings(RZ_NONNULL RzBi .lock = lock, .bf = bf, .strings_db = strings_db, - .buffer_size = opt->buffer_size, + .buffer_size = opt->max_length, .string_encoding = opt->string_encoding, .max_uni_blocks = opt->max_uni_blocks, .min_str_length = opt->min_length, diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index f2c32b54a9b..1ee54547e3f 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -75,7 +75,7 @@ static bool find_string_at(RzCore *core, RzBinObject *bobj, ut64 pointer, char * RzStrEnc strenc = bin->str_search_cfg.string_encoding; RzUtilStrScanOptions scan_opt = { - .buf_size = sizeof(buffer), + .max_str_length = sizeof(buffer), .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 894b1a843e2..3856ad1d628 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1134,8 +1134,8 @@ static bool cb_search_str_min_length(void *user, void *data) { if (node->i_value < 1) { RZ_LOG_ERROR("search.str.min_length cannot be less than 1.\n"); return false; - } else if (node->i_value >= core->bin->str_search_cfg.buffer_size) { - RZ_LOG_ERROR("search.str.buffer_size cannot be greater or equal to %" PFMTSZu ".\n", core->bin->str_search_cfg.buffer_size); + } else if (node->i_value >= core->bin->str_search_cfg.max_length) { + RZ_LOG_ERROR("search.str.max_length cannot be greater or equal to %" PFMTSZu ".\n", core->bin->str_search_cfg.max_length); return false; } @@ -1149,17 +1149,17 @@ static bool cb_search_str_min_length(void *user, void *data) { return true; } -static bool cb_search_str_buffer_size(void *user, void *data) { +static bool cb_search_str_max_length(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; size_t min_buffer_size = RZ_MIN(core->bin->str_search_cfg.min_length, RZ_BIN_STRING_SEARCH_BUFFER_SIZE); if (node->i_value < min_buffer_size) { - RZ_LOG_ERROR("search.str.buffer_size cannot be less than %" PFMTSZu ".\n", min_buffer_size); + RZ_LOG_ERROR("search.str.max_length cannot be less than %" PFMTSZu ".\n", min_buffer_size); return false; } - core->bin->str_search_cfg.buffer_size = node->i_value; + core->bin->str_search_cfg.max_length = node->i_value; if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { RzBinFile *bf = rz_bin_cur(core->bin); if (bf && bf->o) { @@ -3782,7 +3782,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETBPREF("search.overlap", "true", "Look for overlapped search hits."); SETICB("search.io.alignment", 1, &cb_searchalignment, "Only search at set byte alignment."); SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find."); - SETICB("search.str.buffer_size", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_buffer_size, "Maximum buffer size, which will also determine the maximum string length."); + SETICB("search.str.max_length", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_max_length, "Maximum buffer size, which will also determine the maximum string length."); SETICB("search.str.max_uni_blocks", RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS, &cb_search_str_max_uni_blocks, "Maximum number of unicode blocks."); SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 75a84301701..40ebd215737 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -2163,7 +2163,7 @@ RZ_IPI RzCmdStatus rz_print_strings_current_block_handler(RzCore *core, int argc RzDetectedString *detected = NULL; RzBin *bin = core->bin; RzUtilStrScanOptions scan_opt = { - .buf_size = core->blocksize, + .max_str_length = core->blocksize, .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = false, @@ -2198,7 +2198,7 @@ RZ_IPI RzCmdStatus rz_print_first_string_current_block_handler(RzCore *core, int RzDetectedString *detected = NULL; RzBin *bin = core->bin; RzUtilStrScanOptions scan_opt = { - .buf_size = core->blocksize, + .max_str_length = core->blocksize, .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = false, diff --git a/librz/core/cmeta.c b/librz/core/cmeta.c index 1ec593bc926..d974dc423e9 100644 --- a/librz/core/cmeta.c +++ b/librz/core/cmeta.c @@ -436,7 +436,7 @@ static bool meta_string_guess_add(RzCore *core, ut64 addr, size_t limit, char ** } bool big_endian = rz_config_get_b(core->config, "cfg.bigendian"); RzUtilStrScanOptions scan_opt = { - .buf_size = bin->str_search_cfg.buffer_size, + .max_str_length = bin->str_search_cfg.max_length, .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = big_endian, diff --git a/librz/core/core.c b/librz/core/core.c index d1793e26e72..7bd45e17f6e 100644 --- a/librz/core/core.c +++ b/librz/core/core.c @@ -982,7 +982,7 @@ static bool get_string(const ut8 *buf, int size, RzDetectedString **dstr, RzStrE } RzUtilStrScanOptions opt = { - .buf_size = size, + .max_str_length = size, .max_uni_blocks = 4, .min_str_length = 4, .prefer_big_endian = big_endian, diff --git a/librz/core/csearch.c b/librz/core/csearch.c index 12d1c793453..a60f2e25b9f 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -176,8 +176,8 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor RZ_LOG_ERROR("core: invalid string: empty string.\n"); return NULL; } - if (strlen(re_pattern) >= core->bin->str_search_cfg.buffer_size) { - RZ_LOG_ERROR("core: String to search is larger then search.str.buffer_size.\n"); + if (strlen(re_pattern) >= core->bin->str_search_cfg.max_length) { + RZ_LOG_ERROR("core: String to search is larger then search.str.max_length.\n"); return NULL; } @@ -185,7 +185,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor RzUtilStrScanOptions scan_opt = { // buf_size is effectively the maximum string length. // Gets renamed with the refactor. - .buf_size = core->bin->str_search_cfg.buffer_size, + .max_str_length = core->bin->str_search_cfg.max_length, .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, .min_str_length = core->bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, @@ -208,7 +208,7 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor RZ_LOG_ERROR("core: Setting up search from core failed.\n"); goto quit; } - if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, scan_opt.buf_size)) { + if (!rz_search_opt_set_elemet_size(user_opts ? user_opts : search_opts, scan_opt.max_str_length)) { RZ_LOG_ERROR("search: Failed to update chunk size in the search options.\n"); goto quit; } diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 2f1447a855a..2099b3088f0 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -691,7 +691,7 @@ RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *re RZ_SERIALIZE_SUB(core_db, config_db, res, "config", return false;); sdb_rename(config_db, "str.search.max_threads", "search.max_threads"); sdb_rename(config_db, "str.search.min_length", "search.str.min_length"); - sdb_rename(config_db, "str.search.buffer_size", "search.str.buffer_size"); + sdb_rename(config_db, "str.search.buffer_size", "search.str.max_length"); sdb_rename(config_db, "str.search.max_uni_blocks", "search.str.max_uni_blocks"); sdb_rename(config_db, "str.search.max_region_size", "search.str.max_region_size"); sdb_rename(config_db, "str.search.raw_alignment", "search.str.raw_alignment"); diff --git a/librz/include/rz_bin.h b/librz/include/rz_bin.h index e9f03044f1d..bc9579ffc5e 100644 --- a/librz/include/rz_bin.h +++ b/librz/include/rz_bin.h @@ -203,7 +203,7 @@ typedef enum { typedef struct rz_bin_string_search_opt_t { RzThreadNCores max_threads; ///< Maximum thread number (normally set to RZ_THREAD_N_CORES_ALL_AVAILABLE). size_t min_length; ///< Smallest string length that is possible to find. - size_t buffer_size; ///< Maximum buffer size, which will also determine the maximum string length. + size_t max_length; ///< Maximum buffer size, which will also determine the maximum string length. size_t max_uni_blocks; ///< Maximum number of unicode blocks size_t max_region_size; ///< Maximum allowable size for the search interval between two memory regions. size_t raw_alignment; ///< Memory sector alignment used for the raw string search. diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index b8835ae48c4..69df82a6199 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -28,7 +28,7 @@ typedef struct { * Defines the search parameters for rz_scan_strings */ typedef struct { - size_t buf_size; ///< Maximum size of a detected string + size_t max_str_length; ///< Maximum size of a detected string. size_t max_uni_blocks; ///< Maximum number of Unicode blocks size_t min_str_length; ///< Minimum string length bool prefer_big_endian; ///< True if the preferred endianess for UTF strings is big-endian diff --git a/librz/main/rz-bin.c b/librz/main/rz-bin.c index ef2ab64f52e..3d98026b35b 100644 --- a/librz/main/rz-bin.c +++ b/librz/main/rz-bin.c @@ -240,7 +240,7 @@ static int rzbin_show_help(int v) { " RZ_BIN_DEBUGINFOD_URLS: e bin.dbginfo.debuginfod_urls # use alternative debuginfod server\n" " RZ_BIN_DEMANGLE=0: e bin.demangle # do not demangle symbols\n" " RZ_BIN_LANG: e bin.lang # assume lang for demangling\n" - " RZ_BIN_MAXSTRBUF: e search.str.buffer_size # specify maximum buffer size\n" + " RZ_BIN_MAXSTRBUF: e search.str.max_length # specify maximum buffer size\n" " RZ_BIN_PDBSERVER: e pdb.server # use alternative PDB server\n" " RZ_BIN_PREFIX: e bin.prefix # prefix symbols/sections/relocs with a specific string\n" " RZ_BIN_STRFILTER: e bin.str.filter # rizin -qc 'e bin.str.filter=?" @@ -784,7 +784,7 @@ RZ_API int rz_main_rz_bin(int argc, const char **argv) { if ((tmp = rz_sys_getenv("RZ_BIN_MAXSTRBUF"))) { if (rz_num_is_valid_input(NULL, tmp)) { ut64 value = rz_num_math(NULL, tmp); - rz_config_set_i(core.config, "search.str.buffer_size", value); + rz_config_set_i(core.config, "search.str.max_length", value); } free(tmp); } @@ -991,7 +991,7 @@ RZ_API int rz_main_rz_bin(int argc, const char **argv) { rz_config_set_i(core.config, "search.str.min_length", value); if (tmp) { value = rz_num_math(NULL, tmp + 1); - rz_config_set_i(core.config, "search.str.buffer_size", value); + rz_config_set_i(core.config, "search.str.max_length", value); } break; } diff --git a/librz/search/search.c b/librz/search/search.c index dbfd855403f..88c03d33edd 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -80,7 +80,7 @@ RZ_API int rz_search_strings_update(RzSearch *s, ut64 from, const ut8 *buf, int rz_return_val_if_fail(s && buf && len, -1); RzUtilStrScanOptions scan_opt = { - .buf_size = len, + .max_str_length = len, .max_uni_blocks = s->string_max, .min_str_length = s->string_min, .prefer_big_endian = false, diff --git a/librz/util/str_search.c b/librz/util/str_search.c index f3713fc1a34..ffa5c2609d0 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -210,7 +210,7 @@ static ut64 adjust_offset(RzStrEnc str_type, const ut8 *buf, const ut64 str_star } static inline size_t buf_look_ahead(const RzUtilStrScanOptions *opt, RzStrEnc enc) { - if (opt->buf_size < opt->min_str_length) { + if (opt->max_str_length < opt->min_str_length) { return 0; } switch (enc) { @@ -234,7 +234,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 return NULL; } - ut8 *strbuf = RZ_NEWS0(ut8, opt->buf_size); + ut8 *strbuf = RZ_NEWS0(ut8, opt->max_str_length); if (!strbuf) { goto error; } @@ -243,7 +243,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 int rc = 0, i = 0, runes = 0; /* Eat a whole C string */ - for (i = 0; i < opt->buf_size - look_ahead && needle < to; i += rc) { + for (i = 0; i < opt->max_str_length - look_ahead && needle < to; i += rc) { RzCodePoint r = 0; switch(str_type) { @@ -308,7 +308,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 rc = rz_utf8_encode(strbuf + i, r); runes++; } else if (r && r < 0x100 && is_c_escape_sequence((char)r)) { - if ((i + 32) < opt->buf_size && r < 93) { + if ((i + 32) < opt->max_str_length && r < 93) { rc = rz_utf8_encode(strbuf + i, r); } else { // String too long diff --git a/test/db/cmd/cmd_i b/test/db/cmd/cmd_i index fab45383a82..1d30c328854 100644 --- a/test/db/cmd/cmd_i +++ b/test/db/cmd/cmd_i @@ -3224,7 +3224,7 @@ echo -- geq 0 -- e search.str.min_length=1 iz echo -- small buffer 12 -- -e search.str.buffer_size=13 +e search.str.max_length=13 iz EOF EXPECT=<config, "search.str.min_length"), 6, "search.str.min_length"); mu_assert_streq(rz_config_get(core->config, "search.str.encoding"), "utf8", "search.str.encoding"); - mu_assert_eq(rz_config_get_i(core->config, "search.str.buffer_size"), 0x00b00123, "search.str.buffer_size"); + mu_assert_eq(rz_config_get_i(core->config, "search.str.max_length"), 0x00b00123, "search.str.max_length"); rz_core_free(core); mu_end; } diff --git a/test/prj/v18-str-config.rzdb b/test/prj/v19-str-config.rzdb similarity index 99% rename from test/prj/v18-str-config.rzdb rename to test/prj/v19-str-config.rzdb index a30fbecd49a..709ebeeffb4 100644 --- a/test/prj/v18-str-config.rzdb +++ b/test/prj/v19-str-config.rzdb @@ -4772,7 +4772,7 @@ stack.delta=0 stack.reg=SP stack.size=64 str.escbslash=false -str.search.buffer_size=5 +str.search.max_length=5 str.search.check_ascii_freq=false str.search.encoding=utf32be str.search.max_region_size=0x005555555 diff --git a/test/unit/test_str_search.c b/test/unit/test_str_search.c index 6ff0e867085..8f327710d5d 100644 --- a/test/unit/test_str_search.c +++ b/test/unit/test_str_search.c @@ -5,7 +5,7 @@ #include "minunit.h" static RzUtilStrScanOptions g_opt = { - .buf_size = 2048, + .max_str_length = 2048, .max_uni_blocks = 4, .min_str_length = 4, .prefer_big_endian = false, From 64d98e0517678e112072539aa8a283d50352b4fe Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 6 Feb 2025 08:57:53 -0500 Subject: [PATCH 106/157] Move duplicated code into static function. --- librz/core/cconfig.c | 58 ++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 3856ad1d628..96c627f552c 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1128,6 +1128,15 @@ static bool cb_search_max_threads(void *user, void *data) { return true; } +static void check_reload_bin_str_search(RzCore *core) { + if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { + RzBinFile *bf = rz_bin_cur(core->bin); + if (bf && bf->o) { + rz_bin_object_reset_strings(core->bin, bf, bf->o); + } + } +} + static bool cb_search_str_min_length(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; @@ -1140,12 +1149,7 @@ static bool cb_search_str_min_length(void *user, void *data) { } core->bin->str_search_cfg.min_length = node->i_value; - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return true; } @@ -1160,12 +1164,7 @@ static bool cb_search_str_max_length(void *user, void *data) { } core->bin->str_search_cfg.max_length = node->i_value; - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return true; } @@ -1177,12 +1176,7 @@ static bool cb_search_str_max_uni_blocks(void *user, void *data) { return false; } core->bin->str_search_cfg.max_uni_blocks = node->i_value; - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return true; } @@ -1194,12 +1188,7 @@ static bool cb_search_str_max_region_size(void *user, void *data) { return false; } core->bin->str_search_cfg.max_region_size = node->i_value; - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return true; } @@ -1225,12 +1214,7 @@ static bool cb_search_str_check_ascii_freq(void *user, void *data) { return false; } core->bin->str_search_cfg.check_ascii_freq = rz_str_is_true(node->value); - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return true; } @@ -1266,12 +1250,7 @@ static bool cb_search_str_encoding(void *user, void *data) { } core->bin->str_search_cfg.string_encoding = encoding; - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return true; } @@ -1292,12 +1271,7 @@ static bool cb_str_search_mode(void *user, void *data) { return true; } RZ_LOG_ERROR("Invalid value for str.search.mode (%s).\n", node->value); - if (core->bin && rz_config_get_b(core->config, "str.search.reload")) { - RzBinFile *bf = rz_bin_cur(core->bin); - if (bf && bf->o) { - rz_bin_object_reset_strings(core->bin, bf, bf->o); - } - } + check_reload_bin_str_search(core); return false; } From b89bb090fbde0ee9481c37b2bd7e2f861825a7c3 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 6 Feb 2025 08:58:10 -0500 Subject: [PATCH 107/157] Reduce block size again to old value. --- librz/include/rz_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 84e984d7eb1..f75b3f320e1 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -44,7 +44,7 @@ RZ_LIB_VERSION_HEADER(rz_core); #define RZ_CORE_CMD_INVALID -1 #define RZ_CORE_CMD_EXIT -2 -#define RZ_CORE_BLOCKSIZE 0x1000 +#define RZ_CORE_BLOCKSIZE 0x100 #define RZ_CORE_BLOCKSIZE_MAX 0x3200000 /* 32MB */ #define RZ_FLAGS_FS_CLASSES "classes" From 5fe207c53157e3dfc9551e44ac42dc975e366344 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Thu, 6 Feb 2025 09:06:03 -0500 Subject: [PATCH 108/157] Set block size in tests instead of increasing the default one. --- librz/core/cmd_descs/cmd_descs.c | 7 +- librz/core/cmd_descs/cmd_print.yaml | 8 +- test/db/cmd/cmd_search_z | 110 ++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 22478559b1b..a5bc4580fb0 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -15943,12 +15943,13 @@ static const RzCmdDescHelp cmd_print_raw_string_help = { }; static const RzCmdDescHelp ps_help = { - .summary = "Print string at the current offset", + .summary = "Print string at the current offset.", }; static const RzCmdDescDetailEntry print_string_Value_space_details_detail_entries[] = { + { .text = "String length", .arg_str = NULL, .comment = "The string length depends on the block size. You need to change it via 'b ' if your string is too short." }, { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'search.str.encoding' option." }, { .text = "delimeter=null", .arg_str = NULL, .comment = "String is NUL terminated." }, - { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (dosn't stop at non-printable character)." }, + { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (dons't stop at non-printable character)." }, { 0 }, }; static const RzCmdDescDetail print_string_details[] = { @@ -15976,7 +15977,7 @@ static const RzCmdDescArg print_string_args[] = { { 0 }, }; static const RzCmdDescHelp print_string_help = { - .summary = "Print the string at the current offset.", + .summary = "Print the string at the current offset in the block.", .details = print_string_details, .args = print_string_args, }; diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index 70ed084fbe8..cc7b028137a 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1094,10 +1094,10 @@ commands: type: RZ_CMD_ARG_TYPE_RZNUM optional: true - name: ps - summary: Print string at the current offset + summary: Print string at the current offset. subcommands: - name: ps - summary: Print the string at the current offset. + summary: Print the string at the current offset in the block. cname: print_string modes: - RZ_OUTPUT_MODE_STANDARD @@ -1127,12 +1127,14 @@ commands: details: - name: Value details entries: + - text: "String length" + comment: "The string length depends on the block size. You need to change it via 'b ' if your string is too short." - text: "encoding=settings" comment: "Use encoding from 'search.str.encoding' option." - text: "delimeter=null" comment: "String is NUL terminated." - text: "delimeter=block" - comment: "Print whole block as string (dosn't stop at non-printable character)." + comment: "Print whole block as string (dons't stop at non-printable character)." - name: ps+ summary: Print libc++ std::string (same-endian, ascii, zero-terminated) cname: print_string_as_libcpp_string diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index a06fe11f356..d7bd3d5a4b9 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -66,6 +66,8 @@ CMDS=< Date: Fri, 7 Feb 2025 09:53:56 -0500 Subject: [PATCH 109/157] By default search for literal string, not for regex and for the encoding of the settings. --- librz/core/cmd/cmd_search.c | 10 +- librz/core/cmd_descs/cmd_descs.c | 25 +++-- librz/core/cmd_descs/cmd_search.yaml | 27 +++-- librz/include/rz_util/rz_regex.h | 1 + librz/search/string_search.c | 2 +- test/db/cmd/cmd_search_z | 154 +++++++++++++++------------ 6 files changed, 129 insertions(+), 90 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 6450ed78ca0..6e9dcc2a0e1 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2953,6 +2953,9 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c } expected = rz_str_enc_string_as_type(encoding); + if (expected == RZ_STRING_ENC_SETTINGS) { + expected = rz_str_enc_string_as_type(rz_config_get(core->config, "search.str.encoding")); + } if (!RZ_STR_EQ(encoding, "guess") && expected == RZ_STRING_ENC_GUESS) { RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); goto invalid_args; @@ -2986,11 +2989,14 @@ static RzRegexFlags parse_re_flag_desc(const char *re_flags_desc) { return flags; } size_t fcount = 0; - if (strchr(re_flags_desc, 'd')) { + if (strchr(re_flags_desc, 'i')) { fcount++; flags |= RZ_REGEX_CASELESS; } - if (strchr(re_flags_desc, 'i')) { + if (strchr(re_flags_desc, 'l')) { + return RZ_REGEX_LITERAL; + } + if (strchr(re_flags_desc, 'r')) { fcount++; flags |= RZ_REGEX_CASELESS; } diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index a5bc4580fb0..be485087ecb 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -20,7 +20,7 @@ static const RzCmdDescDetail slash_v_details[2]; static const RzCmdDescDetail slash_V_details[2]; static const RzCmdDescDetail cmd_search_hex_details[2]; static const RzCmdDescDetail cmd_search_hex_regex_details[2]; -static const RzCmdDescDetail slash_z_details[3]; +static const RzCmdDescDetail slash_z_details[4]; static const RzCmdDescDetail base64_encode_details[2]; static const RzCmdDescDetail base64_decode_details[2]; static const RzCmdDescDetail print_boundaries_prot_details[2]; @@ -2413,39 +2413,46 @@ static const RzCmdDescDetailEntry slash_z_Encodings_detail_entries[] = { }; static const RzCmdDescDetailEntry slash_z_Regex_space_Flags_detail_entries[] = { - { .text = "d", .arg_str = NULL, .comment = "Default (No flag, Unicode is matched)" }, + { .text = "l", .arg_str = NULL, .comment = "Default. Literal string comparison. Ignores all meta-characters." }, { .text = "i", .arg_str = NULL, .comment = "Caseless (equivalent: PCRE2_CASELESS)" }, - { .text = "e", .arg_str = NULL, .comment = "Extended (equivalent: PCRE2_EXTENDED)" }, - { .text = "E", .arg_str = NULL, .comment = "Extended More (equivalent: PCRE2_EXTENDED_MORE)" }, - { .text = "m", .arg_str = NULL, .comment = "Multiline (equivalent: PCRE2_MULTILINE)" }, + { .text = "r", .arg_str = NULL, .comment = "Regular expression." }, + { .text = "m", .arg_str = NULL, .comment = "Multiline regular expression (equivalent flag: PCRE2_MULTILINE)" }, + { 0 }, +}; + +static const RzCmdDescDetailEntry slash_z_Exampls_detail_entries[] = { + { .text = "/z (ABC*)", .arg_str = NULL, .comment = "Search the exact string: \"(ABC*)\"." }, + { .text = "/z (ABC*)D li", .arg_str = NULL, .comment = "Search the exact string \"(ABC*)\" but case insensitive." }, + { .text = "/z (ABC*)D ri", .arg_str = NULL, .comment = "Search the regular expression \"(ABC*)D\" but case insensitive." }, { 0 }, }; static const RzCmdDescDetail slash_z_details[] = { { .name = "Encodings", .entries = slash_z_Encodings_detail_entries }, { .name = "Regex Flags", .entries = slash_z_Regex_space_Flags_detail_entries }, + { .name = "Exampls", .entries = slash_z_Exampls_detail_entries }, { 0 }, }; static const RzCmdDescHelp slash_z_help = { .summary = "String search.", .details = slash_z_details, }; -static const char *cmd_search_string_sensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; +static const char *cmd_search_string_sensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL }; static const RzCmdDescArg cmd_search_string_sensitive_args[] = { { - .name = "string", + .name = "regex", .type = RZ_CMD_ARG_TYPE_STRING, }, { .name = "regex_flags", .type = RZ_CMD_ARG_TYPE_STRING, - .default_value = "d", + .default_value = "l", }, { .name = "encoding", .type = RZ_CMD_ARG_TYPE_CHOICES, - .default_value = "guess", + .default_value = "settings", .choices.choices = cmd_search_string_sensitive_encoding_choices, }, diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 1df7c6ef7d9..98198209d5c 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -772,16 +772,22 @@ commands: comment: "EBCDIC-US encoding. Alias: csEBCDICUS" - name: "Regex Flags" entries: - - text: "d" - comment: "Default (No flag, Unicode is matched)" + - text: "l" + comment: "Default. Literal string comparison. Ignores all meta-characters." - text: "i" comment: "Caseless (equivalent: PCRE2_CASELESS)" - - text: "e" - comment: "Extended (equivalent: PCRE2_EXTENDED)" - - text: "E" - comment: "Extended More (equivalent: PCRE2_EXTENDED_MORE)" + - text: "r" + comment: "Regular expression." - text: "m" - comment: "Multiline (equivalent: PCRE2_MULTILINE)" + comment: "Multiline regular expression (equivalent flag: PCRE2_MULTILINE)" + - name: "Exampls" + entries: + - text: "/z (ABC*)" + comment: "Search the exact string: \"(ABC*)\"." + - text: "/z (ABC*)D li" + comment: "Search the exact string \"(ABC*)\" but case insensitive." + - text: "/z (ABC*)D ri" + comment: "Search the regular expression \"(ABC*)D\" but case insensitive." subcommands: - name: "/z" summary: String search. @@ -794,14 +800,14 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: string + - name: regex type: RZ_CMD_ARG_TYPE_STRING - name: regex_flags type: RZ_CMD_ARG_TYPE_STRING - default_value: "d" + default_value: "l" - name: encoding type: RZ_CMD_ARG_TYPE_CHOICES - default_value: "guess" + default_value: "settings" choices: - "ascii" - "8bit" @@ -816,3 +822,4 @@ commands: - "ebcdices" - "ebcdicuk" - "ebcdicus" + - "guess" diff --git a/librz/include/rz_util/rz_regex.h b/librz/include/rz_util/rz_regex.h index b1993804bc5..c039acacee4 100644 --- a/librz/include/rz_util/rz_regex.h +++ b/librz/include/rz_util/rz_regex.h @@ -25,6 +25,7 @@ * D is inspected during pcre2_dfa_match() execution (not used). */ #define RZ_REGEX_DEFAULT 0 +#define RZ_REGEX_LITERAL 0x02000000u /* PCRE2_LITERAL - C */ #define RZ_REGEX_CASELESS 0x00000008u /* PCRE2_CASELESS - C */ #define RZ_REGEX_EXTENDED 0x00000080u /* PCRE2_EXTENDED - C */ #define RZ_REGEX_EXTENDED_MORE 0x01000000u /* PCRE2_EXTENDED_MORE - C */ diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 4458837e23b..cd8e8123a30 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -79,7 +79,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs void **it_m = NULL; rz_pvector_foreach (ss->strings, it_m) { RzDetectedString *find = *it_m; - RzPVector *matches = rz_regex_match_all(find->regex, detected->string, detected->size, 0, RZ_REGEX_DEFAULT); + RzPVector *matches = rz_regex_match_all(find->regex, detected->string, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT); void **it; rz_pvector_foreach (matches, it) { RzPVector *match = *it; diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index d7bd3d5a4b9..390a10275b5 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -10,18 +10,6 @@ ERROR: core: invalid string: empty string. EOF RUN -NAME=search escaped string -FILE== -CMDS=< Date: Fri, 7 Feb 2025 09:58:10 -0500 Subject: [PATCH 110/157] Add unit test for ibm290 scanning. --- test/unit/test_str_search.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/unit/test_str_search.c b/test/unit/test_str_search.c index 8f327710d5d..b624ad72825 100644 --- a/test/unit/test_str_search.c +++ b/test/unit/test_str_search.c @@ -31,6 +31,24 @@ bool test_rz_scan_strings_detect_ascii(void) { mu_end; } +bool test_rz_scan_strings_detect_ibm290(void) { + static const unsigned char expected[] = "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x58\x5a\x5b\x5c\x5d\x5e\x5f\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9d\x9e\x9f\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xac\xad\xae\xaf\xba\xbb\xbc\xbd\xbe\xbf\xbf\x00"; + RzBuffer *buf = rz_buf_new_with_bytes(expected, sizeof(expected)); + + RzList *str_list = rz_list_newf((RzListFree)rz_detected_string_free); + int n = rz_scan_strings(buf, str_list, &g_opt, 0, rz_buf_size(buf) - 1, RZ_STRING_ENC_IBM290); + mu_assert_eq(n, 1, "rz_scan_strings ibm290, number of strings"); + + RzDetectedString *s = rz_list_get_n(str_list, 0); + mu_assert_streq(s->string, " 。「」、・ヲァィゥ£.<(+|&ェォャュョッー!¥*);¬アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフ¯ヘホマミムメモヤユヨラリルレロワン゛゜゜", "rz_scan_strings ibm290, different string"); + mu_assert_eq(s->type, RZ_STRING_ENC_IBM290, "rz_scan_strings ibm290, string type"); + + rz_list_free(str_list); + rz_buf_free(buf); + + mu_end; +} + bool test_rz_scan_strings_detect_ibm037(void) { static const unsigned char str[] = "\xc9\x40\x81\x94\x40\x81\x95\x40\xc9\xc2\xd4\xf0\xf3\xf7\x40\xa2\xa3\x99\x89\x95\x87\x25"; RzBuffer *buf = rz_buf_new_with_bytes(str, sizeof(str)); @@ -327,6 +345,7 @@ bool test_rz_scan_strings_extended_ascii(void) { bool all_tests() { mu_run_test(test_rz_scan_strings_detect_ascii); mu_run_test(test_rz_scan_strings_detect_ibm037); + mu_run_test(test_rz_scan_strings_detect_ibm290); mu_run_test(test_rz_scan_strings_detect_utf8); mu_run_test(test_rz_scan_strings_detect_utf16_le); mu_run_test(test_rz_scan_strings_detect_utf16_le_special_chars); From 92498fdc20900d1edc2b9cc4857a0af3ce364e46 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 7 Feb 2025 10:05:38 -0500 Subject: [PATCH 111/157] Rename search.str.encoding to str.encoding. The string encoding property is not only used by search. But also by ps and other commands. Hence it shouldn't be in the same group as search settings. --- librz/core/cconfig.c | 6 +- librz/core/cmd/cmd_search.c | 2 +- librz/core/cmd_descs/cmd_descs.c | 2 +- librz/core/cmd_descs/cmd_print.yaml | 2 +- librz/core/project_migrate.c | 2 +- librz/include/rz_util/rz_str.h | 2 +- librz/util/str.c | 2 +- test/db/archos/darwin-x64/dbg | 2 +- test/db/cmd/cmd_graph | 2 +- test/db/cmd/cmd_i | 10 ++-- test/db/cmd/cmd_pd | 78 ++++++++++++------------- test/db/cmd/cmd_pd2 | 8 +-- test/db/cmd/cmd_ps | 14 ++--- test/db/cmd/cmd_psj | 4 +- test/db/cmd/cmd_search_z | 2 +- test/db/cmd/write | 6 +- test/db/formats/mach0/fatmach0 | 4 +- test/db/formats/mach0/mach0 | 2 +- test/db/rzil/ppc32 | 4 +- test/db/rzil/ppc64 | 4 +- test/integration/test_project_migrate.c | 6 +- test/prj/v19-str-config.rzdb | 2 +- 22 files changed, 83 insertions(+), 83 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 96c627f552c..9c3251518e1 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1233,7 +1233,7 @@ static bool find_encoding(RzConfigNode *node, RzStrEnc *encoding) { return false; } -static bool cb_search_str_encoding(void *user, void *data) { +static bool cb_str_encoding(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; RzStrEnc encoding = RZ_STRING_ENC_GUESS; @@ -1245,7 +1245,7 @@ static bool cb_search_str_encoding(void *user, void *data) { "if utf8 char detected then utf8 else 8bit\n"); return false; } else if (RZ_STR_EQ("settings", node->value) || (rz_str_casecmp("guess", node->value) && !found_enc)) { - RZ_LOG_ERROR("Invalid value for search.str.encoding (%s).\n", node->value); + RZ_LOG_ERROR("Invalid value for str.encoding (%s).\n", node->value); return false; } @@ -3761,7 +3761,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); - n = NODECB("search.str.encoding", "guess", &cb_search_str_encoding); + n = NODECB("search.str.encoding", "guess", &cb_str_encoding); SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 6e9dcc2a0e1..84b9f916c9b 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2954,7 +2954,7 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c expected = rz_str_enc_string_as_type(encoding); if (expected == RZ_STRING_ENC_SETTINGS) { - expected = rz_str_enc_string_as_type(rz_config_get(core->config, "search.str.encoding")); + expected = rz_str_enc_string_as_type(rz_config_get(core->config, "str.encoding")); } if (!RZ_STR_EQ(encoding, "guess") && expected == RZ_STRING_ENC_GUESS) { RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index be485087ecb..c3a60ebd48a 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -15954,7 +15954,7 @@ static const RzCmdDescHelp ps_help = { }; static const RzCmdDescDetailEntry print_string_Value_space_details_detail_entries[] = { { .text = "String length", .arg_str = NULL, .comment = "The string length depends on the block size. You need to change it via 'b ' if your string is too short." }, - { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'search.str.encoding' option." }, + { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'str.encoding' option." }, { .text = "delimeter=null", .arg_str = NULL, .comment = "String is NUL terminated." }, { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (dons't stop at non-printable character)." }, { 0 }, diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index cc7b028137a..c79f5a45cf1 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1130,7 +1130,7 @@ commands: - text: "String length" comment: "The string length depends on the block size. You need to change it via 'b ' if your string is too short." - text: "encoding=settings" - comment: "Use encoding from 'search.str.encoding' option." + comment: "Use encoding from 'str.encoding' option." - text: "delimeter=null" comment: "String is NUL terminated." - text: "delimeter=block" diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 2099b3088f0..1d816822de0 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -696,7 +696,7 @@ RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *re sdb_rename(config_db, "str.search.max_region_size", "search.str.max_region_size"); sdb_rename(config_db, "str.search.raw_alignment", "search.str.raw_alignment"); sdb_rename(config_db, "str.search.check_ascii_freq", "search.str.check_ascii_freq"); - sdb_rename(config_db, "str.search.encoding", "search.str.encoding"); + sdb_rename(config_db, "str.search.encoding", "str.encoding"); return true; } diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index f0894c10541..5b4bf9e574e 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -31,7 +31,7 @@ typedef enum { RZ_STRING_ENC_EBCDIC_US = 's', RZ_STRING_ENC_EBCDIC_ES = 't', RZ_STRING_ENC_GUESS = 'g', - RZ_STRING_ENC_SETTINGS = 'S', ///< Use search.str.encoding. + RZ_STRING_ENC_SETTINGS = 'S', ///< Use str.encoding. } RzStrEnc; /** diff --git a/librz/util/str.c b/librz/util/str.c index 4b21e000eaf..856ae98c893 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -72,7 +72,7 @@ RZ_API const char *rz_str_enc_as_string(RzStrEnc enc) { case RZ_STRING_ENC_GUESS: return "guessed"; case RZ_STRING_ENC_SETTINGS: - return "search.str.encoding"; + return "str.encoding"; default: rz_warn_if_reached(); return "unknown"; diff --git a/test/db/archos/darwin-x64/dbg b/test/db/archos/darwin-x64/dbg index c204f35f323..51b0330115c 100644 --- a/test/db/archos/darwin-x64/dbg +++ b/test/db/archos/darwin-x64/dbg @@ -81,7 +81,7 @@ dcu main 3 ds dr rip dr rdi -ps @e:search.str.encoding=utf8 @ rdi +ps @e:str.encoding=utf8 @ rdi EOF EXPECT=<config, "search.str.min_length"), 6, "search.str.min_length"); - mu_assert_streq(rz_config_get(core->config, "search.str.encoding"), "utf8", "search.str.encoding"); + mu_assert_streq(rz_config_get(core->config, "str.encoding"), "utf8", "str.encoding"); mu_assert_eq(rz_config_get_i(core->config, "search.str.max_length"), 0x00b00123, "search.str.max_length"); rz_core_free(core); mu_end; diff --git a/test/prj/v19-str-config.rzdb b/test/prj/v19-str-config.rzdb index 709ebeeffb4..ea159f7039b 100644 --- a/test/prj/v19-str-config.rzdb +++ b/test/prj/v19-str-config.rzdb @@ -4774,7 +4774,7 @@ stack.size=64 str.escbslash=false str.search.max_length=5 str.search.check_ascii_freq=false -str.search.encoding=utf32be +str.encoding=utf32be str.search.max_region_size=0x005555555 str.search.max_threads=5 str.search.max_uni_blocks=5 From 9ab85288f2a28e141afaefc148e4e717ed36fbb7 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 7 Feb 2025 10:05:49 -0500 Subject: [PATCH 112/157] Set default encoding to UTF-8 --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 9c3251518e1..16753ea3d80 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3761,7 +3761,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); - n = NODECB("search.str.encoding", "guess", &cb_str_encoding); + n = NODECB("search.str.encoding", "utf8", &cb_str_encoding); SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); From 648483e994dc86a97e8453d275364e4c3d463d65 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 7 Feb 2025 10:34:45 -0500 Subject: [PATCH 113/157] Fix project migration --- librz/core/cconfig.c | 13 +++++++++---- test/integration/test_project_migrate.c | 2 +- .../{v19-str-config.rzdb => v18-str-config.rzdb} | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) rename test/prj/{v19-str-config.rzdb => v18-str-config.rzdb} (99%) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 16753ea3d80..638df22f0fc 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1230,6 +1230,11 @@ static bool find_encoding(RzConfigNode *node, RzStrEnc *encoding) { *encoding = rz_str_enc_string_as_type(option); return true; } + if (rz_list_empty(node->options)) { + // Edge case when the node was just initialized but the options + // were not added yet. + *encoding = rz_str_enc_string_as_type(node->value); + } return false; } @@ -1244,7 +1249,7 @@ static bool cb_str_encoding(void *user, void *data) { "if 2nd - 4th & 6th bytes are 0 & no char > 0x10ffff then utf32le else " "if utf8 char detected then utf8 else 8bit\n"); return false; - } else if (RZ_STR_EQ("settings", node->value) || (rz_str_casecmp("guess", node->value) && !found_enc)) { + } else if (RZ_STR_EQ("settings", node->value) || (RZ_STR_EQ("guess", node->value) && !found_enc)) { RZ_LOG_ERROR("Invalid value for str.encoding (%s).\n", node->value); return false; } @@ -3722,6 +3727,9 @@ RZ_API int rz_core_config_init(RzCore *core) { /* str */ SETCB("str.escbslash", "false", &cb_str_escbslash, "Escape the backslash"); + n = NODECB("str.encoding", "utf8", &cb_str_encoding); + SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); + SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); /* string search options */ SETB("str.search.reload", true, "When enabled, any change to any option `str.search.*` will reload the bin strings."); @@ -3761,9 +3769,6 @@ RZ_API int rz_core_config_init(RzCore *core) { SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); - n = NODECB("search.str.encoding", "utf8", &cb_str_encoding); - SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); - SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); SETICB("search.align", 0, &cb_searchalign, "Only catch aligned search hits"); SETI("search.esilcombo", 8, "Stop search after N consecutive hits"); diff --git a/test/integration/test_project_migrate.c b/test/integration/test_project_migrate.c index 557e4760d8d..0617746bfe3 100644 --- a/test/integration/test_project_migrate.c +++ b/test/integration/test_project_migrate.c @@ -575,7 +575,7 @@ static bool test_migrate_v15_v16_str_config() { } static bool test_migrate_v18_v19_str_config() { - RzProject *prj = rz_project_load_file_raw("prj/v19-str-config.rzdb"); + RzProject *prj = rz_project_load_file_raw("prj/v18-str-config.rzdb"); mu_assert_notnull(prj, "load raw project"); RzSerializeResultInfo *res = rz_serialize_result_info_new(); bool s = rz_project_migrate_v18_v19(prj, res); diff --git a/test/prj/v19-str-config.rzdb b/test/prj/v18-str-config.rzdb similarity index 99% rename from test/prj/v19-str-config.rzdb rename to test/prj/v18-str-config.rzdb index ea159f7039b..a30fbecd49a 100644 --- a/test/prj/v19-str-config.rzdb +++ b/test/prj/v18-str-config.rzdb @@ -4772,9 +4772,9 @@ stack.delta=0 stack.reg=SP stack.size=64 str.escbslash=false -str.search.max_length=5 +str.search.buffer_size=5 str.search.check_ascii_freq=false -str.encoding=utf32be +str.search.encoding=utf32be str.search.max_region_size=0x005555555 str.search.max_threads=5 str.search.max_uni_blocks=5 From 0734c35df852e932e632b603e8762693d8feabd3 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 7 Feb 2025 10:43:05 -0500 Subject: [PATCH 114/157] Fix tests --- test/db/cmd/cmd_search | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index cddf1107f18..769c66e2cff 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -130,7 +130,7 @@ e search.show_progress=false /zj hello EOF EXPECT=< Date: Fri, 7 Feb 2025 10:51:35 -0500 Subject: [PATCH 115/157] Sort result because it might change order due to multithreading --- test/db/cmd/cmd_search | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index 769c66e2cff..4b0d1b928b7 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -783,7 +783,7 @@ CMDS=< Date: Fri, 7 Feb 2025 11:07:17 -0500 Subject: [PATCH 116/157] Add example for extended regular expressions. --- librz/core/cmd_descs/cmd_descs.c | 6 ++++-- librz/core/cmd_descs/cmd_search.yaml | 6 +++++- test/db/cmd/cmd_search_z | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index c3a60ebd48a..4593a9b38f9 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -2416,20 +2416,22 @@ static const RzCmdDescDetailEntry slash_z_Regex_space_Flags_detail_entries[] = { { .text = "l", .arg_str = NULL, .comment = "Default. Literal string comparison. Ignores all meta-characters." }, { .text = "i", .arg_str = NULL, .comment = "Caseless (equivalent: PCRE2_CASELESS)" }, { .text = "r", .arg_str = NULL, .comment = "Regular expression." }, + { .text = "e", .arg_str = NULL, .comment = "Extended regular expression." }, { .text = "m", .arg_str = NULL, .comment = "Multiline regular expression (equivalent flag: PCRE2_MULTILINE)" }, { 0 }, }; -static const RzCmdDescDetailEntry slash_z_Exampls_detail_entries[] = { +static const RzCmdDescDetailEntry slash_z_Exampels_detail_entries[] = { { .text = "/z (ABC*)", .arg_str = NULL, .comment = "Search the exact string: \"(ABC*)\"." }, { .text = "/z (ABC*)D li", .arg_str = NULL, .comment = "Search the exact string \"(ABC*)\" but case insensitive." }, { .text = "/z (ABC*)D ri", .arg_str = NULL, .comment = "Search the regular expression \"(ABC*)D\" but case insensitive." }, + { .text = "/z \"и.{3}м\" ei", .arg_str = NULL, .comment = "Search the extended regular expression \"и.{3}м\" but case insensitive." }, { 0 }, }; static const RzCmdDescDetail slash_z_details[] = { { .name = "Encodings", .entries = slash_z_Encodings_detail_entries }, { .name = "Regex Flags", .entries = slash_z_Regex_space_Flags_detail_entries }, - { .name = "Exampls", .entries = slash_z_Exampls_detail_entries }, + { .name = "Exampels", .entries = slash_z_Exampels_detail_entries }, { 0 }, }; static const RzCmdDescHelp slash_z_help = { diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 98198209d5c..c488fa1b314 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -778,9 +778,11 @@ commands: comment: "Caseless (equivalent: PCRE2_CASELESS)" - text: "r" comment: "Regular expression." + - text: "e" + comment: "Extended regular expression." - text: "m" comment: "Multiline regular expression (equivalent flag: PCRE2_MULTILINE)" - - name: "Exampls" + - name: "Exampels" entries: - text: "/z (ABC*)" comment: "Search the exact string: \"(ABC*)\"." @@ -788,6 +790,8 @@ commands: comment: "Search the exact string \"(ABC*)\" but case insensitive." - text: "/z (ABC*)D ri" comment: "Search the regular expression \"(ABC*)D\" but case insensitive." + - text: "/z \"и.{3}м\" ei" + comment: "Search the extended regular expression \"и.{3}м\" but case insensitive." subcommands: - name: "/z" summary: String search. diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index 5ab808dd3f3..53e8bbde1f0 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -1055,3 +1055,29 @@ EXPECT=< Date: Fri, 7 Feb 2025 11:24:23 -0500 Subject: [PATCH 117/157] Remove unused min_uni_blocks setting and move the number into a constant. The setting was somewhat related to false positive string detection. It seemed to be the value how many blocks the characters of a string can be in. But it is too ineffecient to scan this in this implementation. Also not a setting which should be exposed to the user in this way. --- librz/arch/data.c | 1 - librz/bin/bfile_string.c | 3 --- librz/core/canalysis.c | 1 - librz/core/cconfig.c | 17 ++--------------- librz/core/cmd/cmd_print.c | 2 -- librz/core/cmeta.c | 1 - librz/core/core.c | 3 +-- librz/core/csearch.c | 1 - librz/core/project_migrate.c | 2 +- librz/include/rz_bin.h | 2 -- librz/include/rz_util/rz_str_search.h | 1 - librz/include/rz_util/rz_utf8.h | 2 +- librz/search/search.c | 1 - librz/search/string_search.c | 2 +- librz/util/str_search.c | 10 +++++++--- librz/util/utf32.c | 2 +- librz/util/utf8.c | 2 +- test/integration/test_project_migrate.c | 1 - test/unit/test_encodings.c | 6 +++--- test/unit/test_str_search.c | 1 - 20 files changed, 18 insertions(+), 43 deletions(-) diff --git a/librz/arch/data.c b/librz/arch/data.c index fe6a06c4d23..6ee9244ec0c 100644 --- a/librz/arch/data.c +++ b/librz/arch/data.c @@ -11,7 +11,6 @@ static bool get_string(const ut8 *buf, int size, RzDetectedString **dstr, RzStrE RzUtilStrScanOptions opt = { .max_str_length = size, - .max_uni_blocks = 4, .min_str_length = 4, .prefer_big_endian = big_endian, .check_ascii_freq = false, diff --git a/librz/bin/bfile_string.c b/librz/bin/bfile_string.c index bd07de881bd..e043cbee457 100644 --- a/librz/bin/bfile_string.c +++ b/librz/bin/bfile_string.c @@ -84,7 +84,6 @@ static RzList /**/ *string_scan_range(SharedData *shared, co RzUtilStrScanOptions scan_opt = { .max_str_length = buffer_size, - .max_uni_blocks = shared->max_uni_blocks, .min_str_length = shared->min_str_length, .prefer_big_endian = shared->prefer_big_endian, .check_ascii_freq = shared->check_ascii_freq, @@ -313,7 +312,6 @@ RZ_API void rz_bin_string_search_opt_init(RZ_NONNULL RzBinStringSearchOpt *opt) opt->max_threads = RZ_THREAD_N_CORES_ALL_AVAILABLE; opt->min_length = RZ_BIN_STRING_SEARCH_MIN_STRING; opt->max_length = RZ_BIN_STRING_SEARCH_BUFFER_SIZE; - opt->max_uni_blocks = RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS; opt->max_region_size = RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE; opt->raw_alignment = RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT; opt->string_encoding = RZ_STRING_ENC_GUESS; @@ -466,7 +464,6 @@ RZ_API RZ_OWN RzPVector /**/ *rz_bin_file_strings(RZ_NONNULL RzBi .strings_db = strings_db, .buffer_size = opt->max_length, .string_encoding = opt->string_encoding, - .max_uni_blocks = opt->max_uni_blocks, .min_str_length = opt->min_length, .check_ascii_freq = opt->check_ascii_freq, .prefer_big_endian = prefer_big_endian, diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index 1ee54547e3f..897f3a2a0da 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -76,7 +76,6 @@ static bool find_string_at(RzCore *core, RzBinObject *bobj, ut64 pointer, char * RzStrEnc strenc = bin->str_search_cfg.string_encoding; RzUtilStrScanOptions scan_opt = { .max_str_length = sizeof(buffer), - .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, .check_ascii_freq = bin->str_search_cfg.check_ascii_freq, diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 638df22f0fc..1f27c17605e 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1168,18 +1168,6 @@ static bool cb_search_str_max_length(void *user, void *data) { return true; } -static bool cb_search_str_max_uni_blocks(void *user, void *data) { - RzCore *core = (RzCore *)user; - RzConfigNode *node = (RzConfigNode *)data; - if (node->i_value < 1) { - RZ_LOG_ERROR("search.str.max_uni_blocks cannot be less than 1.\n"); - return false; - } - core->bin->str_search_cfg.max_uni_blocks = node->i_value; - check_reload_bin_str_search(core); - return true; -} - static bool cb_search_str_max_region_size(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; @@ -3763,9 +3751,8 @@ RZ_API int rz_core_config_init(RzCore *core) { SETBPREF("search.show_progress", "true", "Show the search process."); SETBPREF("search.overlap", "true", "Look for overlapped search hits."); SETICB("search.io.alignment", 1, &cb_searchalignment, "Only search at set byte alignment."); - SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find."); - SETICB("search.str.max_length", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_max_length, "Maximum buffer size, which will also determine the maximum string length."); - SETICB("search.str.max_uni_blocks", RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS, &cb_search_str_max_uni_blocks, "Maximum number of unicode blocks."); + SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find. (inclusive)"); + SETICB("search.str.max_length", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_max_length, "Maximum buffer size, which will also determine the maximum string length. (inclusive)"); SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 40ebd215737..294137a510f 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -2164,7 +2164,6 @@ RZ_IPI RzCmdStatus rz_print_strings_current_block_handler(RzCore *core, int argc RzBin *bin = core->bin; RzUtilStrScanOptions scan_opt = { .max_str_length = core->blocksize, - .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = false, .check_ascii_freq = bin->str_search_cfg.check_ascii_freq, @@ -2199,7 +2198,6 @@ RZ_IPI RzCmdStatus rz_print_first_string_current_block_handler(RzCore *core, int RzBin *bin = core->bin; RzUtilStrScanOptions scan_opt = { .max_str_length = core->blocksize, - .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = false, .check_ascii_freq = bin->str_search_cfg.check_ascii_freq, diff --git a/librz/core/cmeta.c b/librz/core/cmeta.c index d974dc423e9..c447d19c738 100644 --- a/librz/core/cmeta.c +++ b/librz/core/cmeta.c @@ -437,7 +437,6 @@ static bool meta_string_guess_add(RzCore *core, ut64 addr, size_t limit, char ** bool big_endian = rz_config_get_b(core->config, "cfg.bigendian"); RzUtilStrScanOptions scan_opt = { .max_str_length = bin->str_search_cfg.max_length, - .max_uni_blocks = bin->str_search_cfg.max_uni_blocks, .min_str_length = bin->str_search_cfg.min_length, .prefer_big_endian = big_endian, .check_ascii_freq = bin->str_search_cfg.check_ascii_freq, diff --git a/librz/core/core.c b/librz/core/core.c index 7bd45e17f6e..952f40fcab5 100644 --- a/librz/core/core.c +++ b/librz/core/core.c @@ -983,8 +983,7 @@ static bool get_string(const ut8 *buf, int size, RzDetectedString **dstr, RzStrE RzUtilStrScanOptions opt = { .max_str_length = size, - .max_uni_blocks = 4, - .min_str_length = 4, + .min_str_length = RZ_BIN_STRING_SEARCH_MIN_STRING, .prefer_big_endian = big_endian, .check_ascii_freq = false, }; diff --git a/librz/core/csearch.c b/librz/core/csearch.c index a60f2e25b9f..e480df1c6f0 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -186,7 +186,6 @@ RZ_API RZ_OWN RzList /**/ *rz_core_search_string(RZ_NONNULL RzCor // buf_size is effectively the maximum string length. // Gets renamed with the refactor. .max_str_length = core->bin->str_search_cfg.max_length, - .max_uni_blocks = core->bin->str_search_cfg.max_uni_blocks, .min_str_length = core->bin->str_search_cfg.min_length, .prefer_big_endian = core->analysis->big_endian, .check_ascii_freq = core->bin->str_search_cfg.check_ascii_freq, diff --git a/librz/core/project_migrate.c b/librz/core/project_migrate.c index 1d816822de0..4692ff9c067 100644 --- a/librz/core/project_migrate.c +++ b/librz/core/project_migrate.c @@ -689,10 +689,10 @@ RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *re RZ_SERIALIZE_SUB(prj, core_db, res, "core", return false;); Sdb *config_db; RZ_SERIALIZE_SUB(core_db, config_db, res, "config", return false;); + sdb_remove(config_db, "str.search.max_uni_blocks"); sdb_rename(config_db, "str.search.max_threads", "search.max_threads"); sdb_rename(config_db, "str.search.min_length", "search.str.min_length"); sdb_rename(config_db, "str.search.buffer_size", "search.str.max_length"); - sdb_rename(config_db, "str.search.max_uni_blocks", "search.str.max_uni_blocks"); sdb_rename(config_db, "str.search.max_region_size", "search.str.max_region_size"); sdb_rename(config_db, "str.search.raw_alignment", "search.str.raw_alignment"); sdb_rename(config_db, "str.search.check_ascii_freq", "search.str.check_ascii_freq"); diff --git a/librz/include/rz_bin.h b/librz/include/rz_bin.h index bc9579ffc5e..d7f5b5c05d9 100644 --- a/librz/include/rz_bin.h +++ b/librz/include/rz_bin.h @@ -189,7 +189,6 @@ enum { #define RZ_BIN_STRING_SEARCH_MIN_STRING 4 #define RZ_BIN_STRING_SEARCH_BUFFER_SIZE 2048 -#define RZ_BIN_STRING_SEARCH_MAX_UNI_BLOCKS 4 #define RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE (1024 * 1024 * 10) #define RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT 0x10000 #define RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ true @@ -204,7 +203,6 @@ typedef struct rz_bin_string_search_opt_t { RzThreadNCores max_threads; ///< Maximum thread number (normally set to RZ_THREAD_N_CORES_ALL_AVAILABLE). size_t min_length; ///< Smallest string length that is possible to find. size_t max_length; ///< Maximum buffer size, which will also determine the maximum string length. - size_t max_uni_blocks; ///< Maximum number of unicode blocks size_t max_region_size; ///< Maximum allowable size for the search interval between two memory regions. size_t raw_alignment; ///< Memory sector alignment used for the raw string search. bool check_ascii_freq; ///< If true, perform check on ASCII frequencies when looking for false positives diff --git a/librz/include/rz_util/rz_str_search.h b/librz/include/rz_util/rz_str_search.h index 69df82a6199..2877f20b4b2 100644 --- a/librz/include/rz_util/rz_str_search.h +++ b/librz/include/rz_util/rz_str_search.h @@ -29,7 +29,6 @@ typedef struct { */ typedef struct { size_t max_str_length; ///< Maximum size of a detected string. - size_t max_uni_blocks; ///< Maximum number of Unicode blocks size_t min_str_length; ///< Minimum string length bool prefer_big_endian; ///< True if the preferred endianess for UTF strings is big-endian bool check_ascii_freq; ///< If true, perform check on ASCII frequencies when looking for false positives diff --git a/librz/include/rz_util/rz_utf8.h b/librz/include/rz_util/rz_utf8.h index d4ce805edd5..07f3857ac63 100644 --- a/librz/include/rz_util/rz_utf8.h +++ b/librz/include/rz_util/rz_utf8.h @@ -9,7 +9,7 @@ typedef struct { const char *name; } RUtfBlock; -#define LAST_UNICODE_CODE_POINT 0x10ffff +#define UNICODE_LAST_CODE_POINT 0x10ffff /** * \brief An Unicode code point. diff --git a/librz/search/search.c b/librz/search/search.c index 88c03d33edd..5afa5f2e596 100644 --- a/librz/search/search.c +++ b/librz/search/search.c @@ -81,7 +81,6 @@ RZ_API int rz_search_strings_update(RzSearch *s, ut64 from, const ut8 *buf, int RzUtilStrScanOptions scan_opt = { .max_str_length = len, - .max_uni_blocks = s->string_max, .min_str_length = s->string_min, .prefer_big_endian = false, }; diff --git a/librz/search/string_search.c b/librz/search/string_search.c index cd8e8123a30..4edcf3fd059 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -41,7 +41,7 @@ static void align_offsets(RzUtilStrScanOptions options, RzStrEnc encoding, RzDet if (!len_found) { if (!offset_found) { // If the previous offset was not found, we know something is broken. - // If it was found on the ohter hand, the string is exactly as long as the whole buffer. + // If it was found on the other hand, the string is exactly as long as the whole buffer. // So `start + len` is OOB and hence not in the hash table. RZ_LOG_WARN("Could not determine length of string in memory. String length will be off.\n"); } diff --git a/librz/util/str_search.c b/librz/util/str_search.c index ffa5c2609d0..59cbfe1bbc9 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -119,7 +119,6 @@ static UTF8StringInfo calculate_utf8_string_info(ut8 *str, int size) { } static FalsePositiveResult reduce_false_positives(const RzUtilStrScanOptions *opt, ut8 *str, int size, RzStrEnc str_type) { - switch (str_type) { case RZ_STRING_ENC_8BIT: { for (int i = 0; i < size; i++) { @@ -156,7 +155,12 @@ static FalsePositiveResult reduce_false_positives(const RzUtilStrScanOptions *op return RETRY_ASCII; } - if (num_blocks > opt->max_uni_blocks) { + // If the string has characters of more then 4 blocks, it is + // considered invalid. I think at least. This was a funny metric + // to reduce false positives. But basically useless, because not + // documented. Also way too ineffecient. Because this whole thing iterates + // twice over the string. Leave it here to prevent regressions. + if (num_blocks > 4) { return SKIP_STRING; } break; @@ -322,7 +326,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 } int strbuf_size = i; - if (runes >= opt->min_str_length) { + if (runes >= opt->min_str_length && runes <= opt->max_str_length) { FalsePositiveResult false_positive_result = reduce_false_positives(opt, strbuf, strbuf_size, str_type); if (false_positive_result == SKIP_STRING) { goto error; diff --git a/librz/util/utf32.c b/librz/util/utf32.c index ea39112ea45..930b894435d 100644 --- a/librz/util/utf32.c +++ b/librz/util/utf32.c @@ -63,7 +63,7 @@ RZ_API bool rz_utf32_valid_code_point(RZ_NONNULL const ut8 *buf, size_t buf_len, // UTF-16 surrogates are forbitten code points as of RFC 3629. bool is_utf16_surregate = cp >= 0xd800 && cp <= 0xdfff; // Largest Unicode code point is 0x10ffff, also limited in RFC 3629. - bool above_max_code_point = cp > LAST_UNICODE_CODE_POINT; + bool above_max_code_point = cp > UNICODE_LAST_CODE_POINT; if (is_utf16_surregate || above_max_code_point) { return false; } diff --git a/librz/util/utf8.c b/librz/util/utf8.c index da21a996902..3aeb2e0dcf5 100644 --- a/librz/util/utf8.c +++ b/librz/util/utf8.c @@ -517,7 +517,7 @@ RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { if (ch) { *ch = code_point; } - return code_point > LAST_UNICODE_CODE_POINT ? 0 : 4; + return code_point > UNICODE_LAST_CODE_POINT ? 0 : 4; } return 0; } diff --git a/test/integration/test_project_migrate.c b/test/integration/test_project_migrate.c index 0617746bfe3..96b74d96baa 100644 --- a/test/integration/test_project_migrate.c +++ b/test/integration/test_project_migrate.c @@ -595,7 +595,6 @@ static bool test_migrate_v18_v19_str_config() { mu_assert_streq_free(sdb_get(config_db, "search.max_threads"), "5", "New config has wrong value"); mu_assert_streq_free(sdb_get(config_db, "search.str.min_length"), "5", "New config has wrong value"); mu_assert_streq_free(sdb_get(config_db, "search.str.max_length"), "5", "New config has wrong value"); - mu_assert_streq_free(sdb_get(config_db, "search.str.max_uni_blocks"), "5", "New config has wrong value"); mu_assert_streq_free(sdb_get(config_db, "search.str.max_region_size"), "0x005555555", "New config has wrong value"); mu_assert_streq_free(sdb_get(config_db, "search.str.raw_alignment"), "55", "New config has wrong value"); mu_assert_streq_free(sdb_get(config_db, "search.str.check_ascii_freq"), "false", "New config has wrong value"); diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 13009f6a00e..734cedb4dda 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -87,14 +87,14 @@ bool test_rz_utf16_decode(void) { nbytes = rz_utf16_decode(utf16le_last_surr, 4, &codepoint, false); mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_eq_fmt(codepoint, LAST_UNICODE_CODE_POINT, "Character decode failed.", "0x%" PFMT64x); + mu_assert_eq_fmt(codepoint, UNICODE_LAST_CODE_POINT, "Character decode failed.", "0x%" PFMT64x); rz_utf8_encode((ut8 *)utf8_out, codepoint); mu_assert_streq(utf8_out, "􏿿", "Encode failed."); memset(utf8_out, 0, sizeof(utf8_out)); nbytes = rz_utf16_decode(utf16be_last_surr, 4, &codepoint, true); mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); - mu_assert_eq_fmt(codepoint, LAST_UNICODE_CODE_POINT, "Character decode failed.", "0x%" PFMT64x); + mu_assert_eq_fmt(codepoint, UNICODE_LAST_CODE_POINT, "Character decode failed.", "0x%" PFMT64x); rz_utf8_encode((ut8 *)utf8_out, codepoint); mu_assert_streq(utf8_out, "􏿿", "Encode failed."); memset(utf8_out, 0, sizeof(utf8_out)); @@ -163,7 +163,7 @@ bool test_rz_utf16_encode(void) { memset(utf16_out, 0, sizeof(utf16_out)); const ut8 utf16le_last_surr[] = { 0xFF, 0xDB, 0xFF, 0xDF }; - codepoint = LAST_UNICODE_CODE_POINT; + codepoint = UNICODE_LAST_CODE_POINT; nbytes = rz_utf16le_encode(utf16_out, codepoint); mu_assert_eq(nbytes, 4, "Decoded number of bytes mismatch."); mu_assert_memeq(utf16_out, utf16le_last_surr, sizeof(utf16le), "Encode failed."); diff --git a/test/unit/test_str_search.c b/test/unit/test_str_search.c index b624ad72825..5bc1dd685d1 100644 --- a/test/unit/test_str_search.c +++ b/test/unit/test_str_search.c @@ -6,7 +6,6 @@ static RzUtilStrScanOptions g_opt = { .max_str_length = 2048, - .max_uni_blocks = 4, .min_str_length = 4, .prefer_big_endian = false, .check_ascii_freq = true From 1a439dcfedaeea9e826978c80fae38a67ec76fc8 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 7 Feb 2025 11:37:31 -0500 Subject: [PATCH 118/157] Document that raw_alignment is not used for normal search. --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 1f27c17605e..01f3b564a6a 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3754,7 +3754,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find. (inclusive)"); SETICB("search.str.max_length", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_max_length, "Maximum buffer size, which will also determine the maximum string length. (inclusive)"); SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); - SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search."); + SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search (RzBin only. Use search.align for /z)."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); SETICB("search.align", 0, &cb_searchalign, "Only catch aligned search hits"); From c47767086930d1b7ad68c0dac33fbc940eecb2f1 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Fri, 7 Feb 2025 12:20:30 -0500 Subject: [PATCH 119/157] Implement alignment matching of search hits (incomplete). --- librz/core/cconfig.c | 14 +------ librz/core/csearch.c | 2 +- librz/search/bytes_search.c | 11 +++++- librz/search/string_search.c | 4 ++ test/db/cmd/cmd_search_x | 77 ++++++++++++++++++++++++++++++++++++ test/db/cmd/cmd_search_z | 41 +++++++++++++++++++ 6 files changed, 134 insertions(+), 15 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 01f3b564a6a..79ea869eb44 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -2396,16 +2396,6 @@ static bool cb_searchalign(void *user, void *data) { return true; } -static bool cb_searchalignment(void *user, void *data) { - RzConfigNode *node = (RzConfigNode *)data; - ut64 alignment = node->i_value; - if (alignment >= 64 || alignment < 1) { - RZ_LOG_ERROR("Alignment has to be between 1-63.\n"); - return false; - } - return true; -} - static bool cb_segoff(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; @@ -3727,7 +3717,6 @@ RZ_API int rz_core_config_init(RzCore *core) { /* search */ SETCB("search.contiguous", "true", &cb_contiguous, "Accept contiguous/adjacent search hits"); - SETICB("search.align", 0, &cb_searchalign, "Only catch aligned search hits"); SETI("search.chunk", 0, "Chunk size for /+ (default size is asm.bits/8"); SETI("search.esilcombo", 8, "Stop search after N consecutive hits"); SETI("search.distance", 0, "Search string distance"); @@ -3750,14 +3739,13 @@ RZ_API int rz_core_config_init(RzCore *core) { SETI("search.maxhits", 0, "Maximum number of hits ('0' means no limit)"); SETBPREF("search.show_progress", "true", "Show the search process."); SETBPREF("search.overlap", "true", "Look for overlapped search hits."); - SETICB("search.io.alignment", 1, &cb_searchalignment, "Only search at set byte alignment."); SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find. (inclusive)"); SETICB("search.str.max_length", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_max_length, "Maximum buffer size, which will also determine the maximum string length. (inclusive)"); SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search (RzBin only. Use search.align for /z)."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); - SETICB("search.align", 0, &cb_searchalign, "Only catch aligned search hits"); + SETICB("search.align", 0, &cb_searchalign, "Address alignment for search."); SETI("search.esilcombo", 8, "Stop search after N consecutive hits"); SETI("search.distance", 0, "Search string distance"); SETBPREF("search.flags", "true", "All search results are flagged, otherwise only printed"); diff --git a/librz/core/csearch.c b/librz/core/csearch.c index e480df1c6f0..80edf83129a 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -27,7 +27,7 @@ RZ_API RZ_OWN RzSearchFindOpt *rz_core_setup_default_search_find_opts(RzCore *co } if (!(rz_search_find_opt_set_inverse_match(fopts, rz_config_get_b(core->config, "search.inverse")) && rz_search_find_opt_set_overlap_match(fopts, rz_config_get_b(core->config, "search.overlap")) && - rz_search_find_opt_set_alignment(fopts, rz_config_get_i(core->config, "search.io.alignment")))) { + rz_search_find_opt_set_alignment(fopts, rz_config_get_i(core->config, "search.align")))) { RZ_LOG_ERROR("Failed set find options.\n"); rz_search_find_opt_free(fopts); return NULL; diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index 1ef9682344d..f454b52ab50 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -219,7 +219,11 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const R rz_pvector_foreach (matches, it) { match = *it; RzRegexMatch *group0 = rz_pvector_at(match, 0); - RzSearchHit *hit = rz_search_hit_new(hp->pattern_desc, group0->start, group0->len); + if (fopts->alignment > 1 && (address + group0->start) % fopts->alignment != 0) { + // Match has not the correct alignment in memory. + continue; + } + RzSearchHit *hit = rz_search_hit_new(hp->pattern_desc, address + group0->start, group0->len); if (!hit || !rz_th_queue_push(hits, hit, true)) { rz_search_hit_free(hit); rz_pvector_free(matches); @@ -230,6 +234,11 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const R continue; } for (size_t offset = 0; offset < size;) { + if (fopts->alignment > 1 && (address + offset) % fopts->alignment != 0) { + // Match has not the correct alignment in memory. + offset += (fopts->alignment - (address + offset) % fopts->alignment); + continue; + } size_t leftovers = size - offset; if (hp->length > leftovers) { break; diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 4edcf3fd059..c39a8888a95 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -93,6 +93,10 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs ut64 str_mem_len; ut64 str_mem_offset; align_offsets(options, detected->type, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); + if (fopt->alignment > 1 && (str_mem_offset + offset) % fopt->alignment != 0) { + // Match has not the correct alignment in memory. + continue; + } char *hit_type = rz_str_newf("string.%s", rz_str_enc_as_string(detected->type)); RzSearchHit *hit = rz_search_hit_new(hit_type, str_mem_offset + offset, str_mem_len); free(hit_type); diff --git a/test/db/cmd/cmd_search_x b/test/db/cmd/cmd_search_x index b2716a2653c..bccefa71645 100644 --- a/test/db/cmd/cmd_search_x +++ b/test/db/cmd/cmd_search_x @@ -318,3 +318,80 @@ EXPECT=< Date: Sat, 8 Feb 2025 10:32:32 -0500 Subject: [PATCH 120/157] Finish alignment search. --- librz/core/cconfig.c | 7 +- librz/include/rz_util/rz_regex.h | 6 ++ librz/search/bytes_search.c | 11 +-- librz/search/string_search.c | 6 +- librz/util/regex.c | 63 +++++++++++---- test/db/cmd/cmd_search_x | 130 ++++++++++++++++++++++--------- test/db/cmd/cmd_search_z | 108 +++++++++++++++++++------ 7 files changed, 247 insertions(+), 84 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 79ea869eb44..d9bc55da04a 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "core_private.h" @@ -2391,6 +2392,10 @@ static bool cb_contiguous(void *user, void *data) { static bool cb_searchalign(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; + if (rz_bits_count_ut64(node->i_value) != 1) { + RZ_LOG_ERROR("Alignment is only defined for '>0' and 'n^2'.\n"); + return false; + } core->search->align = node->i_value; core->print->addrmod = node->i_value; return true; @@ -3745,7 +3750,7 @@ RZ_API int rz_core_config_init(RzCore *core) { SETICB("search.str.raw_alignment", RZ_BIN_STRING_SEARCH_RAW_FILE_ALIGNMENT, &cb_search_str_raw_alignment, "Memory sector alignment used for the raw string search (RzBin only. Use search.align for /z)."); SETICB("search.str.check_ascii_freq", RZ_BIN_STRING_SEARCH_CHECK_ASCII_FREQ, &cb_search_str_check_ascii_freq, "If true, perform check on ASCII frequencies when looking for false positives during string search"); - SETICB("search.align", 0, &cb_searchalign, "Address alignment for search."); + SETICB("search.align", 1, &cb_searchalign, "Address alignment (searches only if 'address % search.align == 0')."); SETI("search.esilcombo", 8, "Stop search after N consecutive hits"); SETI("search.distance", 0, "Search string distance"); SETBPREF("search.flags", "true", "All search results are flagged, otherwise only printed"); diff --git a/librz/include/rz_util/rz_regex.h b/librz/include/rz_util/rz_regex.h index c039acacee4..0f5767a60a9 100644 --- a/librz/include/rz_util/rz_regex.h +++ b/librz/include/rz_util/rz_regex.h @@ -85,6 +85,12 @@ RZ_API RZ_OWN RzPVector /* *>*/ *rz_regex_match_all( RzRegexSize text_size, RzRegexSize text_offset, RzRegexFlags mflags); +RZ_API RZ_OWN RzPVector /* *>*/ *rz_regex_match_all_overlap( + RZ_NONNULL const RzRegex *regex, + RZ_NONNULL const char *text, + RzRegexSize text_size, + RzRegexSize text_offset, + RzRegexFlags mflags); RZ_API bool rz_regex_contains(RZ_NONNULL const char *pattern, RZ_NONNULL const char *text, RzRegexSize text_size, RzRegexFlags cflags, RzRegexFlags mflags); diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index f454b52ab50..a5c5afaa007 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "search_internal.h" /** @@ -33,7 +34,7 @@ RZ_API RZ_OWN RzSearchBytesPattern *rz_search_bytes_pattern_new(RZ_OWN ut8 *byte } pat->bytes = bytes; if (compile_regex) { - pat->regex = rz_regex_new_bytes(bytes, length, RZ_REGEX_DEFAULT, RZ_REGEX_DEFAULT, NULL); + pat->regex = rz_regex_new_bytes(bytes, length, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT, NULL); } pat->mask = mask; pat->length = length; @@ -213,13 +214,13 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const R rz_pvector_foreach (patterns, it) { RzSearchBytesPattern *hp = (RzSearchBytesPattern *)*it; if (hp->regex) { - RzPVector *matches = rz_regex_match_all(hp->regex, (const char *)raw_buf, size, 0, RZ_REGEX_DEFAULT); + RzPVector *matches = rz_regex_match_all_overlap(hp->regex, (const char *)raw_buf, size, 0, RZ_REGEX_DEFAULT); void **it; RzPVector *match; rz_pvector_foreach (matches, it) { match = *it; RzRegexMatch *group0 = rz_pvector_at(match, 0); - if (fopts->alignment > 1 && (address + group0->start) % fopts->alignment != 0) { + if (fopts->alignment > 1 && rz_mem_align_padding(address + group0->start, fopts->alignment) != 0) { // Match has not the correct alignment in memory. continue; } @@ -234,9 +235,9 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const R continue; } for (size_t offset = 0; offset < size;) { - if (fopts->alignment > 1 && (address + offset) % fopts->alignment != 0) { + if (fopts->alignment > 1 && rz_mem_align_padding(address + offset, fopts->alignment) != 0) { // Match has not the correct alignment in memory. - offset += (fopts->alignment - (address + offset) % fopts->alignment); + offset += rz_mem_align_padding(address + offset, fopts->alignment); continue; } size_t leftovers = size - offset; diff --git a/librz/search/string_search.c b/librz/search/string_search.c index c39a8888a95..87f37362233 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -61,8 +61,8 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs } // Copy options here so we can set the hash table. - // The search options are a shared ressource and we might get - // runtime conditions editing and freeing it. + // The search options are a shared resource and we might get + // race-conditions editing and freeing it. RzUtilStrScanOptions options = ss->options; options.utf8_to_mem_offset_map = ht_uu_new(); @@ -93,7 +93,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs ut64 str_mem_len; ut64 str_mem_offset; align_offsets(options, detected->type, detected, group0, &str_mem_offset, &str_mem_len, found_idx << 32); - if (fopt->alignment > 1 && (str_mem_offset + offset) % fopt->alignment != 0) { + if (fopt->alignment > 1 && rz_mem_align_padding(str_mem_offset + group0->start, fopt->alignment) != 0) { // Match has not the correct alignment in memory. continue; } diff --git a/librz/util/regex.c b/librz/util/regex.c index c2198c380db..38a4f61b769 100644 --- a/librz/util/regex.c +++ b/librz/util/regex.c @@ -383,6 +383,30 @@ RZ_API RZ_OWN RzPVector /**/ *rz_regex_match_all_not_grouped( return all_matches; } +static RZ_OWN RzPVector /* *>*/ *rz_regex_match_all_internal( + RZ_NONNULL const RzRegex *regex, + RZ_NONNULL const char *text, + RzRegexSize text_size, + RzRegexSize text_offset, + RzRegexFlags mflags, + bool allow_overlap) { + rz_return_val_if_fail(regex && text, NULL); + + RzPVector *all_matches = rz_pvector_new((RzPVectorFree)rz_pvector_free); + RzPVector *matches = rz_regex_match_first(regex, text, text_size, text_offset, mflags); + while (matches && rz_pvector_len(matches) > 0) { + rz_pvector_push(all_matches, matches); + RzRegexMatch *m = rz_pvector_head(matches); + // Search again after the last match. + text_offset = allow_overlap ? m->start + 1 : m->start + m->len; + matches = rz_regex_match_first(regex, text, text_size, text_offset, mflags); + } + + // Free last vector without matches. + rz_pvector_free(matches); + return all_matches; +} + /** * \brief Finds all matches in a text and returns them as vector of vector matches. * @@ -392,31 +416,40 @@ RZ_API RZ_OWN RzPVector /**/ *rz_regex_match_all_not_grouped( * Can be set to RZ_REGEX_ZERO_TERMINATED if the buffer is a zero terminated string. * \param text_offset The offset into \p text from where the search starts. * \param mflags Match flags. + * \param allow_overlap If true it will match also overlaping patterns. * * \return PVector of every match in the given string or NULL in case of failure. * One match with all its groups is again assembled in a pvector. */ -RZ_API RZ_OWN RzPVector /* *>*/ *rz_regex_match_all( +RZ_API RZ_OWN RzPVector /* *>*/ *rz_regex_match_all_overlap( RZ_NONNULL const RzRegex *regex, RZ_NONNULL const char *text, RzRegexSize text_size, RzRegexSize text_offset, RzRegexFlags mflags) { - rz_return_val_if_fail(regex && text, NULL); - - RzPVector *all_matches = rz_pvector_new((RzPVectorFree)rz_pvector_free); - RzPVector *matches = rz_regex_match_first(regex, text, text_size, text_offset, mflags); - while (matches && rz_pvector_len(matches) > 0) { - rz_pvector_push(all_matches, matches); - RzRegexMatch *m = rz_pvector_head(matches); - // Search again after the last match. - text_offset = m->start + m->len; - matches = rz_regex_match_first(regex, text, text_size, text_offset, mflags); - } + return rz_regex_match_all_internal(regex, text, text_size, text_offset, mflags, true); +} - // Free last vector without matches. - rz_pvector_free(matches); - return all_matches; +/** + * \brief Finds all matches in a text and returns them as vector of vector matches. + * + * \param pattern The regex pattern to match. + * \param text The text to search in. + * \param text_size The length of the buffer pointed to by \p text. + * Can be set to RZ_REGEX_ZERO_TERMINATED if the buffer is a zero terminated string. + * \param text_offset The offset into \p text from where the search starts. + * \param mflags Match flags. + * + * \return PVector of every match in the given string or NULL in case of failure. + * One match with all its groups is again assembled in a pvector. + */ +RZ_API RZ_OWN RzPVector /* *>*/ *rz_regex_match_all( + RZ_NONNULL const RzRegex *regex, + RZ_NONNULL const char *text, + RzRegexSize text_size, + RzRegexSize text_offset, + RzRegexFlags mflags) { + return rz_regex_match_all_internal(regex, text, text_size, text_offset, mflags, false); } /** diff --git a/test/db/cmd/cmd_search_x b/test/db/cmd/cmd_search_x index bccefa71645..0944dfea795 100644 --- a/test/db/cmd/cmd_search_x +++ b/test/db/cmd/cmd_search_x @@ -320,42 +320,64 @@ EOF RUN NAME=/xr on virtual address -FILE=bins/wasm/inc.wast +FILE=bins/cmd/search/alignment_test ARGS=-m 0x80000 CMDS=< Date: Sat, 8 Feb 2025 10:41:01 -0500 Subject: [PATCH 121/157] Fix some more tests. --- test/db/cmd/cmd_search | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/db/cmd/cmd_search b/test/db/cmd/cmd_search index 4b0d1b928b7..52c79bf6726 100644 --- a/test/db/cmd/cmd_search +++ b/test/db/cmd/cmd_search @@ -342,6 +342,9 @@ e search.to=0x00000050 /at xor EOF EXPECT=< Date: Sat, 8 Feb 2025 11:02:08 -0500 Subject: [PATCH 122/157] Add EBCDIC tests --- test/db/cmd/cmd_search_z | 252 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/test/db/cmd/cmd_search_z b/test/db/cmd/cmd_search_z index a318210d040..2f1f4a4e982 100644 --- a/test/db/cmd/cmd_search_z +++ b/test/db/cmd/cmd_search_z @@ -90,6 +90,132 @@ EOF EXPECT_ERR= RUN +NAME=String Search - minimal string - Encoding: ebcdic_uk - Latin +FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ebcdic_uk +CMDS=< Date: Sat, 8 Feb 2025 11:08:19 -0500 Subject: [PATCH 123/157] Fix error case where hits is undefined. --- librz/core/cmd/cmd_search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 84b9f916c9b..475bbd79d0e 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2885,13 +2885,13 @@ static bool parse_pattern_arg(const char *arg, RZ_OUT ut8 *re, RZ_OUT size_t *le RZ_IPI RzCmdStatus rz_cmd_search_hex_regex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { ut8 *re = RZ_NEWS0(ut8, strlen(argv[1])); RzSearchOpt *search_opts = setup_search_options(core); + RzList *hits = NULL; if (!search_opts) { goto error; } CMD_SEARCH_BEGIN(); - RzList *hits = NULL; const char *arg = argv[1]; size_t r = 0; if (!parse_pattern_arg(arg, re, &r)) { From e7ca9df6c0d72364a9a8669246acfbeadbb9a6da Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 9 Feb 2025 07:53:21 -0500 Subject: [PATCH 124/157] Remove addrmod member. It was pressumingly used to indicate aligned addresses in print mode. But it wasn't documented and the usefulness is dubious. Since it is easy to spot for users to see if addresses are aligned or not anyways. --- librz/core/cconfig.c | 1 - librz/core/tui/visual.c | 3 +-- librz/include/rz_util/rz_print.h | 2 -- librz/util/print.c | 7 ++----- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index d9bc55da04a..4a5cba13ca1 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -2397,7 +2397,6 @@ static bool cb_searchalign(void *user, void *data) { return false; } core->search->align = node->i_value; - core->print->addrmod = node->i_value; return true; } diff --git a/librz/core/tui/visual.c b/librz/core/tui/visual.c index c915b556b58..3adad460b74 100644 --- a/librz/core/tui/visual.c +++ b/librz/core/tui/visual.c @@ -3841,7 +3841,6 @@ RZ_IPI int rz_core_visual(RzCore *core, const char *input) { rz_cons_singleton()->teefile = ""; static char debugstr[512]; - core->print->flags |= RZ_PRINT_FLAGS_ADDRMOD; do { dodo: rz_core_visual_tab_update(core); @@ -3890,7 +3889,7 @@ RZ_IPI int rz_core_visual(RzCore *core, const char *input) { flags |= RZ_PRINT_FLAGS_COLOR; } visual->debug = rz_config_get_b(core->config, "cfg.debug"); - flags |= RZ_PRINT_FLAGS_ADDRMOD | RZ_PRINT_FLAGS_HEADER; + flags |= RZ_PRINT_FLAGS_HEADER; rz_print_set_flags(core->print, flags); scrseek = rz_num_math(core->num, rz_config_get(core->config, "scr.seek")); diff --git a/librz/include/rz_util/rz_print.h b/librz/include/rz_util/rz_print.h index 96b0ae0e17d..7e6a87a1fda 100644 --- a/librz/include/rz_util/rz_print.h +++ b/librz/include/rz_util/rz_print.h @@ -13,7 +13,6 @@ extern "C" { #endif #define RZ_PRINT_FLAGS_COLOR 0x00000001 -#define RZ_PRINT_FLAGS_ADDRMOD 0x00000002 #define RZ_PRINT_FLAGS_CURSOR 0x00000004 #define RZ_PRINT_FLAGS_HEADER 0x00000008 #define RZ_PRINT_FLAGS_SPARSE 0x00000010 @@ -135,7 +134,6 @@ typedef struct rz_print_t { int flags; int seggrn; bool use_comments; - int addrmod; int col; int stride; int bytespace; diff --git a/librz/util/print.c b/librz/util/print.c index 4ed2044a61d..b6bd70df044 100644 --- a/librz/util/print.c +++ b/librz/util/print.c @@ -66,12 +66,10 @@ RZ_API RzPrint *rz_print_new(void) { p->cols = 16; p->cur_enabled = false; p->cur = p->ocur = -1; - p->addrmod = 4; p->flags = RZ_PRINT_FLAGS_COLOR | RZ_PRINT_FLAGS_OFFSET | - RZ_PRINT_FLAGS_HEADER | - RZ_PRINT_FLAGS_ADDRMOD; + RZ_PRINT_FLAGS_HEADER; p->seggrn = 4; p->zoom = RZ_NEW0(RzPrintZoom); p->reg = NULL; @@ -388,8 +386,7 @@ static inline void print_addr(RzStrBuf *sb, RzPrint *p, ut64 addr) { bool use_segoff = p ? (p->flags & RZ_PRINT_FLAGS_SEGOFF) : false; bool use_color = p ? (p->flags & RZ_PRINT_FLAGS_COLOR) : false; bool dec = p ? (p->flags & RZ_PRINT_FLAGS_ADDRDEC) : false; - bool mod = p ? (p->flags & RZ_PRINT_FLAGS_ADDRMOD) : false; - char ch = p ? ((p->addrmod && mod) ? ((addr % p->addrmod) ? ' ' : ',') : ' ') : ' '; + char ch = ' '; if (p && p->flags & RZ_PRINT_FLAGS_COMPACT && p->col == 1) { ch = '|'; } From 7980f0969a42cd9bf60dce20eda2a84fd68df178 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 9 Feb 2025 10:45:21 -0500 Subject: [PATCH 125/157] Fix: Don't print none-printable strings (e.g. only NUL byte strings). --- librz/core/disasm.c | 2 +- librz/util/str.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/librz/core/disasm.c b/librz/core/disasm.c index d229b8c519c..bdca28205a6 100644 --- a/librz/core/disasm.c +++ b/librz/core/disasm.c @@ -3828,7 +3828,7 @@ static void ds_print_str(RzDisasmState *ds, const char *str, int len, ut64 refad } const char *prefix; char *escstr = ds_esc_str(ds, str, len, &prefix, false); - if (escstr) { + if (escstr && rz_str_is_printable_incl_newlines(escstr)) { bool inv = ds->show_color && !ds->show_emu_strinv; ds_begin_comment(ds); ds_comment(ds, true, "; %s%s\"%.128s\"%s", inv ? Color_INVERT : "", prefix, escstr, diff --git a/librz/util/str.c b/librz/util/str.c index 856ae98c893..01103f3be2b 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -2160,6 +2160,9 @@ RZ_API bool rz_str_is_printable_limited(const char *str, int size) { } RZ_API bool rz_str_is_printable_incl_newlines(const char *str) { + if (!str || str[0] == '\0') { + return false; + } while (*str) { int ulen = rz_utf8_decode((const ut8 *)str, strlen(str), NULL); if (ulen > 1) { From efa98fb31beb20a4431e919698bd66bfeabede27 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 9 Feb 2025 10:48:47 -0500 Subject: [PATCH 126/157] Check if flag at refaddr is a string before printing it as such. --- librz/core/disasm.c | 2 +- librz/include/rz_core.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/librz/core/disasm.c b/librz/core/disasm.c index bdca28205a6..9798f162caf 100644 --- a/librz/core/disasm.c +++ b/librz/core/disasm.c @@ -4058,7 +4058,7 @@ static void ds_print_ptr(RzDisasmState *ds, int len, int idx) { } #endif f = rz_flag_get_i(core->flags, refaddr); - if (f) { + if (f && (RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STRINGS) || RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STR))) { if (strlen(msg) != 1) { char *msg2 = rz_str_dup(msg); if (msg2) { diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index f75b3f320e1..15d069a67d6 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -57,6 +57,7 @@ RZ_LIB_VERSION_HEADER(rz_core); #define RZ_FLAGS_FS_SEGMENTS "segments" #define RZ_FLAGS_FS_SIGNS "sign" #define RZ_FLAGS_FS_STRINGS "strings" +#define RZ_FLAGS_FS_STR "str" #define RZ_FLAGS_FS_SYMBOLS "symbols" #define RZ_FLAGS_FS_SYMBOLS_SECTIONS "symbols.sections" #define RZ_FLAGS_FS_SYSCALLS "syscalls" From 80ed949d8aed16051d54c11e68e5ddce3f5d27ac Mon Sep 17 00:00:00 2001 From: Rot127 Date: Sun, 9 Feb 2025 10:53:49 -0500 Subject: [PATCH 127/157] Revert default string encoding setting to UTF-8 (breaks many tests). --- librz/core/cconfig.c | 3 ++- librz/core/disasm.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 4a5cba13ca1..87550af14ca 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1223,6 +1223,7 @@ static bool find_encoding(RzConfigNode *node, RzStrEnc *encoding) { // Edge case when the node was just initialized but the options // were not added yet. *encoding = rz_str_enc_string_as_type(node->value); + return true; } return false; } @@ -3709,7 +3710,7 @@ RZ_API int rz_core_config_init(RzCore *core) { /* str */ SETCB("str.escbslash", "false", &cb_str_escbslash, "Escape the backslash"); - n = NODECB("str.encoding", "utf8", &cb_str_encoding); + n = NODECB("str.encoding", "guess", &cb_str_encoding); SETDESC(n, "The default string encoding type (when set to guess, it is automatically guessed)."); SETOPTIONS(n, "ascii", "8bit", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL); diff --git a/librz/core/disasm.c b/librz/core/disasm.c index 9798f162caf..fe6c7f67ad7 100644 --- a/librz/core/disasm.c +++ b/librz/core/disasm.c @@ -4058,7 +4058,7 @@ static void ds_print_ptr(RzDisasmState *ds, int len, int idx) { } #endif f = rz_flag_get_i(core->flags, refaddr); - if (f && (RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STRINGS) || RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STR))) { + if (f && f->space && (RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STRINGS) || RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STR))) { if (strlen(msg) != 1) { char *msg2 = rz_str_dup(msg); if (msg2) { From aa19d6c360edfdc66d71342cb4bfef9b189f1735 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 07:29:18 -0500 Subject: [PATCH 128/157] Fix rebase changes --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 87550af14ca..243e97ea0d4 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -2393,7 +2393,7 @@ static bool cb_contiguous(void *user, void *data) { static bool cb_searchalign(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; - if (rz_bits_count_ut64(node->i_value) != 1) { + if (rz_bits_count_ones_ut64(node->i_value) != 1) { RZ_LOG_ERROR("Alignment is only defined for '>0' and 'n^2'.\n"); return false; } From 7c715684865d783c122e7a82293b8a4b6d35ad3c Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 10:20:06 -0500 Subject: [PATCH 129/157] Revert "Check if flag at refaddr is a string before printing it as such." This reverts commit 15a565a162dc8ca38d70e3c1b3f04f6c63587933. Also fixes the underlying issue by assuming UTF16 can decode less then 2 bytes. --- librz/core/disasm.c | 2 +- librz/include/rz_core.h | 1 - librz/include/rz_util/rz_str.h | 2 ++ librz/util/str.c | 5 +---- librz/util/str_search.c | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/librz/core/disasm.c b/librz/core/disasm.c index fe6c7f67ad7..bdca28205a6 100644 --- a/librz/core/disasm.c +++ b/librz/core/disasm.c @@ -4058,7 +4058,7 @@ static void ds_print_ptr(RzDisasmState *ds, int len, int idx) { } #endif f = rz_flag_get_i(core->flags, refaddr); - if (f && f->space && (RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STRINGS) || RZ_STR_EQ(f->space->name, RZ_FLAGS_FS_STR))) { + if (f) { if (strlen(msg) != 1) { char *msg2 = rz_str_dup(msg); if (msg2) { diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 15d069a67d6..f75b3f320e1 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -57,7 +57,6 @@ RZ_LIB_VERSION_HEADER(rz_core); #define RZ_FLAGS_FS_SEGMENTS "segments" #define RZ_FLAGS_FS_SIGNS "sign" #define RZ_FLAGS_FS_STRINGS "strings" -#define RZ_FLAGS_FS_STR "str" #define RZ_FLAGS_FS_SYMBOLS "symbols" #define RZ_FLAGS_FS_SYMBOLS_SECTIONS "symbols.sections" #define RZ_FLAGS_FS_SYSCALLS "syscalls" diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index 5b4bf9e574e..141cd36160f 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -10,6 +10,8 @@ extern "C" { #endif +#define ASCII_LAST_CODE_POINT 0x7F + typedef enum { RZ_STRING_TYPE_RAW, ///< The raw sequence of bytes without any marker of beginning or end RZ_STRING_TYPE_ZERO, ///< C-style strings (ASCII or UTF-8) with zero as the end marker diff --git a/librz/util/str.c b/librz/util/str.c index 01103f3be2b..8890e08b939 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -1751,7 +1751,7 @@ static char *rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool } if (show_asciidot && !IS_PRINTABLE(ch)) { *q++ = '.'; - } else if (ch_bytes > 1) { + } else if (ch > ASCII_LAST_CODE_POINT) { if (keep_printable) { q += rz_utf8_encode((ut8 *)q, ch); } else { @@ -2160,9 +2160,6 @@ RZ_API bool rz_str_is_printable_limited(const char *str, int size) { } RZ_API bool rz_str_is_printable_incl_newlines(const char *str) { - if (!str || str[0] == '\0') { - return false; - } while (*str) { int ulen = rz_utf8_decode((const ut8 *)str, strlen(str), NULL); if (ulen > 1) { diff --git a/librz/util/str_search.c b/librz/util/str_search.c index 59cbfe1bbc9..cbb3b8b788f 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -250,7 +250,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 for (i = 0; i < opt->max_str_length - look_ahead && needle < to; i += rc) { RzCodePoint r = 0; - switch(str_type) { + switch (str_type) { case RZ_STRING_ENC_UTF32LE: rc = rz_utf32le_decode(buf + needle - from, to - needle, &r); break; From 073c6ed349196eb2eeeff392a8fbc14716141752 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 10:30:22 -0500 Subject: [PATCH 130/157] Fix check setting invalid encoding. --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 243e97ea0d4..8ede735b8cc 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1239,7 +1239,7 @@ static bool cb_str_encoding(void *user, void *data) { "if 2nd - 4th & 6th bytes are 0 & no char > 0x10ffff then utf32le else " "if utf8 char detected then utf8 else 8bit\n"); return false; - } else if (RZ_STR_EQ("settings", node->value) || (RZ_STR_EQ("guess", node->value) && !found_enc)) { + } else if (!RZ_STR_EQ("guess", node->value) && !found_enc) { RZ_LOG_ERROR("Invalid value for str.encoding (%s).\n", node->value); return false; } From db6c783c23ae7125fd4014d90b4a7c56296615dc Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 10:31:07 -0500 Subject: [PATCH 131/157] Fix tests which showed incorrect encoding enscaping prefix. UTF16/32 have a u/U prefix, no x. --- test/db/cmd/cmd_pd | 34 +++++++++++++++++----------------- test/db/cmd/cmd_pd2 | 8 ++++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/test/db/cmd/cmd_pd b/test/db/cmd/cmd_pd index b34a05338f9..d06aef151b2 100644 --- a/test/db/cmd/cmd_pd +++ b/test/db/cmd/cmd_pd @@ -916,14 +916,14 @@ EOF EXPECT=< \\u00a2\\u20ac\\U00010348 in green:\e[32m \xa2\u20ac\U00010348 \e[0m\n" + 0x004016ac mov edi, 0x40224a ; 'J"@' ; u"utf16le> \\u00a2\\u20ac\\U00010348 in green:\e[32m \u00a2\u20ac\U00010348 \e[0m\n" 0x004016b6 mov edi, str.e_e_b ; "_%e%e%b% " 0x004016b6 mov edi, str.e_e_b ; u"\u255f\u2565\u2565\u2562 is a wall with no embedded zeros\n" 0x004016c0 mov edi, 0x40230c @@ -1067,11 +1067,11 @@ pd 1 @ 0x00401701 EOF EXPECT=< \\u00a2\\u20ac\\U00010348 in cyan:\e[36m \xa2\u20ac\U00010348 \e[0m\n" + 0x004016de mov esi, str.Linux_wide_esc:___0m ; U"\tLinux_wide\\esc: \e[0m\U000000a1\r\n" + 0x004016ed mov edi, 0x40258c ; U"utf32le> \\u00a2\\u20ac\\U00010348 in cyan:\e[36m \U000000a2\U000020ac\U00010348 \e[0m\n" 0x004016f7 mov edi, 0x40266c ; U"Mountain range with embedded quad zeros: \U00010300A\U00010300A\U00010300A\n" 0x00401701 mov edi, 0x402730 ; '0'@' ; "e%" - 0x00401701 mov edi, 0x402730 ; '0'@' ; U"\u2565\u2565\u2565\u2565\u2565\u2565\u2565\u2565\u2565\u256b\u2565\u2565\u2565\u2565\u2565\u2565\u2565\u2565\u2565\u256b\u2565\u" + 0x00401701 mov edi, 0x402730 ; '0'@' ; U"\U00002565\U00002565\U00002565\U00002565\U00002565\U00002565\U00002565\U00002565\U00002565\U0000256b\U00002565\U00002565\U000025" EOF RUN @@ -1133,7 +1133,7 @@ utf8 utf16le 0x004016c0 mov edi, 0x40230c ; u"\u2520\u2542\u2500\u2500\u2542\u2528 is a fence with embedded zeros\n" utf32le - 0x004016ed mov edi, 0x40258c ; U"utf32le> \\u00a2\\u20ac\\U00010348 in cyan:\e[36m \xa2\u20ac\U00010348 \e[0m\n" + 0x004016ed mov edi, 0x40258c ; U"utf32le> \\u00a2\\u20ac\\U00010348 in cyan:\e[36m \U000000a2\U000020ac\U00010348 \e[0m\n" utf32be utf16le @@ -1179,15 +1179,15 @@ e asm.cmt.right=false pd 1 @ 0x140001010 EOF EXPECT=< Date: Mon, 10 Feb 2025 10:38:16 -0500 Subject: [PATCH 132/157] Fix unititialized condition for hits. --- librz/core/cmd/cmd_search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 475bbd79d0e..8d94fa1ae19 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2817,13 +2817,13 @@ static RzSearchOpt *setup_search_options(RzCore *core) { // "/x" RZ_IPI RzCmdStatus rz_cmd_search_hex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { RzSearchOpt *search_opts = setup_search_options(core); + RzList *hits = NULL; if (!search_opts) { goto error; } CMD_SEARCH_BEGIN(); - RzList *hits = NULL; const char *arg = argv[1]; RzSearchBytesPattern *pattern = rz_search_parse_byte_pattern(arg, "bytes"); From fe8a4b7ccc31e123734a69a63d5837a1ac82a205 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 11:05:40 -0500 Subject: [PATCH 133/157] Forbit to set settings as encoding. --- librz/core/cconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 8ede735b8cc..5bf383d00db 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -1239,7 +1239,7 @@ static bool cb_str_encoding(void *user, void *data) { "if 2nd - 4th & 6th bytes are 0 & no char > 0x10ffff then utf32le else " "if utf8 char detected then utf8 else 8bit\n"); return false; - } else if (!RZ_STR_EQ("guess", node->value) && !found_enc) { + } else if (RZ_STR_EQ("settings", node->value) || (!RZ_STR_EQ("guess", node->value) && !found_enc)) { RZ_LOG_ERROR("Invalid value for str.encoding (%s).\n", node->value); return false; } From d30d8ce29ccb91d8a89e17b8b632a28dfa728796 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 11:15:54 -0500 Subject: [PATCH 134/157] Handle the 'settings' case in code search. --- librz/core/cmd/cmd_search.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 8d94fa1ae19..2cddead61ef 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2957,8 +2957,11 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c expected = rz_str_enc_string_as_type(rz_config_get(core->config, "str.encoding")); } if (!RZ_STR_EQ(encoding, "guess") && expected == RZ_STRING_ENC_GUESS) { - RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); - goto invalid_args; + if (!RZ_STR_EQ(encoding, "settings")) { + RZ_LOG_ERROR("core: invalid encoding '%s'.\n", encoding); + goto invalid_args; + } + // Else we are fine, since the encoding in the settings is set to 'guess'. } bool progress = rz_config_get_b(core->config, "search.show_progress"); From 288ba04ad7831a7361b5ff86d5f8732e1c25b620 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 11:25:04 -0500 Subject: [PATCH 135/157] Don't show search progress by default for tests. --- binrz/rz-test/run.c | 1 + 1 file changed, 1 insertion(+) diff --git a/binrz/rz-test/run.c b/binrz/rz-test/run.c index 227ac1ea21a..570a6c1fd5e 100644 --- a/binrz/rz-test/run.c +++ b/binrz/rz-test/run.c @@ -119,6 +119,7 @@ static RzSubprocessOutput *run_rz_test(RzTestRunConfig *config, ut64 timeout_ms, rz_pvector_push(&args, "-escr.color=0"); rz_pvector_push(&args, "-escr.interactive=0"); rz_pvector_push(&args, "-eflirt.sigdb.load.system=false"); + rz_pvector_push(&args, "-esearch.show_progress=false"); rz_pvector_push(&args, "-eflirt.sigdb.load.home=false"); rz_pvector_push(&args, "-N"); RzListIter *it; From e831bee0d5a4ef50a034e02dfce5784149394dc0 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 11:45:49 -0500 Subject: [PATCH 136/157] Respect match_overlap option. --- librz/search/bytes_search.c | 2 +- librz/search/string_search.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index a5c5afaa007..62c9e377707 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -214,7 +214,7 @@ static bool bytes_find(RzSearchFindOpt *fopts, void *user, ut64 address, const R rz_pvector_foreach (patterns, it) { RzSearchBytesPattern *hp = (RzSearchBytesPattern *)*it; if (hp->regex) { - RzPVector *matches = rz_regex_match_all_overlap(hp->regex, (const char *)raw_buf, size, 0, RZ_REGEX_DEFAULT); + RzPVector *matches = fopts->match_overlap ? rz_regex_match_all_overlap(hp->regex, (const char *)raw_buf, size, 0, RZ_REGEX_DEFAULT) : rz_regex_match_all(hp->regex, (const char *)raw_buf, size, 0, RZ_REGEX_DEFAULT); void **it; RzPVector *match; rz_pvector_foreach (matches, it) { diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 87f37362233..7a312619803 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -34,7 +34,7 @@ static void align_offsets(RzUtilStrScanOptions options, RzStrEnc encoding, RzDet *str_mem_offset = ht_uu_find(options.utf8_to_mem_offset_map, found_idx | (group0->start), &offset_found); if (!offset_found) { RZ_LOG_WARN("Could not determine memory offset of %s string in search. String offset will be off for: %s\n", - rz_str_enc_as_string(detected->type), detected->string); + rz_str_enc_as_string(detected->type), detected->string); *str_mem_offset = detected->addr + group0->start; } *str_mem_len = ht_uu_find(options.utf8_to_mem_offset_map, found_idx | (group0->start + group0->len), &len_found) - *str_mem_offset; @@ -79,7 +79,7 @@ static bool string_find(RZ_NULLABLE RzSearchFindOpt *fopt, void *user, ut64 offs void **it_m = NULL; rz_pvector_foreach (ss->strings, it_m) { RzDetectedString *find = *it_m; - RzPVector *matches = rz_regex_match_all(find->regex, detected->string, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT); + RzPVector *matches = fopt->match_overlap ? rz_regex_match_all_overlap(find->regex, detected->string, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT) : rz_regex_match_all(find->regex, detected->string, RZ_REGEX_ZERO_TERMINATED, 0, RZ_REGEX_DEFAULT); void **it; rz_pvector_foreach (matches, it) { RzPVector *match = *it; From 921e5ae1595e71d5102174d9fa36a585a5f42031 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 11:50:57 -0500 Subject: [PATCH 137/157] Fix all simple tests which mostly rename things. --- test/db/archos/linux-x64/dbg_search_x | 1 - test/db/cmd/basic | 22 ++++---- test/db/cmd/bug_3788 | 13 ++--- test/db/cmd/cmd_json | 10 ++-- test/db/cmd/cmd_ps | 10 ++-- test/db/cmd/cmd_search | 28 ---------- test/db/cmd/cmd_search_hit | 8 --- test/db/cmd/cmd_search_in | 6 --- test/db/cmd/cmd_search_x | 15 ------ test/db/cmd/cmd_search_z | 73 --------------------------- test/db/cmd/elf | 4 +- test/db/cmd/hex | 53 +++++++++---------- test/db/cmd/print | 2 + test/db/cmd/project | 1 + test/db/formats/elf/strings | 2 +- 15 files changed, 58 insertions(+), 190 deletions(-) diff --git a/test/db/archos/linux-x64/dbg_search_x b/test/db/archos/linux-x64/dbg_search_x index 57f860c139a..692a42dea99 100644 --- a/test/db/archos/linux-x64/dbg_search_x +++ b/test/db/archos/linux-x64/dbg_search_x @@ -3,7 +3,6 @@ FILE=bins/elf/arch-x86_64-ls ARGS=-d CMDS=< /dev/null +s hit.bytes.0 %vi $? EOF EXPECT=< Date: Mon, 10 Feb 2025 12:01:27 -0500 Subject: [PATCH 138/157] Remove duplicate overlap setting --- librz/core/cconfig.c | 1 - test/db/cmd/basic | 2 +- test/db/cmd/cmd_search_x | 4 ++++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 5bf383d00db..96681cdf63f 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -3743,7 +3743,6 @@ RZ_API int rz_core_config_init(RzCore *core) { SETPREF("search.prefix", "hit", "Prefix name in search hits label"); SETI("search.maxhits", 0, "Maximum number of hits ('0' means no limit)"); SETBPREF("search.show_progress", "true", "Show the search process."); - SETBPREF("search.overlap", "true", "Look for overlapped search hits."); SETICB("search.str.min_length", RZ_BIN_STRING_SEARCH_MIN_STRING, &cb_search_str_min_length, "Smallest string length that is possible to find. (inclusive)"); SETICB("search.str.max_length", RZ_BIN_STRING_SEARCH_BUFFER_SIZE, &cb_search_str_max_length, "Maximum buffer size, which will also determine the maximum string length. (inclusive)"); SETICB("search.str.max_region_size", RZ_BIN_STRING_SEARCH_MAX_REGION_SIZE, &cb_search_str_max_region_size, "Maximum allowable size for the string search interval between two memory regions."); diff --git a/test/db/cmd/basic b/test/db/cmd/basic index cc3a86ead98..3a51a4da839 100644 --- a/test/db/cmd/basic +++ b/test/db/cmd/basic @@ -51,7 +51,7 @@ w AAAA EOF EXPECT=< Date: Mon, 10 Feb 2025 12:11:32 -0500 Subject: [PATCH 139/157] Fix now completely detected string. --- test/db/cmd/cmd_i | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/db/cmd/cmd_i b/test/db/cmd/cmd_i index 407f79d85bb..10df4b782d6 100644 --- a/test/db/cmd/cmd_i +++ b/test/db/cmd/cmd_i @@ -3244,10 +3244,9 @@ nth paddr vaddr len size section type string -------------------------------------------------------------- 0 0x000004b0 0x080484b0 12 13 .rodata ascii Hello world! -- small buffer 12 -- -nth paddr vaddr len size section type string ------------------------------------------------------------ - 0 0x000004b0 0x080484b0 9 9 .rodata ascii Hello wor - 1 0x000004b9 0x080484b9 3 4 .rodata ascii ld! +nth paddr vaddr len size section type string +-------------------------------------------------------------- + 0 0x000004b0 0x080484b0 12 12 .rodata ascii Hello world! EOF RUN From dd9aa63022d1208e6bde8a388ad754fc45354a9f Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 13:05:50 -0500 Subject: [PATCH 140/157] Fix docs --- librz/core/cmd_descs/cmd_descs.c | 8 ++++---- librz/core/cmd_descs/cmd_search.yaml | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 4593a9b38f9..7b6f8551461 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -2422,9 +2422,9 @@ static const RzCmdDescDetailEntry slash_z_Regex_space_Flags_detail_entries[] = { }; static const RzCmdDescDetailEntry slash_z_Exampels_detail_entries[] = { - { .text = "/z (ABC*)", .arg_str = NULL, .comment = "Search the exact string: \"(ABC*)\"." }, - { .text = "/z (ABC*)D li", .arg_str = NULL, .comment = "Search the exact string \"(ABC*)\" but case insensitive." }, - { .text = "/z (ABC*)D ri", .arg_str = NULL, .comment = "Search the regular expression \"(ABC*)D\" but case insensitive." }, + { .text = "/z (ABC*)", .arg_str = NULL, .comment = "Search the exact string \"(ABC*)\"." }, + { .text = "/z (ABC*)D li", .arg_str = NULL, .comment = "Search the exact string \"(ABC*)D\" but case insensitive." }, + { .text = "/z \\\\d\\\\sC*\\\\w ri", .arg_str = NULL, .comment = "Search the regular expression \"\\d\\sC*\\w\" but case insensitive." }, { .text = "/z \"и.{3}м\" ei", .arg_str = NULL, .comment = "Search the extended regular expression \"и.{3}м\" but case insensitive." }, { 0 }, }; @@ -2441,7 +2441,7 @@ static const RzCmdDescHelp slash_z_help = { static const char *cmd_search_string_sensitive_encoding_choices[] = { "ascii", "8bit", "mutf8", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", "guess", NULL }; static const RzCmdDescArg cmd_search_string_sensitive_args[] = { { - .name = "regex", + .name = "pattern", .type = RZ_CMD_ARG_TYPE_STRING, }, diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index c488fa1b314..a8613e81330 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -785,11 +785,11 @@ commands: - name: "Exampels" entries: - text: "/z (ABC*)" - comment: "Search the exact string: \"(ABC*)\"." + comment: "Search the exact string \"(ABC*)\"." - text: "/z (ABC*)D li" - comment: "Search the exact string \"(ABC*)\" but case insensitive." - - text: "/z (ABC*)D ri" - comment: "Search the regular expression \"(ABC*)D\" but case insensitive." + comment: "Search the exact string \"(ABC*)D\" but case insensitive." + - text: "/z \\\\d\\\\sC*\\\\w ri" + comment: "Search the regular expression \"\\d\\sC*\\w\" but case insensitive." - text: "/z \"и.{3}м\" ei" comment: "Search the extended regular expression \"и.{3}м\" but case insensitive." subcommands: @@ -804,7 +804,7 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_TABLE args: - - name: regex + - name: pattern type: RZ_CMD_ARG_TYPE_STRING - name: regex_flags type: RZ_CMD_ARG_TYPE_STRING From 05ea9314c85cf384792f007783fb8d975dda849c Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 13:27:19 -0500 Subject: [PATCH 141/157] Fix regex flags parsing. --- librz/core/cmd/cmd_search.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 2cddead61ef..2775faa63be 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2997,11 +2997,11 @@ static RzRegexFlags parse_re_flag_desc(const char *re_flags_desc) { flags |= RZ_REGEX_CASELESS; } if (strchr(re_flags_desc, 'l')) { - return RZ_REGEX_LITERAL; + flags |= RZ_REGEX_LITERAL; + return flags; } if (strchr(re_flags_desc, 'r')) { - fcount++; - flags |= RZ_REGEX_CASELESS; + return flags; } if (strchr(re_flags_desc, 'e')) { fcount++; From 43625206962e5d431d30444d273adc9a61a5310b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 13:30:32 -0500 Subject: [PATCH 142/157] Remove legacy regex search. --- librz/core/cmd/cmd_search.c | 31 ----- librz/core/cmd_descs/cmd_descs.c | 40 ------ librz/core/cmd_descs/cmd_descs.h | 4 - librz/core/cmd_descs/cmd_search.yaml | 29 ----- test/db/cmd/regexp | 176 +++++++++++++-------------- 5 files changed, 88 insertions(+), 192 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 2775faa63be..38f5031e48b 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2197,27 +2197,6 @@ static int cmd_search_legacy_handler(void *data, const char *input) { rz_search_begin(core->search); dosearch = true; break; - case 'e': // "/e" match regexp - if (input[1] == '?') { - RZ_LOG_ERROR("core: Usage: /e /foo/i or /e/foo/i\n"); - } else if (input[1]) { - RzSearchKeyword *kw; - kw = rz_search_keyword_new_regexp(input + 1, NULL); - if (!kw) { - RZ_LOG_ERROR("core: Invalid regexp specified\n"); - break; - } - rz_search_reset(core->search, RZ_SEARCH_REGEXP); - // TODO distance is unused - rz_search_set_distance(core->search, (int)rz_config_get_i(core->config, "search.distance")); - rz_search_kw_add(core->search, kw); - rz_search_begin(core->search); - dosearch = true; - param.regex_search = true; - } else { - RZ_LOG_ERROR("core: Missing regex\n"); - } - break; case 'E': // "/E" if (core->bin && core->bin->is_debugger) { rz_debug_map_sync(core->dbg); @@ -2654,16 +2633,6 @@ RZ_IPI RzCmdStatus rz_cmd_search_deltified_handler(RzCore *core, int argc, const return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); } -// "/e" -RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return pass_to_legacy_api(core, argc, argv, RZ_OUTPUT_MODE_STANDARD); -} - -// "/ei" -RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - return pass_to_legacy_api(core, argc, argv, state->mode); -} - // "/E" RZ_IPI RzCmdStatus rz_cmd_search_esil_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { return pass_to_legacy_api(core, argc, argv, mode); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 7b6f8551461..00f47997888 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -139,8 +139,6 @@ static const RzCmdDescArg cmd_search_insn_offset_backwards_fallback_args[2]; static const RzCmdDescArg cmd_search_pattern_args[2]; static const RzCmdDescArg cmd_search_blocks_args[2]; static const RzCmdDescArg cmd_search_sections_args[2]; -static const RzCmdDescArg cmd_search_regex_raw_sensitive_args[2]; -static const RzCmdDescArg cmd_search_regex_raw_insensitive_args[2]; static const RzCmdDescArg cmd_search_graph_path_args[3]; static const RzCmdDescArg cmd_search_graph_path_follow_jumps_args[3]; static const RzCmdDescArg cmd_search_hash_block_args[3]; @@ -1903,37 +1901,6 @@ static const RzCmdDescHelp cmd_search_sections_help = { .args = cmd_search_sections_args, }; -static const RzCmdDescHelp slash_e_help = { - .summary = "Raw regular expression search.", -}; -static const RzCmdDescArg cmd_search_regex_raw_sensitive_args[] = { - { - .name = "regex", - .type = RZ_CMD_ARG_TYPE_STRING, - .flags = RZ_CMD_ARG_FLAG_LAST, - - }, - { 0 }, -}; -static const RzCmdDescHelp cmd_search_regex_raw_sensitive_help = { - .summary = "Raw regular expression search (case-sensitive).", - .args = cmd_search_regex_raw_sensitive_args, -}; - -static const RzCmdDescArg cmd_search_regex_raw_insensitive_args[] = { - { - .name = "regex", - .type = RZ_CMD_ARG_TYPE_STRING, - .flags = RZ_CMD_ARG_FLAG_LAST, - - }, - { 0 }, -}; -static const RzCmdDescHelp cmd_search_regex_raw_insensitive_help = { - .summary = "Raw regular expression search (case-insensitive).", - .args = cmd_search_regex_raw_insensitive_args, -}; - static const RzCmdDescHelp slash_g_help = { .summary = "Search for all graph paths A to B (/gg follow jumps, see search.count and analysis.depth).", }; @@ -20964,13 +20931,6 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_search_sections_cd); rz_cmd_desc_set_default_mode(cmd_search_sections_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *slash_e_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/e", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_regex_raw_sensitive_handler, &cmd_search_regex_raw_sensitive_help, &slash_e_help); - rz_warn_if_fail(slash_e_cd); - rz_cmd_desc_set_default_mode(slash_e_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *cmd_search_regex_raw_insensitive_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_e_cd, "/ei", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_regex_raw_insensitive_handler, &cmd_search_regex_raw_insensitive_help); - rz_warn_if_fail(cmd_search_regex_raw_insensitive_cd); - rz_cmd_desc_set_default_mode(cmd_search_regex_raw_insensitive_cd, RZ_OUTPUT_MODE_STANDARD); - RzCmdDesc *slash_g_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/g", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_graph_path_handler, &cmd_search_graph_path_help, &slash_g_help); rz_warn_if_fail(slash_g_cd); rz_cmd_desc_set_default_mode(slash_g_cd, RZ_OUTPUT_MODE_STANDARD); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index e3e4e4f0999..5bfb8ca763f 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -123,10 +123,6 @@ RZ_IPI RzCmdStatus rz_cmd_search_pattern_handler(RzCore *core, int argc, const c RZ_IPI RzCmdStatus rz_cmd_search_blocks_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/s" RZ_IPI RzCmdStatus rz_cmd_search_sections_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); -// "/e" -RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); -// "/ei" -RZ_IPI RzCmdStatus rz_cmd_search_regex_raw_insensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/g" RZ_IPI RzCmdStatus rz_cmd_search_graph_path_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "/gg" diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index a8613e81330..dd3ae894351 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -337,35 +337,6 @@ commands: args: - name: "threshold" type: RZ_CMD_ARG_TYPE_STRING - - name: "/e" - summary: Raw regular expression search. - subcommands: - - name: "/e" - summary: Raw regular expression search (case-sensitive). - cname: cmd_search_regex_raw_sensitive - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE - args: - - name: regex - type: RZ_CMD_ARG_TYPE_STRING - - name: "/ei" - summary: Raw regular expression search (case-insensitive). - cname: cmd_search_regex_raw_insensitive - type: RZ_CMD_DESC_TYPE_ARGV_STATE - default_mode: RZ_OUTPUT_MODE_STANDARD - modes: - - RZ_OUTPUT_MODE_STANDARD - - RZ_OUTPUT_MODE_JSON - - RZ_OUTPUT_MODE_QUIET - - RZ_OUTPUT_MODE_TABLE - args: - - name: regex - type: RZ_CMD_ARG_TYPE_STRING - name: "/g" summary: Search for all graph paths A to B (/gg follow jumps, see search.count and analysis.depth). diff --git a/test/db/cmd/regexp b/test/db/cmd/regexp index 74593d3c07a..703ba8c02be 100644 --- a/test/db/cmd/regexp +++ b/test/db/cmd/regexp @@ -1,4 +1,4 @@ -NAME=/e /test/i +NAME=/z test i FILE=malloc://1024 CMDS=< Date: Mon, 10 Feb 2025 14:06:58 -0500 Subject: [PATCH 143/157] Apply review suggestions --- librz/core/cmd/cmd_search.c | 9 +++++++-- librz/core/csearch.c | 1 + librz/search/bytes_search.c | 4 ++++ librz/search/options.c | 5 +++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index 38f5031e48b..a06f7a2ce32 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2391,15 +2391,19 @@ static int cmd_search_legacy_handler(void *data, const char *input) { } static int pass_to_legacy_api(RzCore *core, int argc, const char **argv, RzOutputMode mode) { + rz_return_val_if_fail(core && argv, RZ_CMD_STATUS_ERROR); // The +1 strips the '/', because the legacy handler expect it this way. const char *cmd = argv[0] + 1; RzStrBuf *legacy_input = rz_strbuf_new(cmd); + if (!legacy_input) { + rz_warn_if_reached(); + return RZ_CMD_STATUS_ERROR; + } // Append arguments for (size_t i = 1; i < argc; i++) { rz_strbuf_appendf(legacy_input, " %s", argv[i]); } - bool succeeded = cmd_search_legacy_handler(core, rz_strbuf_get(legacy_input)); - rz_strbuf_free(legacy_input); + bool succeeded = cmd_search_legacy_handler(core, rz_strbuf_drain(legacy_input)); return succeeded ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; } @@ -2852,6 +2856,7 @@ static bool parse_pattern_arg(const char *arg, RZ_OUT ut8 *re, RZ_OUT size_t *le // "/xr" RZ_IPI RzCmdStatus rz_cmd_search_hex_regex_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { + rz_return_val_if_fail(core && state && argv, RZ_CMD_STATUS_ERROR); ut8 *re = RZ_NEWS0(ut8, strlen(argv[1])); RzSearchOpt *search_opts = setup_search_options(core); RzList *hits = NULL; diff --git a/librz/core/csearch.c b/librz/core/csearch.c index 80edf83129a..61575f20290 100644 --- a/librz/core/csearch.c +++ b/librz/core/csearch.c @@ -20,6 +20,7 @@ * \return The find options to use. Or NULL in case of failure. */ RZ_API RZ_OWN RzSearchFindOpt *rz_core_setup_default_search_find_opts(RzCore *core) { + rz_return_val_if_fail(core, NULL); RzSearchFindOpt *fopts = rz_search_find_opt_new(); if (!fopts) { RZ_LOG_ERROR("Failed allocating find options.\n"); diff --git a/librz/search/bytes_search.c b/librz/search/bytes_search.c index 62c9e377707..e605368cc30 100644 --- a/librz/search/bytes_search.c +++ b/librz/search/bytes_search.c @@ -120,6 +120,10 @@ RZ_API RZ_OWN RzSearchBytesPattern *rz_search_parse_byte_pattern(const char *byt ut8 *bytes = RZ_NEWS0(ut8, strlen(byte_pattern) + 1); ut8 *mask = RZ_NEWS0(ut8, strlen(byte_pattern) + 1); RzPVector *matches = NULL; + if (!bytes || !mask) { + RZ_LOG_ERROR("Allocation falied.\n"); + goto error; + } // Some sanity checks size_t ddot_count = rz_str_char_count(byte_pattern, ':'); diff --git a/librz/search/options.c b/librz/search/options.c index e16c32eb1eb..11157588b9b 100644 --- a/librz/search/options.c +++ b/librz/search/options.c @@ -16,9 +16,10 @@ RZ_API RZ_OWN RzSearchOpt *rz_search_opt_new() { } RZ_API void rz_search_opt_free(RZ_NULLABLE RzSearchOpt *opt) { - if (opt) { - rz_search_find_opt_free(opt->find_opts); + if (!opt) { + return; } + rz_search_find_opt_free(opt->find_opts); free(opt); } From b9d2d3bcb0187efc13d9c45c86a88407f90e3f3c Mon Sep 17 00:00:00 2001 From: Rot127 Date: Mon, 10 Feb 2025 14:07:54 -0500 Subject: [PATCH 144/157] Move regex flag utility function to rz_regex. --- librz/core/cmd/cmd_search.c | 37 +------------------ librz/include/rz_util/rz_regex.h | 1 + librz/util/regex.c | 63 ++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/librz/core/cmd/cmd_search.c b/librz/core/cmd/cmd_search.c index a06f7a2ce32..bcb16651c32 100644 --- a/librz/core/cmd/cmd_search.c +++ b/librz/core/cmd/cmd_search.c @@ -2960,44 +2960,9 @@ static RzCmdStatus cmd_string_search_generic(RzCore *core, const char *string, c return RZ_CMD_STATUS_ERROR; } -static RzRegexFlags parse_re_flag_desc(const char *re_flags_desc) { - RzRegexFlags flags = RZ_REGEX_DEFAULT; - if (RZ_STR_ISEMPTY(re_flags_desc)) { - return flags; - } - size_t fcount = 0; - if (strchr(re_flags_desc, 'i')) { - fcount++; - flags |= RZ_REGEX_CASELESS; - } - if (strchr(re_flags_desc, 'l')) { - flags |= RZ_REGEX_LITERAL; - return flags; - } - if (strchr(re_flags_desc, 'r')) { - return flags; - } - if (strchr(re_flags_desc, 'e')) { - fcount++; - flags |= RZ_REGEX_EXTENDED; - } - if (strchr(re_flags_desc, 'E')) { - fcount++; - flags |= RZ_REGEX_EXTENDED_MORE; - } - if (strchr(re_flags_desc, 'm')) { - fcount++; - flags |= RZ_REGEX_MULTILINE; - } - if (fcount != strlen(re_flags_desc)) { - return ~RZ_REGEX_DEFAULT; - } - return flags; -} - // "/z" RZ_IPI RzCmdStatus rz_cmd_search_string_sensitive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { - RzRegexFlags flags = parse_re_flag_desc(argv[2]); + RzRegexFlags flags = rz_regex_parse_flag_desc(argv[2]); if (flags == ~RZ_REGEX_DEFAULT) { RZ_LOG_ERROR("Regex flags are invalid: '%s'\n", argv[2]); return RZ_CMD_STATUS_ERROR; diff --git a/librz/include/rz_util/rz_regex.h b/librz/include/rz_util/rz_regex.h index 0f5767a60a9..de2adb97a7f 100644 --- a/librz/include/rz_util/rz_regex.h +++ b/librz/include/rz_util/rz_regex.h @@ -103,5 +103,6 @@ RZ_API RZ_OWN RzStrBuf *rz_regex_full_match_str(RZ_NONNULL const char *pattern, RZ_API RZ_OWN RzRegexCompContext *rz_regex_compile_context_new(); RZ_API void rz_regex_compile_context_free(RzRegexCompContext *ccontext); RZ_API void rz_regex_set_nul_as_newline(RZ_NONNULL RzRegexCompContext *ccontext); +RZ_API RzRegexFlags rz_regex_parse_flag_desc(RZ_NULLABLE const char *re_flags_desc); #endif /* RZ_REGEX_H */ diff --git a/librz/util/regex.c b/librz/util/regex.c index 38a4f61b769..1d0fb273792 100644 --- a/librz/util/regex.c +++ b/librz/util/regex.c @@ -587,3 +587,66 @@ RZ_API void rz_regex_compile_context_free(RzRegexCompContext *ccontext) { RZ_API void rz_regex_set_nul_as_newline(RZ_NONNULL RzRegexCompContext *ccontext) { pcre2_set_newline(ccontext, PCRE2_NEWLINE_NUL); } + + +/** + * \brief Parses a string with regex flags characters and returns the numerical + * value of it. + * + * - ''/NULL/'r' - Default: RZ_REGEX_DEFAULT + * - 'l' - RZ_REGEX_LITERAL + * - 'i' - RZ_REGEX_CASELESS + * - 'e' - RZ_REGEX_EXTENDED + * - 'E' - RZ_REGEX_EXTENDED_MORE + * - 'm' - RZ_REGEX_MULTILINE + * + * \param re_flags_desc The string containing several characters. + * + * \return The flags as numerical value. Or ~RZ_REGEX_DEFAULT if flags are invalid. + * + * Examples: + * + * - "ri" => RZ_REGEX_DEFAULT | RZ_REGEX_CASELESS + * - "li" => RZ_REGEX_LITERAL | RZ_REGEX_CASELESS + * - "Eim" => RZ_REGEX_EXTENDED | RZ_REGEX_CASELESS | RZ_REGEX_MULTILINE + * - "rl" => ~RZ_REGEX_DEFAULT => Error: Flag combination is invalid. + * - "xX" => ~RZ_REGEX_DEFAULT => Error: Flag combination is invalid. + */ +RZ_API RzRegexFlags rz_regex_parse_flag_desc(RZ_NULLABLE const char *re_flags_desc) { + RzRegexFlags flags = RZ_REGEX_DEFAULT; + if (RZ_STR_ISEMPTY(re_flags_desc)) { + return flags; + } + size_t fcount = 0; + if (strchr(re_flags_desc, 'i')) { + fcount++; + flags |= RZ_REGEX_CASELESS; + } + if (strchr(re_flags_desc, 'l')) { + fcount++; + flags |= RZ_REGEX_LITERAL; + goto return_flags; + } + if (strchr(re_flags_desc, 'r')) { + fcount++; + goto return_flags; + } + if (strchr(re_flags_desc, 'e')) { + fcount++; + flags |= RZ_REGEX_EXTENDED; + } + if (strchr(re_flags_desc, 'E')) { + fcount++; + flags |= RZ_REGEX_EXTENDED_MORE; + } + if (strchr(re_flags_desc, 'm')) { + fcount++; + flags |= RZ_REGEX_MULTILINE; + } +return_flags: + if (fcount != strlen(re_flags_desc)) { + RZ_LOG_ERROR("Flag combination '%s' is invalid.\n", re_flags_desc); + return ~RZ_REGEX_DEFAULT; + } + return flags; +} From 506727cf37f028431f0d34bd06f55544d0c42484 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 08:36:45 -0500 Subject: [PATCH 145/157] Update Unicode to version 16.0.0. This also moves most Unicode logic into unicode.c and separates the different Unicode groups into separated tables. --- librz/core/disasm.c | 4 +- librz/include/rz_util.h | 1 + librz/include/rz_util/rz_unicode.h | 36 +++ librz/include/rz_util/rz_utf8.h | 12 +- librz/util/meson.build | 1 + librz/util/str.c | 8 +- librz/util/str_search.c | 4 +- librz/util/unicode.c | 345 +++++++++++++++++++++++++++++ librz/util/utf16.c | 2 +- librz/util/utf8.c | 343 +++++++--------------------- test/db/cmd/cmd_ps | 11 + test/unit/test_encodings.c | 130 ++++++++++- 12 files changed, 606 insertions(+), 291 deletions(-) create mode 100644 librz/include/rz_util/rz_unicode.h create mode 100644 librz/util/unicode.c diff --git a/librz/core/disasm.c b/librz/core/disasm.c index bdca28205a6..ee2b5d0fc07 100644 --- a/librz/core/disasm.c +++ b/librz/core/disasm.c @@ -3744,7 +3744,7 @@ static char *ds_esc_str(RzDisasmState *ds, const char *str, int len, const char const char *prefix = ""; RzStrEnc strenc = ds->strenc; if (strenc == RZ_STRING_ENC_GUESS) { - strenc = rz_utf_bom_encoding((ut8 *)str, len); + strenc = rz_unicode_bom_encoding((ut8 *)str, len); } RzStrEscOptions opt = { 0 }; opt.show_asciidot = ds->show_asciidot; @@ -4051,7 +4051,7 @@ static void ds_print_ptr(RzDisasmState *ds, int len, int idx) { } bool print_msg = true; #if 1 - if (ds->strenc == RZ_STRING_ENC_GUESS && rz_utf_bom_encoding((ut8 *)msg, len) == RZ_STRING_ENC_GUESS && !(IS_PRINTABLE(*msg) || IS_WHITECHAR(*msg))) { + if (ds->strenc == RZ_STRING_ENC_GUESS && rz_unicode_bom_encoding((ut8 *)msg, len) == RZ_STRING_ENC_GUESS && !(IS_PRINTABLE(*msg) || IS_WHITECHAR(*msg))) { print_msg = false; } else { msg[len - 1] = 0; diff --git a/librz/include/rz_util.h b/librz/include/rz_util.h index d1703297b07..0626df7f83d 100644 --- a/librz/include/rz_util.h +++ b/librz/include/rz_util.h @@ -62,6 +62,7 @@ #include "rz_util/rz_sys.h" #include "rz_util/rz_tree.h" #include "rz_util/rz_uleb128.h" +#include "rz_util/rz_unicode.h" #include "rz_util/rz_utf8.h" #include "rz_util/rz_utf16.h" #include "rz_util/rz_utf32.h" diff --git a/librz/include/rz_util/rz_unicode.h b/librz/include/rz_util/rz_unicode.h new file mode 100644 index 00000000000..45e584b5ba4 --- /dev/null +++ b/librz/include/rz_util/rz_unicode.h @@ -0,0 +1,36 @@ +#ifndef RZ_UNICODE_H +#define RZ_UNICODE_H + +#include +#include "rz_str.h" + +#define UNICODE_VERSION_MAJOR 16 +#define UNICODE_VERSION_MINOR 0 +#define UNICODE_VERSION_PATCH 0 +#define UNICODE_LAST_CODE_POINT 0x10ffff + +struct rz_unicode_range_name_entry_t { + ut32 from; + ut32 to; + const char *name; +}; + +typedef struct rz_unicode_range_name_entry_t RzUnicodeRangeNameTable[]; + +struct rz_unicode_range_entry_t { + ut32 from; + ut32 to; +}; + +typedef struct rz_unicode_range_entry_t RzUnicodeRangeTable[]; + +typedef ut32 RzCodePoint; + +RZ_API bool rz_unicode_code_point_is_printable(const RzCodePoint c); +RZ_API bool rz_unicode_code_point_is_defined(const RzCodePoint c); +RZ_API bool rz_unicode_code_point_is_control(const RzCodePoint c); +RZ_API bool rz_unicode_code_point_is_surrogate(const RzCodePoint c); +RZ_API bool rz_unicode_code_point_is_private(const RzCodePoint c); +RZ_API RzStrEnc rz_unicode_bom_encoding(const ut8 *ptr, size_t ptrlen); + +#endif // RZ_UNICODE_H diff --git a/librz/include/rz_util/rz_utf8.h b/librz/include/rz_util/rz_utf8.h index 07f3857ac63..56d354579a5 100644 --- a/librz/include/rz_util/rz_utf8.h +++ b/librz/include/rz_util/rz_utf8.h @@ -2,30 +2,20 @@ #define RZ_UTF8_H /* For RzStrEnc definition */ -#include "rz_str.h" - -typedef struct { - ut32 from, to; - const char *name; -} RUtfBlock; - -#define UNICODE_LAST_CODE_POINT 0x10ffff +#include "rz_unicode.h" /** * \brief An Unicode code point. */ -typedef ut32 RzCodePoint; RZ_API int rz_utf8_encode(ut8 *ptr, const RzCodePoint ch); RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_mutf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_utf8_encode_str(const RzCodePoint *str, ut8 *dst, const int dst_length); RZ_API int rz_utf8_size(const ut8 *ptr); RZ_API int rz_utf8_strlen(const ut8 *str); -RZ_API bool rz_code_point_is_printable(const RzCodePoint c); RZ_API const char *rz_utf_block_name(int idx); RZ_API int rz_utf_block_idx(RzCodePoint ch); RZ_API int *rz_utf_block_list(const ut8 *str, int len, int **freq_list); -RZ_API RzStrEnc rz_utf_bom_encoding(const ut8 *ptr, int ptrlen); #if __WINDOWS__ #define rz_utf16_to_utf8(wc) rz_utf16_to_utf8_l((wchar_t *)wc, -1) #define rz_utf8_to_utf16(cstring) rz_utf8_to_utf16_l((char *)cstring, -1) diff --git a/librz/util/meson.build b/librz/util/meson.build index ca765107201..834955ba735 100644 --- a/librz/util/meson.build +++ b/librz/util/meson.build @@ -78,6 +78,7 @@ rz_util_common_sources = [ 'utf16.c', 'utf32.c', 'utf8.c', + 'unicode.c', 'vector.c', 'version.c', 'w32-sys.c', diff --git a/librz/util/str.c b/librz/util/str.c index 8890e08b939..02f1e42eefb 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -1877,7 +1877,7 @@ static char *escape_utf8_for_json(const char *buf, int buf_size, bool mutf8) { } } } else if (ch_bytes == 4) { - if (rz_code_point_is_printable(ch)) { + if (rz_unicode_code_point_is_printable(ch)) { // Assumes buf is UTF8-encoded for (i = 0; i < ch_bytes; i++) { *q++ = *(p + i); @@ -1901,7 +1901,7 @@ static char *escape_utf8_for_json(const char *buf, int buf_size, bool mutf8) { } } } else if (ch_bytes > 1) { - if (rz_code_point_is_printable(ch)) { + if (rz_unicode_code_point_is_printable(ch)) { // Assumes buf is UTF8-encoded for (i = 0; i < ch_bytes; i++) { *q++ = *(p + i); @@ -4073,7 +4073,7 @@ RZ_API RzList /**/ *rz_str_wrap(char *str, size_t width) { */ RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, ut32 length) { rz_return_val_if_fail(buffer, RZ_STRING_ENC_UTF8); - RzStrEnc enc = rz_utf_bom_encoding(buffer, length); + RzStrEnc enc = rz_unicode_bom_encoding(buffer, length); if (enc != RZ_STRING_ENC_GUESS) { return enc; } @@ -4267,7 +4267,7 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU } else { if (code_point == '\\') { rz_strbuf_appendf(&sb, "\\\\"); - } else if ((code_point == '\n' && !option->escape_nl) || (rz_code_point_is_printable(code_point) && code_point >= ' ')) { + } else if ((code_point == '\n' && !option->escape_nl) || (rz_unicode_code_point_is_printable(code_point) && code_point >= ' ')) { char tmp[5] = { 0 }; rz_utf8_encode((ut8 *)tmp, code_point); rz_strbuf_appendf(&sb, "%s", tmp); diff --git a/librz/util/str_search.c b/librz/util/str_search.c index cbb3b8b788f..b72c3ed6c42 100644 --- a/librz/util/str_search.c +++ b/librz/util/str_search.c @@ -303,7 +303,7 @@ static RzDetectedString *process_one_string(const ut8 *buf, const ut64 from, ut6 needle += rc; - if (rz_code_point_is_printable(r) && r != '\\') { + if (rz_unicode_code_point_is_printable(r) && r != '\\') { if (str_type == RZ_STRING_ENC_UTF32LE || str_type == RZ_STRING_ENC_UTF32BE) { if (r == 0xff) { r = 0; @@ -538,7 +538,7 @@ RZ_API int rz_scan_strings_raw(RZ_NONNULL const ut8 *buf, RZ_NONNULL RzList /* +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "rz_util/rz_assert.h" +#include "rz_util/rz_str.h" +#include "rz_util/rz_unicode.h" + +/** + * \brief Unicode control ranges. + * + * Table generated with `ucd-generate general-category`. + * See: https://github.com/BurntSushi/ucd-generate + * + * Unicode version: 16.0.0. + */ +const RzUnicodeRangeTable surrogate_ranges = { + { 55296, 57343 }, +}; + +/** + * \brief Unicode control ranges. + * + * Table generated with `ucd-generate general-category`. + * See: https://github.com/BurntSushi/ucd-generate + * + * Unicode version: 16.0.0. + */ +const RzUnicodeRangeTable control_ranges = { + { 0, 31 }, + { 127, 159 }, +}; + +/** + * \brief Unicode private use ranges. + * + * Table generated with `ucd-generate general-category`. + * See: https://github.com/BurntSushi/ucd-generate + * + * Unicode version: 16.0.0. + */ +const RzUnicodeRangeTable private_ranges = { + { 57344, 63743 }, + { 983040, 1048573 }, + { 1048576, 1114109 }, +}; + +/** + * \brief Unicode undefined ranges. + * + * Table generated with `ucd-generate general-category`. + * See: https://github.com/BurntSushi/ucd-generate + * + * Unicode version: 16.0.0. + */ +const RzUnicodeRangeTable undefined_ranges = { + { 888, 889 }, { 896, 899 }, { 907, 907 }, { 909, 909 }, { 930, 930 }, { 1328, 1328 }, + { 1367, 1368 }, { 1419, 1420 }, { 1424, 1424 }, { 1480, 1487 }, { 1515, 1518 }, + { 1525, 1535 }, { 1806, 1806 }, { 1867, 1868 }, { 1970, 1983 }, { 2043, 2044 }, + { 2094, 2095 }, { 2111, 2111 }, { 2140, 2141 }, { 2143, 2143 }, { 2155, 2159 }, + { 2191, 2191 }, { 2194, 2198 }, { 2436, 2436 }, { 2445, 2446 }, { 2449, 2450 }, + { 2473, 2473 }, { 2481, 2481 }, { 2483, 2485 }, { 2490, 2491 }, { 2501, 2502 }, + { 2505, 2506 }, { 2511, 2518 }, { 2520, 2523 }, { 2526, 2526 }, { 2532, 2533 }, + { 2559, 2560 }, { 2564, 2564 }, { 2571, 2574 }, { 2577, 2578 }, { 2601, 2601 }, + { 2609, 2609 }, { 2612, 2612 }, { 2615, 2615 }, { 2618, 2619 }, { 2621, 2621 }, + { 2627, 2630 }, { 2633, 2634 }, { 2638, 2640 }, { 2642, 2648 }, { 2653, 2653 }, + { 2655, 2661 }, { 2679, 2688 }, { 2692, 2692 }, { 2702, 2702 }, { 2706, 2706 }, + { 2729, 2729 }, { 2737, 2737 }, { 2740, 2740 }, { 2746, 2747 }, { 2758, 2758 }, + { 2762, 2762 }, { 2766, 2767 }, { 2769, 2783 }, { 2788, 2789 }, { 2802, 2808 }, + { 2816, 2816 }, { 2820, 2820 }, { 2829, 2830 }, { 2833, 2834 }, { 2857, 2857 }, + { 2865, 2865 }, { 2868, 2868 }, { 2874, 2875 }, { 2885, 2886 }, { 2889, 2890 }, + { 2894, 2900 }, { 2904, 2907 }, { 2910, 2910 }, { 2916, 2917 }, { 2936, 2945 }, + { 2948, 2948 }, { 2955, 2957 }, { 2961, 2961 }, { 2966, 2968 }, { 2971, 2971 }, + { 2973, 2973 }, { 2976, 2978 }, { 2981, 2983 }, { 2987, 2989 }, { 3002, 3005 }, + { 3011, 3013 }, { 3017, 3017 }, { 3022, 3023 }, { 3025, 3030 }, { 3032, 3045 }, + { 3067, 3071 }, { 3085, 3085 }, { 3089, 3089 }, { 3113, 3113 }, { 3130, 3131 }, + { 3141, 3141 }, { 3145, 3145 }, { 3150, 3156 }, { 3159, 3159 }, { 3163, 3164 }, + { 3166, 3167 }, { 3172, 3173 }, { 3184, 3190 }, { 3213, 3213 }, { 3217, 3217 }, + { 3241, 3241 }, { 3252, 3252 }, { 3258, 3259 }, { 3269, 3269 }, { 3273, 3273 }, + { 3278, 3284 }, { 3287, 3292 }, { 3295, 3295 }, { 3300, 3301 }, { 3312, 3312 }, + { 3316, 3327 }, { 3341, 3341 }, { 3345, 3345 }, { 3397, 3397 }, { 3401, 3401 }, + { 3408, 3411 }, { 3428, 3429 }, { 3456, 3456 }, { 3460, 3460 }, { 3479, 3481 }, + { 3506, 3506 }, { 3516, 3516 }, { 3518, 3519 }, { 3527, 3529 }, { 3531, 3534 }, + { 3541, 3541 }, { 3543, 3543 }, { 3552, 3557 }, { 3568, 3569 }, { 3573, 3584 }, + { 3643, 3646 }, { 3676, 3712 }, { 3715, 3715 }, { 3717, 3717 }, { 3723, 3723 }, + { 3748, 3748 }, { 3750, 3750 }, { 3774, 3775 }, { 3781, 3781 }, { 3783, 3783 }, + { 3791, 3791 }, { 3802, 3803 }, { 3808, 3839 }, { 3912, 3912 }, { 3949, 3952 }, + { 3992, 3992 }, { 4029, 4029 }, { 4045, 4045 }, { 4059, 4095 }, { 4294, 4294 }, + { 4296, 4300 }, { 4302, 4303 }, { 4681, 4681 }, { 4686, 4687 }, { 4695, 4695 }, + { 4697, 4697 }, { 4702, 4703 }, { 4745, 4745 }, { 4750, 4751 }, { 4785, 4785 }, + { 4790, 4791 }, { 4799, 4799 }, { 4801, 4801 }, { 4806, 4807 }, { 4823, 4823 }, + { 4881, 4881 }, { 4886, 4887 }, { 4955, 4956 }, { 4989, 4991 }, { 5018, 5023 }, + { 5110, 5111 }, { 5118, 5119 }, { 5789, 5791 }, { 5881, 5887 }, { 5910, 5918 }, + { 5943, 5951 }, { 5972, 5983 }, { 5997, 5997 }, { 6001, 6001 }, { 6004, 6015 }, + { 6110, 6111 }, { 6122, 6127 }, { 6138, 6143 }, { 6170, 6175 }, { 6265, 6271 }, + { 6315, 6319 }, { 6390, 6399 }, { 6431, 6431 }, { 6444, 6447 }, { 6460, 6463 }, + { 6465, 6467 }, { 6510, 6511 }, { 6517, 6527 }, { 6572, 6575 }, { 6602, 6607 }, + { 6619, 6621 }, { 6684, 6685 }, { 6751, 6751 }, { 6781, 6782 }, { 6794, 6799 }, + { 6810, 6815 }, { 6830, 6831 }, { 6863, 6911 }, { 6989, 6989 }, { 7156, 7163 }, + { 7224, 7226 }, { 7242, 7244 }, { 7307, 7311 }, { 7355, 7356 }, { 7368, 7375 }, + { 7419, 7423 }, { 7958, 7959 }, { 7966, 7967 }, { 8006, 8007 }, { 8014, 8015 }, + { 8024, 8024 }, { 8026, 8026 }, { 8028, 8028 }, { 8030, 8030 }, { 8062, 8063 }, + { 8117, 8117 }, { 8133, 8133 }, { 8148, 8149 }, { 8156, 8156 }, { 8176, 8177 }, + { 8181, 8181 }, { 8191, 8191 }, { 8293, 8293 }, { 8306, 8307 }, { 8335, 8335 }, + { 8349, 8351 }, { 8385, 8399 }, { 8433, 8447 }, { 8588, 8591 }, { 9258, 9279 }, + { 9291, 9311 }, { 11124, 11125 }, { 11158, 11158 }, { 11508, 11512 }, + { 11558, 11558 }, { 11560, 11564 }, { 11566, 11567 }, { 11624, 11630 }, + { 11633, 11646 }, { 11671, 11679 }, { 11687, 11687 }, { 11695, 11695 }, + { 11703, 11703 }, { 11711, 11711 }, { 11719, 11719 }, { 11727, 11727 }, + { 11735, 11735 }, { 11743, 11743 }, { 11870, 11903 }, { 11930, 11930 }, + { 12020, 12031 }, { 12246, 12271 }, { 12352, 12352 }, { 12439, 12440 }, + { 12544, 12548 }, { 12592, 12592 }, { 12687, 12687 }, { 12774, 12782 }, + { 12831, 12831 }, { 42125, 42127 }, { 42183, 42191 }, { 42540, 42559 }, + { 42744, 42751 }, { 42958, 42959 }, { 42962, 42962 }, { 42964, 42964 }, + { 42973, 42993 }, { 43053, 43055 }, { 43066, 43071 }, { 43128, 43135 }, + { 43206, 43213 }, { 43226, 43231 }, { 43348, 43358 }, { 43389, 43391 }, + { 43470, 43470 }, { 43482, 43485 }, { 43519, 43519 }, { 43575, 43583 }, + { 43598, 43599 }, { 43610, 43611 }, { 43715, 43738 }, { 43767, 43776 }, + { 43783, 43784 }, { 43791, 43792 }, { 43799, 43807 }, { 43815, 43815 }, + { 43823, 43823 }, { 43884, 43887 }, { 44014, 44015 }, { 44026, 44031 }, + { 55204, 55215 }, { 55239, 55242 }, { 55292, 55295 }, { 64110, 64111 }, + { 64218, 64255 }, { 64263, 64274 }, { 64280, 64284 }, { 64311, 64311 }, + { 64317, 64317 }, { 64319, 64319 }, { 64322, 64322 }, { 64325, 64325 }, + { 64451, 64466 }, { 64912, 64913 }, { 64968, 64974 }, { 64976, 65007 }, + { 65050, 65055 }, { 65107, 65107 }, { 65127, 65127 }, { 65132, 65135 }, + { 65141, 65141 }, { 65277, 65278 }, { 65280, 65280 }, { 65471, 65473 }, + { 65480, 65481 }, { 65488, 65489 }, { 65496, 65497 }, { 65501, 65503 }, + { 65511, 65511 }, { 65519, 65528 }, { 65534, 65535 }, { 65548, 65548 }, + { 65575, 65575 }, { 65595, 65595 }, { 65598, 65598 }, { 65614, 65615 }, + { 65630, 65663 }, { 65787, 65791 }, { 65795, 65798 }, { 65844, 65846 }, + { 65935, 65935 }, { 65949, 65951 }, { 65953, 65999 }, { 66046, 66175 }, + { 66205, 66207 }, { 66257, 66271 }, { 66300, 66303 }, { 66340, 66348 }, + { 66379, 66383 }, { 66427, 66431 }, { 66462, 66462 }, { 66500, 66503 }, + { 66518, 66559 }, { 66718, 66719 }, { 66730, 66735 }, { 66772, 66775 }, + { 66812, 66815 }, { 66856, 66863 }, { 66916, 66926 }, { 66939, 66939 }, + { 66955, 66955 }, { 66963, 66963 }, { 66966, 66966 }, { 66978, 66978 }, + { 66994, 66994 }, { 67002, 67002 }, { 67005, 67007 }, { 67060, 67071 }, + { 67383, 67391 }, { 67414, 67423 }, { 67432, 67455 }, { 67462, 67462 }, + { 67505, 67505 }, { 67515, 67583 }, { 67590, 67591 }, { 67593, 67593 }, + { 67638, 67638 }, { 67641, 67643 }, { 67645, 67646 }, { 67670, 67670 }, + { 67743, 67750 }, { 67760, 67807 }, { 67827, 67827 }, { 67830, 67834 }, + { 67868, 67870 }, { 67898, 67902 }, { 67904, 67967 }, { 68024, 68027 }, + { 68048, 68049 }, { 68100, 68100 }, { 68103, 68107 }, { 68116, 68116 }, + { 68120, 68120 }, { 68150, 68151 }, { 68155, 68158 }, { 68169, 68175 }, + { 68185, 68191 }, { 68256, 68287 }, { 68327, 68330 }, { 68343, 68351 }, + { 68406, 68408 }, { 68438, 68439 }, { 68467, 68471 }, { 68498, 68504 }, + { 68509, 68520 }, { 68528, 68607 }, { 68681, 68735 }, { 68787, 68799 }, + { 68851, 68857 }, { 68904, 68911 }, { 68922, 68927 }, { 68966, 68968 }, + { 68998, 69005 }, { 69008, 69215 }, { 69247, 69247 }, { 69290, 69290 }, + { 69294, 69295 }, { 69298, 69313 }, { 69317, 69371 }, { 69416, 69423 }, + { 69466, 69487 }, { 69514, 69551 }, { 69580, 69599 }, { 69623, 69631 }, + { 69710, 69713 }, { 69750, 69758 }, { 69827, 69836 }, { 69838, 69839 }, + { 69865, 69871 }, { 69882, 69887 }, { 69941, 69941 }, { 69960, 69967 }, + { 70007, 70015 }, { 70112, 70112 }, { 70133, 70143 }, { 70162, 70162 }, + { 70210, 70271 }, { 70279, 70279 }, { 70281, 70281 }, { 70286, 70286 }, + { 70302, 70302 }, { 70314, 70319 }, { 70379, 70383 }, { 70394, 70399 }, + { 70404, 70404 }, { 70413, 70414 }, { 70417, 70418 }, { 70441, 70441 }, + { 70449, 70449 }, { 70452, 70452 }, { 70458, 70458 }, { 70469, 70470 }, + { 70473, 70474 }, { 70478, 70479 }, { 70481, 70486 }, { 70488, 70492 }, + { 70500, 70501 }, { 70509, 70511 }, { 70517, 70527 }, { 70538, 70538 }, + { 70540, 70541 }, { 70543, 70543 }, { 70582, 70582 }, { 70593, 70593 }, + { 70595, 70596 }, { 70598, 70598 }, { 70603, 70603 }, { 70614, 70614 }, + { 70617, 70624 }, { 70627, 70655 }, { 70748, 70748 }, { 70754, 70783 }, + { 70856, 70863 }, { 70874, 71039 }, { 71094, 71095 }, { 71134, 71167 }, + { 71237, 71247 }, { 71258, 71263 }, { 71277, 71295 }, { 71354, 71359 }, + { 71370, 71375 }, { 71396, 71423 }, { 71451, 71452 }, { 71468, 71471 }, + { 71495, 71679 }, { 71740, 71839 }, { 71923, 71934 }, { 71943, 71944 }, + { 71946, 71947 }, { 71956, 71956 }, { 71959, 71959 }, { 71990, 71990 }, + { 71993, 71994 }, { 72007, 72015 }, { 72026, 72095 }, { 72104, 72105 }, + { 72152, 72153 }, { 72165, 72191 }, { 72264, 72271 }, { 72355, 72367 }, + { 72441, 72447 }, { 72458, 72639 }, { 72674, 72687 }, { 72698, 72703 }, + { 72713, 72713 }, { 72759, 72759 }, { 72774, 72783 }, { 72813, 72815 }, + { 72848, 72849 }, { 72872, 72872 }, { 72887, 72959 }, { 72967, 72967 }, + { 72970, 72970 }, { 73015, 73017 }, { 73019, 73019 }, { 73022, 73022 }, + { 73032, 73039 }, { 73050, 73055 }, { 73062, 73062 }, { 73065, 73065 }, + { 73103, 73103 }, { 73106, 73106 }, { 73113, 73119 }, { 73130, 73439 }, + { 73465, 73471 }, { 73489, 73489 }, { 73531, 73533 }, { 73563, 73647 }, + { 73649, 73663 }, { 73714, 73726 }, { 74650, 74751 }, { 74863, 74863 }, + { 74869, 74879 }, { 75076, 77711 }, { 77811, 77823 }, { 78934, 78943 }, + { 82939, 82943 }, { 83527, 90367 }, { 90426, 92159 }, { 92729, 92735 }, + { 92767, 92767 }, { 92778, 92781 }, { 92863, 92863 }, { 92874, 92879 }, + { 92910, 92911 }, { 92918, 92927 }, { 92998, 93007 }, { 93018, 93018 }, + { 93026, 93026 }, { 93048, 93052 }, { 93072, 93503 }, { 93562, 93759 }, + { 93851, 93951 }, { 94027, 94030 }, { 94088, 94094 }, { 94112, 94175 }, + { 94181, 94191 }, { 94194, 94207 }, { 100344, 100351 }, { 101590, 101630 }, + { 101641, 110575 }, { 110580, 110580 }, { 110588, 110588 }, { 110591, 110591 }, + { 110883, 110897 }, { 110899, 110927 }, { 110931, 110932 }, { 110934, 110947 }, + { 110952, 110959 }, { 111356, 113663 }, { 113771, 113775 }, { 113789, 113791 }, + { 113801, 113807 }, { 113818, 113819 }, { 113828, 117759 }, { 118010, 118015 }, + { 118452, 118527 }, { 118574, 118575 }, { 118599, 118607 }, { 118724, 118783 }, + { 119030, 119039 }, { 119079, 119080 }, { 119275, 119295 }, { 119366, 119487 }, + { 119508, 119519 }, { 119540, 119551 }, { 119639, 119647 }, { 119673, 119807 }, + { 119893, 119893 }, { 119965, 119965 }, { 119968, 119969 }, { 119971, 119972 }, + { 119975, 119976 }, { 119981, 119981 }, { 119994, 119994 }, { 119996, 119996 }, + { 120004, 120004 }, { 120070, 120070 }, { 120075, 120076 }, { 120085, 120085 }, + { 120093, 120093 }, { 120122, 120122 }, { 120127, 120127 }, { 120133, 120133 }, + { 120135, 120137 }, { 120145, 120145 }, { 120486, 120487 }, { 120780, 120781 }, + { 121484, 121498 }, { 121504, 121504 }, { 121520, 122623 }, { 122655, 122660 }, + { 122667, 122879 }, { 122887, 122887 }, { 122905, 122906 }, { 122914, 122914 }, + { 122917, 122917 }, { 122923, 122927 }, { 122990, 123022 }, { 123024, 123135 }, + { 123181, 123183 }, { 123198, 123199 }, { 123210, 123213 }, { 123216, 123535 }, + { 123567, 123583 }, { 123642, 123646 }, { 123648, 124111 }, { 124154, 124367 }, + { 124411, 124414 }, { 124416, 124895 }, { 124903, 124903 }, { 124908, 124908 }, + { 124911, 124911 }, { 124927, 124927 }, { 125125, 125126 }, { 125143, 125183 }, + { 125260, 125263 }, { 125274, 125277 }, { 125280, 126064 }, { 126133, 126208 }, + { 126270, 126463 }, { 126468, 126468 }, { 126496, 126496 }, { 126499, 126499 }, + { 126501, 126502 }, { 126504, 126504 }, { 126515, 126515 }, { 126520, 126520 }, + { 126522, 126522 }, { 126524, 126529 }, { 126531, 126534 }, { 126536, 126536 }, + { 126538, 126538 }, { 126540, 126540 }, { 126544, 126544 }, { 126547, 126547 }, + { 126549, 126550 }, { 126552, 126552 }, { 126554, 126554 }, { 126556, 126556 }, + { 126558, 126558 }, { 126560, 126560 }, { 126563, 126563 }, { 126565, 126566 }, + { 126571, 126571 }, { 126579, 126579 }, { 126584, 126584 }, { 126589, 126589 }, + { 126591, 126591 }, { 126602, 126602 }, { 126620, 126624 }, { 126628, 126628 }, + { 126634, 126634 }, { 126652, 126703 }, { 126706, 126975 }, { 127020, 127023 }, + { 127124, 127135 }, { 127151, 127152 }, { 127168, 127168 }, { 127184, 127184 }, + { 127222, 127231 }, { 127406, 127461 }, { 127491, 127503 }, { 127548, 127551 }, + { 127561, 127567 }, { 127570, 127583 }, { 127590, 127743 }, { 128728, 128731 }, + { 128749, 128751 }, { 128765, 128767 }, { 128887, 128890 }, { 128986, 128991 }, + { 129004, 129007 }, { 129009, 129023 }, { 129036, 129039 }, { 129096, 129103 }, + { 129114, 129119 }, { 129160, 129167 }, { 129198, 129199 }, { 129212, 129215 }, + { 129218, 129279 }, { 129620, 129631 }, { 129646, 129647 }, { 129661, 129663 }, + { 129674, 129678 }, { 129735, 129741 }, { 129757, 129758 }, { 129770, 129775 }, + { 129785, 129791 }, { 129939, 129939 }, { 130042, 131071 }, { 173792, 173823 }, + { 177978, 177983 }, { 178206, 178207 }, { 183970, 183983 }, { 191457, 191471 }, + { 192094, 194559 }, { 195102, 196607 }, { 201547, 201551 }, { 205744, 917504 }, + { 917506, 917535 }, { 917632, 917759 }, { 918000, 983039 }, { 1048574, 1048575 }, + { 1114110, 1114111 }, { 0x110000, 0xFFFFFFFF } +}; + +static bool bin_search_range(RzCodePoint cp, const RzUnicodeRangeTable table, size_t table_size) { + int low = 0; + int hi = table_size - 1; + + do { + int mid = (low + hi) >> 1; + if (cp >= table[mid].from && cp <= table[mid].to) { + return true; + } + if (mid < table_size && cp > table[mid].to) { + low = mid + 1; + } + if (mid < table_size && cp < table[mid].from) { + hi = mid - 1; + } + } while (low <= hi); + + return false; +} + +/** + * \brief Returns true when the RzCodePoint is a defined Unicode code point. + * + * \param c RzCodePoint value to test. + * + * \return True if the code point is defined, false otherwise. + */ +RZ_API bool rz_unicode_code_point_is_defined(const RzCodePoint c) { + return !bin_search_range(c, undefined_ranges, RZ_ARRAY_SIZE(undefined_ranges)); +} + +/** + * \brief Returns true when the RzCodePoint is a Unicode control code point. + * + * \param c RzCodePoint value to test. + * + * \return True if the code point is a control code point, false otherwise. + */ +RZ_API bool rz_unicode_code_point_is_control(const RzCodePoint c) { + return (c >= control_ranges[0].from && c <= control_ranges[0].to) || + (c >= control_ranges[1].from && c <= control_ranges[1].to); +} + +/** + * \brief Returns true when the RzCodePoint is a Unicode surrogate code point. + * + * \param c RzCodePoint value to test. + * + * \return True if the code point is a surrogate code point, false otherwise. + */ +RZ_API bool rz_unicode_code_point_is_surrogate(const RzCodePoint c) { + return c >= surrogate_ranges[0].from && c <= surrogate_ranges[0].to; +} + +/** + * \brief Returns true when the RzCodePoint is a Unicode private code point. + * + * \param c RzCodePoint value to test. + * + * \return True if the code point is a private code point, false otherwise. + */ +RZ_API bool rz_unicode_code_point_is_private(const RzCodePoint c) { + return bin_search_range(c, private_ranges, RZ_ARRAY_SIZE(private_ranges)); +} + +/** + * \brief Returns true when the RzCodePoint is a printable symbol. + * Printable means: + * - Is defined Unicode code point. + * - Outside of the control plain. + * - Not a surrogate. + * - Not from the private range. + * + * Note: This means \n, \t, \r etc. are considered not printable! + * + * \param c RzCodePoint value to test + * + * \return true if the code point is printable, otherwise false + */ +RZ_API bool rz_unicode_code_point_is_printable(const RzCodePoint c) { + // RzCodePoints are most commonly single byte... We can early out with this common case. + if (c <= 0xFF) { + // Check for control plain (extended ASCII) here, because they are so common. + return !rz_unicode_code_point_is_control(c); + } + return rz_unicode_code_point_is_defined(c) && + !rz_unicode_code_point_is_control(c) && + !rz_unicode_code_point_is_surrogate(c) && + !rz_unicode_code_point_is_private(c); +} + +RZ_API RzStrEnc rz_unicode_bom_encoding(const ut8 *ptr, size_t ptrlen) { + rz_return_val_if_fail(ptr, RZ_STRING_ENC_GUESS); + if (ptrlen > 3) { + if (ptr[0] == 0xff && ptr[1] == 0xfe && !ptr[2] && !ptr[3]) { + return RZ_STRING_ENC_UTF32LE; + } + if (!ptr[0] && !ptr[1] && ptr[2] == 0xfe && ptr[3] == 0xff) { + return RZ_STRING_ENC_UTF32BE; + } + } + if (ptrlen > 2) { + if (ptr[0] == 0xef && ptr[1] == 0xbb && ptr[2] == 0xbf) { + return RZ_STRING_ENC_UTF8; + } + } + if (ptrlen > 1) { + if (ptr[0] == 0xff && ptr[1] == 0xfe) { + return RZ_STRING_ENC_UTF16LE; + } + if (ptr[0] == 0xfe && ptr[1] == 0xff) { + return RZ_STRING_ENC_UTF16BE; + } + } + return RZ_STRING_ENC_GUESS; +} diff --git a/librz/util/utf16.c b/librz/util/utf16.c index 335472f3800..00512cc9926 100644 --- a/librz/util/utf16.c +++ b/librz/util/utf16.c @@ -134,7 +134,7 @@ RZ_API bool rz_utf16_is_printable_code_point(RZ_NONNULL const ut8 *buf, size_t b RzCodePoint cp = 0; while (lookahead > 0) { size_t dec_bytes = rz_utf16_decode(buf + offset, buf_len - offset, &cp, big_endian); - if (!rz_code_point_is_printable(cp) || dec_bytes == 0) { + if (!rz_unicode_code_point_is_printable(cp) || dec_bytes == 0) { return false; } lookahead--; diff --git a/librz/util/utf8.c b/librz/util/utf8.c index 3aeb2e0dcf5..81d9467c490 100644 --- a/librz/util/utf8.c +++ b/librz/util/utf8.c @@ -7,199 +7,16 @@ #include #include -#define UTF_LAST_BLOCK (281) -#define UTF_BLOCKS_COUNT RZ_ARRAY_SIZE(utf_blocks) -#define UTF_NONPRINTABLE_RANGES_COUNT RZ_ARRAY_SIZE(nonprintable_ranges) +#define UNICODE_BLOCKS_COUNT RZ_ARRAY_SIZE(unicode_blocks) -const struct { - ut32 from, to; -} nonprintable_ranges[] = { - { 0x0000, 0x001F }, { 0x007F, 0x009F }, { 0x034F, 0x034F }, - { 0x0378, 0x0379 }, { 0x037F, 0x0383 }, { 0x038B, 0x038B }, - { 0x038D, 0x038D }, { 0x03A2, 0x03A2 }, { 0x0528, 0x0530 }, - { 0x0557, 0x0558 }, { 0x0560, 0x0560 }, { 0x0588, 0x0588 }, - { 0x058B, 0x058E }, { 0x0590, 0x0590 }, { 0x05C8, 0x05CF }, - { 0x05EB, 0x05EF }, { 0x05F5, 0x0605 }, { 0x061C, 0x061D }, - { 0x06DD, 0x06DD }, { 0x070E, 0x070F }, { 0x074B, 0x074C }, - { 0x07B2, 0x07BF }, { 0x07FB, 0x07FF }, { 0x082E, 0x082F }, - { 0x083F, 0x083F }, { 0x085C, 0x085D }, { 0x085F, 0x089F }, - { 0x08A1, 0x08A1 }, { 0x08AD, 0x08E3 }, { 0x08FF, 0x08FF }, - { 0x0978, 0x0978 }, { 0x0980, 0x0980 }, { 0x0984, 0x0984 }, - { 0x098D, 0x098E }, { 0x0991, 0x0992 }, { 0x09A9, 0x09A9 }, - { 0x09B1, 0x09B1 }, { 0x09B3, 0x09B5 }, { 0x09BA, 0x09BB }, - { 0x09C5, 0x09C6 }, { 0x09C9, 0x09CA }, { 0x09CF, 0x09D6 }, - { 0x09D8, 0x09DB }, { 0x09DE, 0x09DE }, { 0x09E4, 0x09E5 }, - { 0x09FC, 0x0A00 }, { 0x0A04, 0x0A04 }, { 0x0A0B, 0x0A0E }, - { 0x0A11, 0x0A12 }, { 0x0A29, 0x0A29 }, { 0x0A31, 0x0A31 }, - { 0x0A34, 0x0A34 }, { 0x0A37, 0x0A37 }, { 0x0A3A, 0x0A3B }, - { 0x0A3D, 0x0A3D }, { 0x0A43, 0x0A46 }, { 0x0A49, 0x0A4A }, - { 0x0A4E, 0x0A50 }, { 0x0A52, 0x0A58 }, { 0x0A5D, 0x0A5D }, - { 0x0A5F, 0x0A65 }, { 0x0A76, 0x0A80 }, { 0x0A84, 0x0A84 }, - { 0x0A8E, 0x0A8E }, { 0x0A92, 0x0A92 }, { 0x0AA9, 0x0AA9 }, - { 0x0AB1, 0x0AB1 }, { 0x0AB4, 0x0AB4 }, { 0x0ABA, 0x0ABB }, - { 0x0AC6, 0x0AC6 }, { 0x0ACA, 0x0ACA }, { 0x0ACE, 0x0ACF }, - { 0x0AD1, 0x0ADF }, { 0x0AE4, 0x0AE5 }, { 0x0AF2, 0x0B00 }, - { 0x0B04, 0x0B04 }, { 0x0B0D, 0x0B0E }, { 0x0B11, 0x0B12 }, - { 0x0B29, 0x0B29 }, { 0x0B31, 0x0B31 }, { 0x0B34, 0x0B34 }, - { 0x0B3A, 0x0B3B }, { 0x0B45, 0x0B46 }, { 0x0B49, 0x0B4A }, - { 0x0B4E, 0x0B55 }, { 0x0B58, 0x0B5B }, { 0x0B5E, 0x0B5E }, - { 0x0B64, 0x0B65 }, { 0x0B78, 0x0B81 }, { 0x0B84, 0x0B84 }, - { 0x0B8B, 0x0B8D }, { 0x0B91, 0x0B91 }, { 0x0B96, 0x0B98 }, - { 0x0B9B, 0x0B9B }, { 0x0B9D, 0x0B9D }, { 0x0BA0, 0x0BA2 }, - { 0x0BA5, 0x0BA7 }, { 0x0BAB, 0x0BAD }, { 0x0BBA, 0x0BBD }, - { 0x0BC3, 0x0BC5 }, { 0x0BC9, 0x0BC9 }, { 0x0BCE, 0x0BCF }, - { 0x0BD1, 0x0BD6 }, { 0x0BD8, 0x0BE5 }, { 0x0BFB, 0x0C00 }, - { 0x0C04, 0x0C04 }, { 0x0C0D, 0x0C0D }, { 0x0C11, 0x0C11 }, - { 0x0C29, 0x0C29 }, { 0x0C34, 0x0C34 }, { 0x0C3A, 0x0C3C }, - { 0x0C45, 0x0C45 }, { 0x0C49, 0x0C49 }, { 0x0C4E, 0x0C54 }, - { 0x0C57, 0x0C57 }, { 0x0C5A, 0x0C5F }, { 0x0C64, 0x0C65 }, - { 0x0C70, 0x0C77 }, { 0x0C80, 0x0C81 }, { 0x0C84, 0x0C84 }, - { 0x0C8D, 0x0C8D }, { 0x0C91, 0x0C91 }, { 0x0CA9, 0x0CA9 }, - { 0x0CB4, 0x0CB4 }, { 0x0CBA, 0x0CBB }, { 0x0CC5, 0x0CC5 }, - { 0x0CC9, 0x0CC9 }, { 0x0CCE, 0x0CD4 }, { 0x0CD7, 0x0CDD }, - { 0x0CDF, 0x0CDF }, { 0x0CE4, 0x0CE5 }, { 0x0CF0, 0x0CF0 }, - { 0x0CF3, 0x0D01 }, { 0x0D04, 0x0D04 }, { 0x0D0D, 0x0D0D }, - { 0x0D11, 0x0D11 }, { 0x0D3B, 0x0D3C }, { 0x0D45, 0x0D45 }, - { 0x0D49, 0x0D49 }, { 0x0D4F, 0x0D56 }, { 0x0D58, 0x0D5F }, - { 0x0D64, 0x0D65 }, { 0x0D76, 0x0D78 }, { 0x0D80, 0x0D81 }, - { 0x0D84, 0x0D84 }, { 0x0D97, 0x0D99 }, { 0x0DB2, 0x0DB2 }, - { 0x0DBC, 0x0DBC }, { 0x0DBE, 0x0DBF }, { 0x0DC7, 0x0DC9 }, - { 0x0DCB, 0x0DCE }, { 0x0DD5, 0x0DD5 }, { 0x0DD7, 0x0DD7 }, - { 0x0DE0, 0x0DF1 }, { 0x0DF5, 0x0E00 }, { 0x0E3B, 0x0E3E }, - { 0x0E5C, 0x0E80 }, { 0x0E83, 0x0E83 }, { 0x0E85, 0x0E86 }, - { 0x0E89, 0x0E89 }, { 0x0E8B, 0x0E8C }, { 0x0E8E, 0x0E93 }, - { 0x0E98, 0x0E98 }, { 0x0EA0, 0x0EA0 }, { 0x0EA4, 0x0EA4 }, - { 0x0EA6, 0x0EA6 }, { 0x0EA8, 0x0EA9 }, { 0x0EAC, 0x0EAC }, - { 0x0EBA, 0x0EBA }, { 0x0EBE, 0x0EBF }, { 0x0EC5, 0x0EC5 }, - { 0x0EC7, 0x0EC7 }, { 0x0ECE, 0x0ECF }, { 0x0EDA, 0x0EDB }, - { 0x0EE0, 0x0EFF }, { 0x0F48, 0x0F48 }, { 0x0F6D, 0x0F70 }, - { 0x0F98, 0x0F98 }, { 0x0FBD, 0x0FBD }, { 0x0FCD, 0x0FCD }, - { 0x0FDB, 0x0FFF }, { 0x10C6, 0x10C6 }, { 0x10C8, 0x10CC }, - { 0x10CE, 0x10CF }, { 0x115F, 0x1160 }, { 0x1249, 0x1249 }, - { 0x124E, 0x124F }, { 0x1257, 0x1257 }, { 0x1259, 0x1259 }, - { 0x125E, 0x125F }, { 0x1289, 0x1289 }, { 0x128E, 0x128F }, - { 0x12B1, 0x12B1 }, { 0x12B6, 0x12B7 }, { 0x12BF, 0x12BF }, - { 0x12C1, 0x12C1 }, { 0x12C6, 0x12C7 }, { 0x12D7, 0x12D7 }, - { 0x1311, 0x1311 }, { 0x1316, 0x1317 }, { 0x135B, 0x135C }, - { 0x137D, 0x137F }, { 0x139A, 0x139F }, { 0x13F5, 0x13FF }, - { 0x169D, 0x169F }, { 0x16F1, 0x16FF }, { 0x170D, 0x170D }, - { 0x1715, 0x171F }, { 0x1737, 0x173F }, { 0x1754, 0x175F }, - { 0x176D, 0x176D }, { 0x1771, 0x1771 }, { 0x1774, 0x177F }, - { 0x17B4, 0x17B5 }, { 0x17DE, 0x17DF }, { 0x17EA, 0x17EF }, - { 0x17FA, 0x17FF }, { 0x180B, 0x180D }, { 0x180F, 0x180F }, - { 0x181A, 0x181F }, { 0x1878, 0x187F }, { 0x18AB, 0x18AF }, - { 0x18F6, 0x18FF }, { 0x191D, 0x191F }, { 0x192C, 0x192F }, - { 0x193C, 0x193F }, { 0x1941, 0x1943 }, { 0x196E, 0x196F }, - { 0x1975, 0x197F }, { 0x19AC, 0x19AF }, { 0x19CA, 0x19CF }, - { 0x19DB, 0x19DD }, { 0x1A1C, 0x1A1D }, { 0x1A5F, 0x1A5F }, - { 0x1A7D, 0x1A7E }, { 0x1A8A, 0x1A8F }, { 0x1A9A, 0x1A9F }, - { 0x1AAE, 0x1AFF }, { 0x1B4C, 0x1B4F }, { 0x1B7D, 0x1B7F }, - { 0x1BF4, 0x1BFB }, { 0x1C38, 0x1C3A }, { 0x1C4A, 0x1C4C }, - { 0x1C80, 0x1CBF }, { 0x1CC8, 0x1CCF }, { 0x1CF7, 0x1CFF }, - { 0x1DE7, 0x1DFB }, { 0x1F16, 0x1F17 }, { 0x1F1E, 0x1F1F }, - { 0x1F46, 0x1F47 }, { 0x1F4E, 0x1F4F }, { 0x1F58, 0x1F58 }, - { 0x1F5A, 0x1F5A }, { 0x1F5C, 0x1F5C }, { 0x1F5E, 0x1F5E }, - { 0x1F7E, 0x1F7F }, { 0x1FB5, 0x1FB5 }, { 0x1FC5, 0x1FC5 }, - { 0x1FD4, 0x1FD5 }, { 0x1FDC, 0x1FDC }, { 0x1FF0, 0x1FF1 }, - { 0x1FF5, 0x1FF5 }, { 0x1FFF, 0x1FFF }, { 0x200B, 0x200F }, - { 0x202A, 0x202E }, { 0x2060, 0x206F }, { 0x2072, 0x2073 }, - { 0x208F, 0x208F }, { 0x209D, 0x209F }, { 0x20BB, 0x20CF }, - { 0x20F1, 0x20FF }, { 0x218A, 0x218F }, { 0x23F4, 0x23FF }, - { 0x2427, 0x243F }, { 0x244B, 0x245F }, { 0x2700, 0x2700 }, - { 0x2B4D, 0x2B4F }, { 0x2B5A, 0x2BFF }, { 0x2C2F, 0x2C2F }, - { 0x2C5F, 0x2C5F }, { 0x2CF4, 0x2CF8 }, { 0x2D26, 0x2D26 }, - { 0x2D28, 0x2D2C }, { 0x2D2E, 0x2D2F }, { 0x2D68, 0x2D6E }, - { 0x2D71, 0x2D7E }, { 0x2D97, 0x2D9F }, { 0x2DA7, 0x2DA7 }, - { 0x2DAF, 0x2DAF }, { 0x2DB7, 0x2DB7 }, { 0x2DBF, 0x2DBF }, - { 0x2DC7, 0x2DC7 }, { 0x2DCF, 0x2DCF }, { 0x2DD7, 0x2DD7 }, - { 0x2DDF, 0x2DDF }, { 0x2E3C, 0x2E7F }, { 0x2E9A, 0x2E9A }, - { 0x2EF4, 0x2EFF }, { 0x2FD6, 0x2FEF }, { 0x2FFC, 0x2FFF }, - { 0x3040, 0x3040 }, { 0x3097, 0x3098 }, { 0x3100, 0x3104 }, - { 0x312E, 0x3130 }, { 0x3164, 0x3164 }, { 0x318F, 0x318F }, - { 0x31BB, 0x31BF }, { 0x31E4, 0x31EF }, { 0x321F, 0x321F }, - { 0x32FF, 0x32FF }, { 0x4DB6, 0x4DBF }, { 0x9FCD, 0x9FFF }, - { 0xA48D, 0xA48F }, { 0xA4C7, 0xA4CF }, { 0xA62C, 0xA63F }, - { 0xA698, 0xA69E }, { 0xA6F8, 0xA6FF }, { 0xA78F, 0xA78F }, - { 0xA794, 0xA79F }, { 0xA7AB, 0xA7F7 }, { 0xA82C, 0xA82F }, - { 0xA83A, 0xA83F }, { 0xA878, 0xA87F }, { 0xA8C5, 0xA8CD }, - { 0xA8DA, 0xA8DF }, { 0xA8FC, 0xA8FF }, { 0xA954, 0xA95E }, - { 0xA97D, 0xA97F }, { 0xA9CE, 0xA9CE }, { 0xA9DA, 0xA9DD }, - { 0xA9E0, 0xA9FF }, { 0xAA37, 0xAA3F }, { 0xAA4E, 0xAA4F }, - { 0xAA5A, 0xAA5B }, { 0xAA7C, 0xAA7F }, { 0xAAC3, 0xAADA }, - { 0xAAF7, 0xAB00 }, { 0xAB07, 0xAB08 }, { 0xAB0F, 0xAB10 }, - { 0xAB17, 0xAB1F }, { 0xAB27, 0xAB27 }, { 0xAB2F, 0xABBF }, - { 0xABEE, 0xABEF }, { 0xABFA, 0xABFF }, { 0xD7A4, 0xD7AF }, - { 0xD7C7, 0xD7CA }, { 0xD7FC, 0xDFFF }, { 0xFA6E, 0xFA6F }, - { 0xFADA, 0xFAFF }, { 0xFB07, 0xFB12 }, { 0xFB18, 0xFB1C }, - { 0xFB37, 0xFB37 }, { 0xFB3D, 0xFB3D }, { 0xFB3F, 0xFB3F }, - { 0xFB42, 0xFB42 }, { 0xFB45, 0xFB45 }, { 0xFBC2, 0xFBD2 }, - { 0xFD40, 0xFD4F }, { 0xFD90, 0xFD91 }, { 0xFDC8, 0xFDEF }, - { 0xFDFE, 0xFE0F }, { 0xFE1A, 0xFE1F }, { 0xFE27, 0xFE2F }, - { 0xFE53, 0xFE53 }, { 0xFE67, 0xFE67 }, { 0xFE6C, 0xFE6F }, - { 0xFE75, 0xFE75 }, { 0xFEFD, 0xFEFF }, { 0xFF00, 0xFF00 }, - { 0xFFA0, 0xFFA0 }, { 0xFFBF, 0xFFC1 }, { 0xFFC8, 0xFFC9 }, - { 0xFFD0, 0xFFD1 }, { 0xFFD8, 0xFFD9 }, { 0xFFDD, 0xFFDF }, - { 0xFFE7, 0xFFE7 }, { 0xFFEF, 0xFFFB }, { 0xFFFE, 0xFFFF }, - { 0x1000C, 0x1000C }, { 0x10027, 0x10027 }, { 0x1003B, 0x1003B }, - { 0x1003E, 0x1003E }, { 0x1004E, 0x1004F }, { 0x1005E, 0x1007F }, - { 0x100FB, 0x100FF }, { 0x10103, 0x10106 }, { 0x10134, 0x10136 }, - { 0x1018B, 0x1018F }, { 0x1019C, 0x101CF }, { 0x101FE, 0x1027F }, - { 0x1029D, 0x1029F }, { 0x102D1, 0x102FF }, { 0x1031F, 0x1031F }, - { 0x10324, 0x1032F }, { 0x1034B, 0x1037F }, { 0x1039E, 0x1039E }, - { 0x103C4, 0x103C7 }, { 0x103D6, 0x103FF }, { 0x1049E, 0x1049F }, - { 0x104AA, 0x107FF }, { 0x10806, 0x10807 }, { 0x10809, 0x10809 }, - { 0x10836, 0x10836 }, { 0x10839, 0x1083B }, { 0x1083D, 0x1083E }, - { 0x10856, 0x10856 }, { 0x10860, 0x108FF }, { 0x1091C, 0x1091E }, - { 0x1093A, 0x1093E }, { 0x10940, 0x1097F }, { 0x109B8, 0x109BD }, - { 0x109C0, 0x109FF }, { 0x10A04, 0x10A04 }, { 0x10A07, 0x10A0B }, - { 0x10A14, 0x10A14 }, { 0x10A18, 0x10A18 }, { 0x10A34, 0x10A37 }, - { 0x10A3B, 0x10A3E }, { 0x10A48, 0x10A4F }, { 0x10A59, 0x10A5F }, - { 0x10A80, 0x10AFF }, { 0x10B36, 0x10B38 }, { 0x10B56, 0x10B57 }, - { 0x10B73, 0x10B77 }, { 0x10B80, 0x10BFF }, { 0x10C49, 0x10E5F }, - { 0x10E7F, 0x10FFF }, { 0x1104E, 0x11051 }, { 0x11070, 0x1107F }, - { 0x110BD, 0x110BD }, { 0x110C2, 0x110CF }, { 0x110E9, 0x110EF }, - { 0x110FA, 0x110FF }, { 0x11135, 0x11135 }, { 0x11144, 0x1117F }, - { 0x111C9, 0x111CF }, { 0x111DA, 0x1167F }, { 0x116B8, 0x116BF }, - { 0x116CA, 0x11FFF }, { 0x1236F, 0x123FF }, { 0x12463, 0x1246F }, - { 0x12474, 0x12FFF }, { 0x1342F, 0x167FF }, { 0x16A39, 0x16EFF }, - { 0x16F45, 0x16F4F }, { 0x16F7F, 0x16F8E }, { 0x16FA0, 0x1AFFF }, - { 0x1B002, 0x1CFFF }, { 0x1D0F6, 0x1D0FF }, { 0x1D127, 0x1D128 }, - { 0x1D173, 0x1D17A }, { 0x1D1DE, 0x1D1FF }, { 0x1D246, 0x1D2FF }, - { 0x1D357, 0x1D35F }, { 0x1D372, 0x1D3FF }, { 0x1D455, 0x1D455 }, - { 0x1D49D, 0x1D49D }, { 0x1D4A0, 0x1D4A1 }, { 0x1D4A3, 0x1D4A4 }, - { 0x1D4A7, 0x1D4A8 }, { 0x1D4AD, 0x1D4AD }, { 0x1D4BA, 0x1D4BA }, - { 0x1D4BC, 0x1D4BC }, { 0x1D4C4, 0x1D4C4 }, { 0x1D506, 0x1D506 }, - { 0x1D50B, 0x1D50C }, { 0x1D515, 0x1D515 }, { 0x1D51D, 0x1D51D }, - { 0x1D53A, 0x1D53A }, { 0x1D53F, 0x1D53F }, { 0x1D545, 0x1D545 }, - { 0x1D547, 0x1D549 }, { 0x1D551, 0x1D551 }, { 0x1D6A6, 0x1D6A7 }, - { 0x1D7CC, 0x1D7CD }, { 0x1D800, 0x1EDFF }, { 0x1EE04, 0x1EE04 }, - { 0x1EE20, 0x1EE20 }, { 0x1EE23, 0x1EE23 }, { 0x1EE25, 0x1EE26 }, - { 0x1EE28, 0x1EE28 }, { 0x1EE33, 0x1EE33 }, { 0x1EE38, 0x1EE38 }, - { 0x1EE3A, 0x1EE3A }, { 0x1EE3C, 0x1EE41 }, { 0x1EE43, 0x1EE46 }, - { 0x1EE48, 0x1EE48 }, { 0x1EE4A, 0x1EE4A }, { 0x1EE4C, 0x1EE4C }, - { 0x1EE50, 0x1EE50 }, { 0x1EE53, 0x1EE53 }, { 0x1EE55, 0x1EE56 }, - { 0x1EE58, 0x1EE58 }, { 0x1EE5A, 0x1EE5A }, { 0x1EE5C, 0x1EE5C }, - { 0x1EE5E, 0x1EE5E }, { 0x1EE60, 0x1EE60 }, { 0x1EE63, 0x1EE63 }, - { 0x1EE65, 0x1EE66 }, { 0x1EE6B, 0x1EE6B }, { 0x1EE73, 0x1EE73 }, - { 0x1EE78, 0x1EE78 }, { 0x1EE7D, 0x1EE7D }, { 0x1EE7F, 0x1EE7F }, - { 0x1EE8A, 0x1EE8A }, { 0x1EE9C, 0x1EEA0 }, { 0x1EEA4, 0x1EEA4 }, - { 0x1EEAA, 0x1EEAA }, { 0x1EEBC, 0x1EEEF }, { 0x1EEF2, 0x1EFFF }, - { 0x1F02C, 0x1F02F }, { 0x1F094, 0x1F09F }, { 0x1F0AF, 0x1F0B0 }, - { 0x1F0BF, 0x1F0C0 }, { 0x1F0D0, 0x1F0D0 }, { 0x1F0E0, 0x1F0FF }, - { 0x1F10B, 0x1F10F }, { 0x1F12F, 0x1F12F }, { 0x1F16C, 0x1F16F }, - { 0x1F19B, 0x1F1E5 }, { 0x1F203, 0x1F20F }, { 0x1F23B, 0x1F23F }, - { 0x1F249, 0x1F24F }, { 0x1F252, 0x1F2FF }, { 0x1F321, 0x1F32F }, - { 0x1F336, 0x1F336 }, { 0x1F37D, 0x1F37F }, { 0x1F394, 0x1F39F }, - { 0x1F3C5, 0x1F3C5 }, { 0x1F3CB, 0x1F3DF }, { 0x1F3F1, 0x1F3FF }, - { 0x1F43F, 0x1F43F }, { 0x1F441, 0x1F441 }, { 0x1F4F8, 0x1F4F8 }, - { 0x1F4FD, 0x1F4FF }, { 0x1F53E, 0x1F53F }, { 0x1F544, 0x1F54F }, - { 0x1F568, 0x1F5FA }, { 0x1F641, 0x1F644 }, { 0x1F650, 0x1F67F }, - { 0x1F6C6, 0x1F6FF }, { 0x1F774, 0x1FFFF }, { 0x2A6D7, 0x2A6FF }, - { 0x2B735, 0x2B73F }, { 0x2B81E, 0x2F7FF }, { 0x2FA1E, 0xF0000 }, - { 0xFFFFE, 0xFFFFF }, { 0x10FFFE, 0x10FFFF }, { 0x110000, 0xFFFFFFFF } -}; - -const RUtfBlock utf_blocks[] = { +/** + * \brief Unicode blocks. + * + * Copied from: UCD/Blocks.txt + * + * Unicode version: 16.0.0. + */ +const RzUnicodeRangeNameTable unicode_blocks = { { 0x0000, 0x007F, "Basic Latin" }, { 0x0080, 0x00FF, "Latin-1 Supplement" }, { 0x0100, 0x017F, "Latin Extended-A" }, @@ -220,6 +37,7 @@ const RUtfBlock utf_blocks[] = { { 0x0800, 0x083F, "Samaritan" }, { 0x0840, 0x085F, "Mandaic" }, { 0x0860, 0x086F, "Syriac Supplement" }, + { 0x0870, 0x089F, "Arabic Extended-B" }, { 0x08A0, 0x08FF, "Arabic Extended-A" }, { 0x0900, 0x097F, "Devanagari" }, { 0x0980, 0x09FF, "Bengali" }, @@ -263,6 +81,7 @@ const RUtfBlock utf_blocks[] = { { 0x1C00, 0x1C4F, "Lepcha" }, { 0x1C50, 0x1C7F, "Ol Chiki" }, { 0x1C80, 0x1C8F, "Cyrillic Extended-C" }, + { 0x1C90, 0x1CBF, "Georgian Extended" }, { 0x1CC0, 0x1CCF, "Sundanese Supplement" }, { 0x1CD0, 0x1CFF, "Vedic Extensions" }, { 0x1D00, 0x1D7F, "Phonetic Extensions" }, @@ -382,7 +201,10 @@ const RUtfBlock utf_blocks[] = { { 0x104B0, 0x104FF, "Osage" }, { 0x10500, 0x1052F, "Elbasan" }, { 0x10530, 0x1056F, "Caucasian Albanian" }, + { 0x10570, 0x105BF, "Vithkuqi" }, + { 0x105C0, 0x105FF, "Todhri" }, { 0x10600, 0x1077F, "Linear A" }, + { 0x10780, 0x107BF, "Latin Extended-F" }, { 0x10800, 0x1083F, "Cypriot Syllabary" }, { 0x10840, 0x1085F, "Imperial Aramaic" }, { 0x10860, 0x1087F, "Palmyrene" }, @@ -402,7 +224,16 @@ const RUtfBlock utf_blocks[] = { { 0x10B80, 0x10BAF, "Psalter Pahlavi" }, { 0x10C00, 0x10C4F, "Old Turkic" }, { 0x10C80, 0x10CFF, "Old Hungarian" }, + { 0x10D00, 0x10D3F, "Hanifi Rohingya" }, + { 0x10D40, 0x10D8F, "Garay" }, { 0x10E60, 0x10E7F, "Rumi Numeral Symbols" }, + { 0x10E80, 0x10EBF, "Yezidi" }, + { 0x10EC0, 0x10EFF, "Arabic Extended-C" }, + { 0x10F00, 0x10F2F, "Old Sogdian" }, + { 0x10F30, 0x10F6F, "Sogdian" }, + { 0x10F70, 0x10FAF, "Old Uyghur" }, + { 0x10FB0, 0x10FDF, "Chorasmian" }, + { 0x10FE0, 0x10FFF, "Elymaic" }, { 0x11000, 0x1107F, "Brahmi" }, { 0x11080, 0x110CF, "Kaithi" }, { 0x110D0, 0x110FF, "Sora Sompeng" }, @@ -414,48 +245,86 @@ const RUtfBlock utf_blocks[] = { { 0x11280, 0x112AF, "Multani" }, { 0x112B0, 0x112FF, "Khudawadi" }, { 0x11300, 0x1137F, "Grantha" }, + { 0x11380, 0x113FF, "Tulu-Tigalari" }, { 0x11400, 0x1147F, "Newa" }, { 0x11480, 0x114DF, "Tirhuta" }, { 0x11580, 0x115FF, "Siddham" }, { 0x11600, 0x1165F, "Modi" }, { 0x11660, 0x1167F, "Mongolian Supplement" }, { 0x11680, 0x116CF, "Takri" }, - { 0x11700, 0x1173F, "Ahom" }, + { 0x116D0, 0x116FF, "Myanmar Extended-C" }, + { 0x11700, 0x1174F, "Ahom" }, + { 0x11800, 0x1184F, "Dogra" }, { 0x118A0, 0x118FF, "Warang Citi" }, + { 0x11900, 0x1195F, "Dives Akuru" }, + { 0x119A0, 0x119FF, "Nandinagari" }, { 0x11A00, 0x11A4F, "Zanabazar Square" }, { 0x11A50, 0x11AAF, "Soyombo" }, + { 0x11AB0, 0x11ABF, "Unified Canadian Aboriginal Syllabics Extended-A" }, { 0x11AC0, 0x11AFF, "Pau Cin Hau" }, + { 0x11B00, 0x11B5F, "Devanagari Extended-A" }, + { 0x11BC0, 0x11BFF, "Sunuwar" }, { 0x11C00, 0x11C6F, "Bhaiksuki" }, { 0x11C70, 0x11CBF, "Marchen" }, { 0x11D00, 0x11D5F, "Masaram Gondi" }, + { 0x11D60, 0x11DAF, "Gunjala Gondi" }, + { 0x11EE0, 0x11EFF, "Makasar" }, + { 0x11F00, 0x11F5F, "Kawi" }, + { 0x11FB0, 0x11FBF, "Lisu Supplement" }, + { 0x11FC0, 0x11FFF, "Tamil Supplement" }, { 0x12000, 0x123FF, "Cuneiform" }, { 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" }, { 0x12480, 0x1254F, "Early Dynastic Cuneiform" }, + { 0x12F90, 0x12FFF, "Cypro-Minoan" }, { 0x13000, 0x1342F, "Egyptian Hieroglyphs" }, + { 0x13430, 0x1345F, "Egyptian Hieroglyph Format Controls" }, + { 0x13460, 0x143FF, "Egyptian Hieroglyphs Extended-A" }, { 0x14400, 0x1467F, "Anatolian Hieroglyphs" }, + { 0x16100, 0x1613F, "Gurung Khema" }, { 0x16800, 0x16A3F, "Bamum Supplement" }, { 0x16A40, 0x16A6F, "Mro" }, + { 0x16A70, 0x16ACF, "Tangsa" }, { 0x16AD0, 0x16AFF, "Bassa Vah" }, { 0x16B00, 0x16B8F, "Pahawh Hmong" }, + { 0x16D40, 0x16D7F, "Kirat Rai" }, + { 0x16E40, 0x16E9F, "Medefaidrin" }, { 0x16F00, 0x16F9F, "Miao" }, { 0x16FE0, 0x16FFF, "Ideographic Symbols and Punctuation" }, { 0x17000, 0x187FF, "Tangut" }, { 0x18800, 0x18AFF, "Tangut Components" }, + { 0x18B00, 0x18CFF, "Khitan Small Script" }, + { 0x18D00, 0x18D7F, "Tangut Supplement" }, + { 0x1AFF0, 0x1AFFF, "Kana Extended-B" }, { 0x1B000, 0x1B0FF, "Kana Supplement" }, { 0x1B100, 0x1B12F, "Kana Extended-A" }, + { 0x1B130, 0x1B16F, "Small Kana Extension" }, { 0x1B170, 0x1B2FF, "Nushu" }, { 0x1BC00, 0x1BC9F, "Duployan" }, { 0x1BCA0, 0x1BCAF, "Shorthand Format Controls" }, + { 0x1CC00, 0x1CEBF, "Symbols for Legacy Computing Supplement" }, + { 0x1CF00, 0x1CFCF, "Znamenny Musical Notation" }, { 0x1D000, 0x1D0FF, "Byzantine Musical Symbols" }, { 0x1D100, 0x1D1FF, "Musical Symbols" }, { 0x1D200, 0x1D24F, "Ancient Greek Musical Notation" }, + { 0x1D2C0, 0x1D2DF, "Kaktovik Numerals" }, + { 0x1D2E0, 0x1D2FF, "Mayan Numerals" }, { 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" }, { 0x1D360, 0x1D37F, "Counting Rod Numerals" }, { 0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols" }, { 0x1D800, 0x1DAAF, "Sutton SignWriting" }, + { 0x1DF00, 0x1DFFF, "Latin Extended-G" }, { 0x1E000, 0x1E02F, "Glagolitic Supplement" }, + { 0x1E030, 0x1E08F, "Cyrillic Extended-D" }, + { 0x1E100, 0x1E14F, "Nyiakeng Puachue Hmong" }, + { 0x1E290, 0x1E2BF, "Toto" }, + { 0x1E2C0, 0x1E2FF, "Wancho" }, + { 0x1E4D0, 0x1E4FF, "Nag Mundari" }, + { 0x1E5D0, 0x1E5FF, "Ol Onal" }, + { 0x1E7E0, 0x1E7FF, "Ethiopic Extended-B" }, { 0x1E800, 0x1E8DF, "Mende Kikakui" }, { 0x1E900, 0x1E95F, "Adlam" }, + { 0x1EC70, 0x1ECBF, "Indic Siyaq Numbers" }, + { 0x1ED00, 0x1ED4F, "Ottoman Siyaq Numbers" }, { 0x1EE00, 0x1EEFF, "Arabic Mathematical Alphabetic Symbols" }, { 0x1F000, 0x1F02F, "Mahjong Tiles" }, { 0x1F030, 0x1F09F, "Domino Tiles" }, @@ -470,24 +339,29 @@ const RUtfBlock utf_blocks[] = { { 0x1F780, 0x1F7FF, "Geometric Shapes Extended" }, { 0x1F800, 0x1F8FF, "Supplemental Arrows-C" }, { 0x1F900, 0x1F9FF, "Supplemental Symbols and Pictographs" }, + { 0x1FA00, 0x1FA6F, "Chess Symbols" }, + { 0x1FA70, 0x1FAFF, "Symbols and Pictographs Extended-A" }, + { 0x1FB00, 0x1FBFF, "Symbols for Legacy Computing" }, { 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" }, { 0x2A700, 0x2B73F, "CJK Unified Ideographs Extension C" }, { 0x2B740, 0x2B81F, "CJK Unified Ideographs Extension D" }, { 0x2B820, 0x2CEAF, "CJK Unified Ideographs Extension E" }, { 0x2CEB0, 0x2EBEF, "CJK Unified Ideographs Extension F" }, + { 0x2EBF0, 0x2EE5F, "CJK Unified Ideographs Extension I" }, { 0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement" }, + { 0x30000, 0x3134F, "CJK Unified Ideographs Extension G" }, + { 0x31350, 0x323AF, "CJK Unified Ideographs Extension H" }, { 0xE0000, 0xE007F, "Tags" }, { 0xE0100, 0xE01EF, "Variation Selectors Supplement" }, { 0xF0000, 0xFFFFF, "Supplementary Private Use Area-A" }, { 0x100000, 0x10FFFF, "Supplementary Private Use Area-B" }, - { 0x110000, 0xFFFFFFFF, "No_Block" } }; RZ_API const char *rz_utf_block_name(int idx) { - if (idx < 0 || idx >= UTF_LAST_BLOCK) { + if (idx < 0 || idx >= UNICODE_BLOCKS_COUNT) { return NULL; } - return utf_blocks[idx].name; + return unicode_blocks[idx].name; } /* Convert an UTF-8 buf into a unicode RzCodePoint */ @@ -599,44 +473,6 @@ RZ_API int rz_utf8_strlen(const ut8 *str) { return len; } -/** - * \brief Returns true when the RzCodePoint is a printable symbol - * - * \param c RzCodePoint value to test - * \return true if the rune is printable, otherwise false - */ -RZ_API bool rz_code_point_is_printable(const RzCodePoint c) { - // RzCodePoints are most commonly single byte... We can early out with this common case. - if (c < 0x34F) { - /* - manually copied from top, please update if this ever changes - { 0x0000, 0x001F }, { 0x007F, 0x009F }, { 0x034F, 0x034F }, - could do a linear search, but that's a lot slower than a few compare - */ - return !(c <= 0x1F || (c >= 0x7F && c <= 0x9F)); - } - - const int last = UTF_NONPRINTABLE_RANGES_COUNT; - - int low = 0; - int hi = last - 1; - - do { - int mid = (low + hi) >> 1; - if (c >= nonprintable_ranges[mid].from && c <= nonprintable_ranges[mid].to) { - return false; - } - if (mid < last && c > nonprintable_ranges[mid].to) { - low = mid + 1; - } - if (mid < last && c < nonprintable_ranges[mid].from) { - hi = mid - 1; - } - } while (low <= hi); - - return true; -} - #if __WINDOWS__ RZ_API char *rz_utf16_to_utf8_l(const wchar_t *wc, int len) { // -1 is allowed on purpose. @@ -733,23 +569,23 @@ RZ_API char *rz_acp_to_utf8_l(const char *str, int len) { #endif // __WINDOWS__ RZ_API int rz_utf_block_idx(RzCodePoint ch) { - const int last = UTF_BLOCKS_COUNT; + const int last = UNICODE_BLOCKS_COUNT; int low = 0, hi = last - 1, mid = 0; do { mid = (low + hi) >> 1; - if (ch >= utf_blocks[mid].from && ch <= utf_blocks[mid].to) { + if (ch >= unicode_blocks[mid].from && ch <= unicode_blocks[mid].to) { return mid; } - if (mid < last && ch > utf_blocks[mid].to) { + if (mid < last && ch > unicode_blocks[mid].to) { low = mid + 1; } - if (mid < last && ch < utf_blocks[mid].from) { + if (mid < last && ch < unicode_blocks[mid].from) { hi = mid - 1; } } while (low <= hi); - return UTF_BLOCKS_COUNT - 1; /* index for "No_Block" */ + return UNICODE_BLOCKS_COUNT - 1; /* index for "No_Block" */ } /* str must be UTF8-encoded */ @@ -760,7 +596,7 @@ RZ_API int *rz_utf_block_list(const ut8 *str, int len, int **freq_list) { if (len < 0) { len = strlen((const char *)str); } - int block_freq[UTF_BLOCKS_COUNT] = { 0 }; + int block_freq[UNICODE_BLOCKS_COUNT] = { 0 }; int *list = RZ_NEWS0(int, len + 1); if (!list) { return NULL; @@ -782,7 +618,7 @@ RZ_API int *rz_utf_block_list(const ut8 *str, int len, int **freq_list) { int block_idx; int ch_bytes = rz_utf8_decode(str_ptr, str_end - str_ptr, &ch); if (!ch_bytes) { - block_idx = UTF_BLOCKS_COUNT - 1; + block_idx = UNICODE_BLOCKS_COUNT - 1; ch_bytes = 1; } else { block_idx = rz_utf_block_idx(ch); @@ -807,28 +643,3 @@ RZ_API int *rz_utf_block_list(const ut8 *str, int len, int **freq_list) { } return list; } - -RZ_API RzStrEnc rz_utf_bom_encoding(const ut8 *ptr, int ptrlen) { - if (ptrlen > 3) { - if (ptr[0] == 0xff && ptr[1] == 0xfe && !ptr[2] && !ptr[3]) { - return RZ_STRING_ENC_UTF32LE; - } - if (!ptr[0] && !ptr[1] && ptr[2] == 0xfe && ptr[3] == 0xff) { - return RZ_STRING_ENC_UTF32BE; - } - } - if (ptrlen > 2) { - if (ptr[0] == 0xef && ptr[1] == 0xbb && ptr[2] == 0xbf) { - return RZ_STRING_ENC_UTF8; - } - } - if (ptrlen > 1) { - if (ptr[0] == 0xff && ptr[1] == 0xfe) { - return RZ_STRING_ENC_UTF16LE; - } - if (ptr[0] == 0xfe && ptr[1] == 0xff) { - return RZ_STRING_ENC_UTF16BE; - } - } - return RZ_STRING_ENC_GUESS; -} diff --git a/test/db/cmd/cmd_ps b/test/db/cmd/cmd_ps index c9c95aba3dc..f9f7fb815cb 100644 --- a/test/db/cmd/cmd_ps +++ b/test/db/cmd/cmd_ps @@ -184,3 +184,14 @@ EXPECT=< #include "minunit.h" -#include "rz_util/rz_utf32.h" +#include +#include #include #include @@ -178,9 +179,8 @@ bool test_rz_utf16_encode(void) { mu_end; } - bool test_rz_utf32_decode(void) { - const ut8 utf32_size_0[] = { }; + const ut8 utf32_size_0[] = {}; const ut8 utf32_size_1[] = { 0xAC }; const ut8 utf32_size_2[] = { 0xAC, 0xAC }; const ut8 utf32_size_3[] = { 0xAC, 0xAC, 0x20 }; @@ -192,7 +192,7 @@ bool test_rz_utf32_decode(void) { const ut8 utf32be_a[] = { 0x00, 0x00, 0xff, 0x41 }; const ut8 utf32le_a[] = { 0x41, 0xff, 0x00, 0x00 }; - // Chess tower symbol Red General: 🩠 + // Chess tower symbol Red General: 🩠 const ut8 utf32be_red_general[] = { 0x00, 0x01, 0xFA, 0x60 }; const ut8 utf32le_red_general[] = { 0x60, 0xfa, 0x01, 0x00 }; @@ -293,6 +293,121 @@ bool test_rz_ebcdic_valid(void) { mu_end; } +bool test_rz_unicode_printable(void) { + // Control + mu_assert_false(rz_unicode_code_point_is_printable(0x0), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(31), "Not printable."); + mu_assert_true(rz_unicode_code_point_is_printable(32), "Printable."); + mu_assert_true(rz_unicode_code_point_is_printable(126), "Printable."); + mu_assert_false(rz_unicode_code_point_is_printable(127), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(159), "Not printable."); + mu_assert_true(rz_unicode_code_point_is_printable(160), "Printable."); + + // Surrogates + mu_assert_false(rz_unicode_code_point_is_printable(55296), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(57343), "Not printable."); + + // Private - consider them not printable + mu_assert_false(rz_unicode_code_point_is_printable(57344), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(63743), "Not printable."); + mu_assert_true(rz_unicode_code_point_is_printable(63744), "Printable."); + + mu_assert_false(rz_unicode_code_point_is_printable(983040), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(1048573), "Not printable."); + + mu_assert_false(rz_unicode_code_point_is_printable(1048576), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(1114109), "Not printable."); + + // Undefined + // First + mu_assert_true(rz_unicode_code_point_is_printable(887), "Printable."); + mu_assert_false(rz_unicode_code_point_is_printable(888), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(889), "Not printable."); + mu_assert_true(rz_unicode_code_point_is_printable(890), "Printable."); + // Last + mu_assert_false(rz_unicode_code_point_is_printable(1114110), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(1114111), "Not printable."); + // Out of code point range. + mu_assert_false(rz_unicode_code_point_is_printable(0x110000), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(0xFFFFFFFF), "Not printable."); + // Even offset in table + mu_assert_true(rz_unicode_code_point_is_printable(3010), "Printable."); + mu_assert_false(rz_unicode_code_point_is_printable(3011), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(3013), "Not printable."); + mu_assert_true(rz_unicode_code_point_is_printable(3014), "Printable."); + // Odd offset in table + mu_assert_true(rz_unicode_code_point_is_printable(3016), "Printable."); + mu_assert_false(rz_unicode_code_point_is_printable(3017), "Not printable."); + mu_assert_true(rz_unicode_code_point_is_printable(3018), "Printable."); + + mu_end; +} + +bool test_rz_unicode_control(void) { + // Control + mu_assert_true(rz_unicode_code_point_is_control(0x0), "Control."); + mu_assert_true(rz_unicode_code_point_is_control(31), "Control."); + mu_assert_false(rz_unicode_code_point_is_control(32), "Not control."); + mu_assert_false(rz_unicode_code_point_is_control(126), "Not control."); + mu_assert_true(rz_unicode_code_point_is_control(127), "Control."); + mu_assert_true(rz_unicode_code_point_is_control(159), "Control."); + mu_assert_false(rz_unicode_code_point_is_control(160), "Not control."); + mu_end; +} + +bool test_rz_unicode_surrogate(void) { + // Surrogates + mu_assert_false(rz_unicode_code_point_is_printable(55296), "Not printable."); + mu_assert_false(rz_unicode_code_point_is_printable(57343), "Not printable."); + mu_end; +} + +bool test_rz_unicode_private(void) { + // Private - consider them private + mu_assert_false(rz_unicode_code_point_is_private(57343), "Not private."); + mu_assert_true(rz_unicode_code_point_is_private(57344), "Private."); + mu_assert_true(rz_unicode_code_point_is_private(63743), "Private."); + mu_assert_false(rz_unicode_code_point_is_private(63744), "Not private."); + + mu_assert_false(rz_unicode_code_point_is_private(983039), "Not private."); + mu_assert_true(rz_unicode_code_point_is_private(983040), "Private."); + mu_assert_true(rz_unicode_code_point_is_private(1048573), "Private."); + mu_assert_false(rz_unicode_code_point_is_private(1048574), "Not private."); + + mu_assert_false(rz_unicode_code_point_is_private(1048575), "Not private."); + mu_assert_true(rz_unicode_code_point_is_private(1048576), "Private."); + mu_assert_true(rz_unicode_code_point_is_private(1114109), "Private."); + mu_assert_false(rz_unicode_code_point_is_private(1114110), "Not private."); + mu_end; +} + +bool test_rz_unicode_undefined(void) { + // Undefined + // First + mu_assert_true(rz_unicode_code_point_is_defined(887), "Defined."); + mu_assert_false(rz_unicode_code_point_is_defined(888), "Not defined."); + mu_assert_false(rz_unicode_code_point_is_defined(889), "Not defined."); + mu_assert_true(rz_unicode_code_point_is_defined(890), "Defined."); + // Last + mu_assert_true(rz_unicode_code_point_is_defined(1114109), "Defined."); + mu_assert_false(rz_unicode_code_point_is_defined(1114110), "Not defined."); + mu_assert_false(rz_unicode_code_point_is_defined(1114111), "Not defined."); + mu_assert_false(rz_unicode_code_point_is_defined(1114112), "Defined."); + // Out of range + mu_assert_false(rz_unicode_code_point_is_defined(0x110000), "Not defined."); + mu_assert_false(rz_unicode_code_point_is_defined(0xFFFFFFFF), "Not defined."); + // Even offset in table + mu_assert_true(rz_unicode_code_point_is_defined(3010), "Defined."); + mu_assert_false(rz_unicode_code_point_is_defined(3011), "Not defined."); + mu_assert_false(rz_unicode_code_point_is_defined(3013), "Not defined."); + mu_assert_true(rz_unicode_code_point_is_defined(3014), "Defined."); + // Odd offset in table + mu_assert_true(rz_unicode_code_point_is_defined(3016), "Defined."); + mu_assert_false(rz_unicode_code_point_is_defined(3017), "Not defined."); + mu_assert_true(rz_unicode_code_point_is_defined(3018), "Defined."); + + mu_end; +} bool test_rz_utf16_valid(void) { const ut8 utf16be_one_byte[] = { 0x00 }; @@ -300,7 +415,7 @@ bool test_rz_utf16_valid(void) { const ut8 utf16be_ff[] = { 0x00, 0x00 }; const ut8 utf16be_EUR[] = { 0x20, 0xAC }; const ut8 utf16be_complex[] = { 0xD8, 0x01, 0xDC, 0x37 }; - const ut8 utf16be_A_A[] = { 0x00, 0x41, 0x00, 0x41 }; + const ut8 utf16be_A_A[] = { 0x00, 0x41, 0x00, 0x41 }; const ut8 utf16be_complex_EUR_A[] = { 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC, 0x00, 0x41 }; const ut8 utf16be_complex_A_EUR[] = { 0xD8, 0x01, 0xDC, 0x37, 0x00, 0x41, 0x20, 0xAC }; const ut8 utf16be_A_complex_EUR[] = { 0x00, 0x41, 0xD8, 0x01, 0xDC, 0x37, 0x20, 0xAC }; @@ -359,6 +474,11 @@ bool all_tests() { mu_run_test(test_rz_utf32_valid); mu_run_test(test_rz_utf16_valid); mu_run_test(test_rz_ebcdic_valid); + mu_run_test(test_rz_unicode_printable); + mu_run_test(test_rz_unicode_undefined); + mu_run_test(test_rz_unicode_surrogate); + mu_run_test(test_rz_unicode_private); + mu_run_test(test_rz_unicode_control); return tests_passed != tests_run; } From e0b38986406d60f987d05736adf6149266b491f3 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 08:51:45 -0500 Subject: [PATCH 146/157] Add ps option to print until the first non-printable code point. --- librz/core/cmd/cmd_print.c | 24 +-- librz/core/cmd_descs/cmd_descs.c | 7 +- librz/core/cmd_descs/cmd_print.yaml | 8 +- librz/include/rz_util/rz_unicode.h | 1 + librz/util/str.c | 8 +- test/db/cmd/cmd_ps | 2 +- test/db/cmd/cmd_search_z | 268 ++++++++++++++-------------- 7 files changed, 165 insertions(+), 153 deletions(-) diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 294137a510f..e47aca4bd18 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -2083,7 +2083,7 @@ static void core_print_raw_buffer(RzStrStringifyOpt *opt) { } } -static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, ut32 offset, RzOutputMode mode, RzStrEnc str_encoding) { +static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, bool stop_at_unprintable, ut32 offset, RzOutputMode mode, RzStrEnc str_encoding) { const ut8 *buffer = core->block + offset; const ut32 length = core->blocksize - offset; RzStrEnc encoding = str_encoding == RZ_STRING_ENC_SETTINGS ? core->bin->str_search_cfg.string_encoding : str_encoding; @@ -2099,7 +2099,7 @@ static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, ut opt.length = length; opt.encoding = encoding; opt.stop_at_nil = stop_at_nil; - opt.stop_at_unprintable = stop_at_nil; + opt.stop_at_unprintable = stop_at_unprintable; core_print_raw_buffer(&opt); break; case RZ_OUTPUT_MODE_JSON: @@ -2112,12 +2112,15 @@ static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, ut return RZ_CMD_STATUS_OK; } +// "ps" RZ_IPI RzCmdStatus rz_print_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { bool stop_at_nil = !strcmp(argv[2], "null"); + bool stop_at_unprintable = !strcmp(argv[2], "unprintable"); RzStrEnc enc = rz_str_enc_string_as_type(argv[1]); - return core_print_string_in_block(core, stop_at_nil, 0, mode, enc); + return core_print_string_in_block(core, stop_at_nil, stop_at_unprintable, 0, mode, enc); } +// "ps+" RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { ut32 bitness = (ut32)rz_config_get_i(core->config, "asm.bits"); bool big_endian = rz_config_get_b(core->config, "cfg.bigendian"); @@ -2147,17 +2150,18 @@ RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int ar rz_core_seek(core, new_offset, SEEK_SET); rz_core_block_read(core); - status = core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_SETTINGS); + status = core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_SETTINGS); rz_core_seek(core, old_offset, SEEK_SET); rz_core_block_read(core); } else { - status = core_print_string_in_block(core, true, 1, mode, RZ_STRING_ENC_SETTINGS); + status = core_print_string_in_block(core, true, false, 1, mode, RZ_STRING_ENC_SETTINGS); } return status; } +// "psb" RZ_IPI RzCmdStatus rz_print_strings_current_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { RzListIter *it = NULL; RzDetectedString *detected = NULL; @@ -2661,23 +2665,23 @@ RZ_API void rz_print_offset(RzPrint *p, ut64 off, int invert, int offseg, int of } RZ_IPI RzCmdStatus rz_print_utf8_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF8); + return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF8); } RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF16LE); + return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF16LE); } RZ_IPI RzCmdStatus rz_print_utf32le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF32LE); + return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF32LE); } RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF16BE); + return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF16BE); } RZ_IPI RzCmdStatus rz_print_utf32be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) { - return core_print_string_in_block(core, true, 0, mode, RZ_STRING_ENC_UTF32BE); + return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF32BE); } RZ_IPI RzCmdStatus rz_print_hexdump_annotated_handler(RzCore *core, int argc, const char **argv) { diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 00f47997888..52a5904a8b2 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -15924,8 +15924,9 @@ static const RzCmdDescHelp ps_help = { static const RzCmdDescDetailEntry print_string_Value_space_details_detail_entries[] = { { .text = "String length", .arg_str = NULL, .comment = "The string length depends on the block size. You need to change it via 'b ' if your string is too short." }, { .text = "encoding=settings", .arg_str = NULL, .comment = "Use encoding from 'str.encoding' option." }, - { .text = "delimeter=null", .arg_str = NULL, .comment = "String is NUL terminated." }, - { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (dons't stop at non-printable character)." }, + { .text = "delimeter=null", .arg_str = NULL, .comment = "Prints until first NUL code point. Non-printable characters are escaped." }, + { .text = "delimeter=unprintable", .arg_str = NULL, .comment = "Prints until the first non-printable code point. This includes '\\n', '\\t' etc." }, + { .text = "delimeter=block", .arg_str = NULL, .comment = "Print whole block as string (don't stop at non-printable or NUL character)." }, { 0 }, }; static const RzCmdDescDetail print_string_details[] = { @@ -15934,7 +15935,7 @@ static const RzCmdDescDetail print_string_details[] = { }; static const char *print_string_encoding_choices[] = { "settings", "guess", "ascii", "utf8", "utf16le", "utf32le", "utf16be", "utf32be", "ibm037", "ibm290", "ebcdices", "ebcdicuk", "ebcdicus", NULL }; -static const char *print_string_delimiter_choices[] = { "null", "block", NULL }; +static const char *print_string_delimiter_choices[] = { "null", "block", "unprintable", NULL }; static const RzCmdDescArg print_string_args[] = { { .name = "encoding", diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index c79f5a45cf1..6bc4fb53a88 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1123,7 +1123,7 @@ commands: - name: delimiter type: RZ_CMD_ARG_TYPE_CHOICES default_value: "null" - choices: ["null", "block"] + choices: ["null", "block", "unprintable"] details: - name: Value details entries: @@ -1132,9 +1132,11 @@ commands: - text: "encoding=settings" comment: "Use encoding from 'str.encoding' option." - text: "delimeter=null" - comment: "String is NUL terminated." + comment: "Prints until first NUL code point. Non-printable characters are escaped." + - text: "delimeter=unprintable" + comment: "Prints until the first non-printable code point. This includes '\\n', '\\t' etc." - text: "delimeter=block" - comment: "Print whole block as string (dons't stop at non-printable character)." + comment: "Print whole block as string (don't stop at non-printable or NUL character)." - name: ps+ summary: Print libc++ std::string (same-endian, ascii, zero-terminated) cname: print_string_as_libcpp_string diff --git a/librz/include/rz_util/rz_unicode.h b/librz/include/rz_util/rz_unicode.h index 45e584b5ba4..2528239fac2 100644 --- a/librz/include/rz_util/rz_unicode.h +++ b/librz/include/rz_util/rz_unicode.h @@ -4,6 +4,7 @@ #include #include "rz_str.h" +#define UNICODE_NUL 0 #define UNICODE_VERSION_MAJOR 16 #define UNICODE_VERSION_MINOR 0 #define UNICODE_VERSION_PATCH 0 diff --git a/librz/util/str.c b/librz/util/str.c index 02f1e42eefb..6ef89d48e21 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -4217,7 +4217,7 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU line_runes = 0; } continue; - } else if (code_point == '\0' && option->stop_at_nil) { + } else if (code_point == UNICODE_NUL && option->stop_at_nil) { break; } else if (code_point == '\n') { line_runes = 0; @@ -4267,11 +4267,13 @@ RZ_API RZ_OWN char *rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NU } else { if (code_point == '\\') { rz_strbuf_appendf(&sb, "\\\\"); - } else if ((code_point == '\n' && !option->escape_nl) || (rz_unicode_code_point_is_printable(code_point) && code_point >= ' ')) { + } else if ((code_point == '\n' && !option->escape_nl) || (rz_unicode_code_point_is_printable(code_point))) { char tmp[5] = { 0 }; rz_utf8_encode((ut8 *)tmp, code_point); rz_strbuf_appendf(&sb, "%s", tmp); - } else if (!option->stop_at_unprintable) { + } else if (option->stop_at_unprintable) { + break; + } else { ut8 tmp[4]; int n_enc = rz_utf8_encode((ut8 *)tmp, code_point); for (int j = 0; j < n_enc; ++j) { diff --git a/test/db/cmd/cmd_ps b/test/db/cmd/cmd_ps index f9f7fb815cb..7c357ae89a9 100644 --- a/test/db/cmd/cmd_ps +++ b/test/db/cmd/cmd_ps @@ -178,7 +178,7 @@ NAME=ps select encoding FILE=bins/cmd/search/string_encodings/Latin-Lipsum.ebcdic_es CMDS=< Date: Tue, 11 Feb 2025 10:01:44 -0500 Subject: [PATCH 147/157] Fix docs --- librz/core/cmd_descs/cmd_descs.c | 4 ++-- librz/core/cmd_descs/cmd_print.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 52a5904a8b2..a2de9795f74 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -16027,7 +16027,7 @@ static const RzCmdDescArg print_utf16be_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf16be_help = { - .summary = "Print buffer as a utf16be string (alias for 'ps utf16le null').", + .summary = "Print buffer as a utf16be string (alias for 'ps utf16be null').", .args = print_utf16be_args, }; @@ -16051,7 +16051,7 @@ static const RzCmdDescArg print_utf16le_args[] = { { 0 }, }; static const RzCmdDescHelp print_utf16le_help = { - .summary = "Print buffer as a utf16le string (alias for 'ps utf32le null').", + .summary = "Print buffer as a utf16le string (alias for 'ps utf16le null').", .args = print_utf16le_args, }; diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index 6bc4fb53a88..2cbdd8f44e7 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -1188,7 +1188,7 @@ commands: - RZ_OUTPUT_MODE_JSON args: [] - name: psm - summary: Print buffer as a utf16be string (alias for 'ps utf16le null'). + summary: Print buffer as a utf16be string (alias for 'ps utf16be null'). cname: print_utf16be modes: - RZ_OUTPUT_MODE_STANDARD @@ -1209,7 +1209,7 @@ commands: - RZ_OUTPUT_MODE_JSON args: [] - name: psw - summary: Print buffer as a utf16le string (alias for 'ps utf32le null'). + summary: Print buffer as a utf16le string (alias for 'ps utf16le null'). cname: print_utf16le modes: - RZ_OUTPUT_MODE_STANDARD From 004608e0ef804658bf4d22eb721cae2e27e33890 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 10:11:34 -0500 Subject: [PATCH 148/157] Fix some simple tests. --- test/db/analysis/arm | 2 +- test/db/cmd/cmd_flags | 2 +- test/db/cmd/err | 4 ++-- test/db/cmd/feat_cmdsubst | 8 ++++---- test/db/cmd/regexp | 8 ++++---- test/db/cmd/sidbug | 4 ++-- test/db/tools/rz_asm | 4 +--- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/test/db/analysis/arm b/test/db/analysis/arm index 3bc03d73344..ad2bf3ad85d 100644 --- a/test/db/analysis/arm +++ b/test/db/analysis/arm @@ -1068,7 +1068,7 @@ NAME=misaligned arm string xref FILE=bins/mach0/misaligned_data-iOS-armv7 CMDS=< Date: Tue, 11 Feb 2025 11:52:26 -0500 Subject: [PATCH 149/157] Check for legal decodes in rz_utf8_decode and add unit tests for it. --- librz/include/rz_util/rz_unicode.h | 15 ++++--- librz/include/rz_util/rz_utf8.h | 2 +- librz/util/unicode.c | 11 +++++ librz/util/utf8.c | 64 +++++++++++++++++++----------- test/unit/test_encodings.c | 50 +++++++++++++++++++++++ 5 files changed, 112 insertions(+), 30 deletions(-) diff --git a/librz/include/rz_util/rz_unicode.h b/librz/include/rz_util/rz_unicode.h index 2528239fac2..951258f52d3 100644 --- a/librz/include/rz_util/rz_unicode.h +++ b/librz/include/rz_util/rz_unicode.h @@ -4,11 +4,15 @@ #include #include "rz_str.h" -#define UNICODE_NUL 0 -#define UNICODE_VERSION_MAJOR 16 -#define UNICODE_VERSION_MINOR 0 -#define UNICODE_VERSION_PATCH 0 -#define UNICODE_LAST_CODE_POINT 0x10ffff +#define UNICODE_NUL 0 +#define UNICODE_VERSION_MAJOR 16 +#define UNICODE_VERSION_MINOR 0 +#define UNICODE_VERSION_PATCH 0 +#define UNICODE_FIRST_1BYTE_CODE_POINT 0x0 +#define UNICODE_FIRST_2BYTE_CODE_POINT 0x80 +#define UNICODE_FIRST_3BYTE_CODE_POINT 0x0800 +#define UNICODE_FIRST_4BYTE_CODE_POINT 0x010000 +#define UNICODE_LAST_CODE_POINT 0x10ffff struct rz_unicode_range_name_entry_t { ut32 from; @@ -29,6 +33,7 @@ typedef ut32 RzCodePoint; RZ_API bool rz_unicode_code_point_is_printable(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_defined(const RzCodePoint c); +RZ_API bool rz_unicode_code_point_is_legal_decode(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_control(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_surrogate(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_private(const RzCodePoint c); diff --git a/librz/include/rz_util/rz_utf8.h b/librz/include/rz_util/rz_utf8.h index 56d354579a5..0c95c5641ad 100644 --- a/librz/include/rz_util/rz_utf8.h +++ b/librz/include/rz_util/rz_utf8.h @@ -8,7 +8,7 @@ * \brief An Unicode code point. */ RZ_API int rz_utf8_encode(ut8 *ptr, const RzCodePoint ch); -RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); +RZ_API size_t rz_utf8_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NULLABLE RZ_OUT RzCodePoint *cp); RZ_API int rz_mutf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch); RZ_API int rz_utf8_encode_str(const RzCodePoint *str, ut8 *dst, const int dst_length); RZ_API int rz_utf8_size(const ut8 *ptr); diff --git a/librz/util/unicode.c b/librz/util/unicode.c index d02f58c043f..070173a6055 100644 --- a/librz/util/unicode.c +++ b/librz/util/unicode.c @@ -258,6 +258,17 @@ RZ_API bool rz_unicode_code_point_is_defined(const RzCodePoint c) { return !bin_search_range(c, undefined_ranges, RZ_ARRAY_SIZE(undefined_ranges)); } +/** + * \brief Returns true when the RzCodePoint is a defined Unicode code point and not a surrogate. + * + * \param c RzCodePoint value to test. + * + * \return True if the code point is defined and not a surrogate, false otherwise. + */ +RZ_API bool rz_unicode_code_point_is_legal_decode(const RzCodePoint c) { + return rz_unicode_code_point_is_defined(c) && !rz_unicode_code_point_is_surrogate(c); +} + /** * \brief Returns true when the RzCodePoint is a Unicode control code point. * diff --git a/librz/util/utf8.c b/librz/util/utf8.c index 81d9467c490..4c936918879 100644 --- a/librz/util/utf8.c +++ b/librz/util/utf8.c @@ -364,36 +364,52 @@ RZ_API const char *rz_utf_block_name(int idx) { return unicode_blocks[idx].name; } -/* Convert an UTF-8 buf into a unicode RzCodePoint */ -RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzCodePoint *ch) { - if (ptrlen < 1) { +/** + * \brief Decodes an UTF-8 encoded Unicode code point form the buffer \p buf + * + * \param buf The buffer to read from. + * \param The buffer length in bytes. + * \param cp The decoded code point. It is only written if a valid + * Unicode code point was decoded. + * + * \return The number of bytes decoded. Is always between 0-4. + */ +RZ_API size_t rz_utf8_decode(RZ_NONNULL const ut8 *buf, size_t buf_len, RZ_NULLABLE RZ_OUT RzCodePoint *cp) { + rz_return_val_if_fail(buf, 0); + if (buf_len < 1) { return 0; } - if (ptr[0] < 0x80) { - if (ch) { - *ch = (ut32)ptr[0]; - } - return 1; - } else if (ptrlen > 1 && (ptr[0] & 0xe0) == 0xc0 && (ptr[1] & 0xc0) == 0x80) { - RzCodePoint code_point = (ptr[0] & 0x1f) << 6 | (ptr[1] & 0x3f); - if (ch) { - *ch = code_point; + RzCodePoint code_point = UNICODE_LAST_CODE_POINT + 1; + size_t bytes_used = 0; + if (buf[0] < 0x80) { + code_point = (RzCodePoint)buf[0]; + bytes_used = 1; + } else if (buf_len > 1 && (buf[0] & 0xe0) == 0xc0 && (buf[1] & 0xc0) == 0x80) { + code_point = (buf[0] & 0x1f) << 6 | (buf[1] & 0x3f); + if (code_point < UNICODE_FIRST_2BYTE_CODE_POINT) { + return 0; } - return code_point < 0x80 ? 0 : 2; - } else if (ptrlen > 2 && (ptr[0] & 0xf0) == 0xe0 && (ptr[1] & 0xc0) == 0x80 && (ptr[2] & 0xc0) == 0x80) { - RzCodePoint code_point = (ptr[0] & 0xf) << 12 | (ptr[1] & 0x3f) << 6 | (ptr[2] & 0x3f); - if (ch) { - *ch = code_point; + bytes_used = 2; + } else if (buf_len > 2 && (buf[0] & 0xf0) == 0xe0 && (buf[1] & 0xc0) == 0x80 && (buf[2] & 0xc0) == 0x80) { + code_point = (buf[0] & 0xf) << 12 | (buf[1] & 0x3f) << 6 | (buf[2] & 0x3f); + if (code_point < UNICODE_FIRST_3BYTE_CODE_POINT) { + return 0; } - return code_point < 0x800 ? 0 : 3; - } else if (ptrlen > 3 && (ptr[0] & 0xf8) == 0xf0 && (ptr[1] & 0xc0) == 0x80 && (ptr[2] & 0xc0) == 0x80 && (ptr[3] & 0xc0) == 0x80) { - RzCodePoint code_point = (ptr[0] & 7) << 18 | (ptr[1] & 0x3f) << 12 | (ptr[2] & 0x3f) << 6 | (ptr[3] & 0x3f); - if (ch) { - *ch = code_point; + bytes_used = 3; + } else if (buf_len > 3 && (buf[0] & 0xf8) == 0xf0 && (buf[1] & 0xc0) == 0x80 && (buf[2] & 0xc0) == 0x80 && (buf[3] & 0xc0) == 0x80) { + code_point = (buf[0] & 7) << 18 | (buf[1] & 0x3f) << 12 | (buf[2] & 0x3f) << 6 | (buf[3] & 0x3f); + if (code_point < UNICODE_FIRST_4BYTE_CODE_POINT) { + return 0; } - return code_point > UNICODE_LAST_CODE_POINT ? 0 : 4; + bytes_used = 4; } - return 0; + if (code_point > UNICODE_LAST_CODE_POINT || !rz_unicode_code_point_is_legal_decode(code_point)) { + return 0; + } + if (cp) { + *cp = code_point; + } + return bytes_used; } /* Convert an MUTF-8 buf into a unicode RzCodePoint */ diff --git a/test/unit/test_encodings.c b/test/unit/test_encodings.c index 2cb9a225ba6..4f7bfd8c79d 100644 --- a/test/unit/test_encodings.c +++ b/test/unit/test_encodings.c @@ -8,6 +8,55 @@ #include #include +bool test_rz_utf8_decode(void) { + RzCodePoint codepoint = 0; + const ut8 utf8_1b_valid_first[] = { 0x00 }; + const ut8 utf8_1b_valid_last[] = { 0x7f }; + const ut8 utf8_2b_valid_first[] = { 0xC2, 0x80 }; + const ut8 utf8_2b_valid_last[] = { 0xDF, 0xBF }; + const ut8 utf8_3b_valid_first[] = { 0xE0, 0xA0, 0x80 }; + const ut8 utf8_3b_valid_last[] = { 0xEF, 0xBF, 0xBD }; + const ut8 utf8_4b_valid_first[] = { 0xF0, 0x90, 0x80, 0x80 }; + const ut8 utf8_4b_valid_last[] = { 0xF4, 0x8F, 0xBF, 0xBD }; + + mu_assert_eq(rz_utf8_decode(utf8_1b_valid_first, sizeof(utf8_1b_valid_first), &codepoint), 1, "Decode failed"); + mu_assert_eq(codepoint, 0, "Code point incorrect"); + mu_assert_eq(rz_utf8_decode(utf8_1b_valid_last, sizeof(utf8_1b_valid_last), &codepoint), 1, "Decode failed"); + mu_assert_eq(codepoint, 0x7f, "Code point incorrect"); + + mu_assert_eq(rz_utf8_decode(utf8_2b_valid_first, sizeof(utf8_2b_valid_first), &codepoint), 2, "Decode failed"); + mu_assert_eq(codepoint, 0x80, "Code point incorrect"); + mu_assert_eq(rz_utf8_decode(utf8_2b_valid_last, sizeof(utf8_2b_valid_last), &codepoint), 2, "Decode failed"); + mu_assert_eq(codepoint, 0x07FF, "Code point incorrect"); + + mu_assert_eq(rz_utf8_decode(utf8_3b_valid_first, sizeof(utf8_3b_valid_first), &codepoint), 3, "Decode failed"); + mu_assert_eq(codepoint, 0x800, "Code point incorrect"); + mu_assert_eq(rz_utf8_decode(utf8_3b_valid_last, sizeof(utf8_3b_valid_last), &codepoint), 3, "Decode failed"); + mu_assert_eq(codepoint, 0xFFFD, "Code point incorrect"); + + mu_assert_eq(rz_utf8_decode(utf8_4b_valid_first, sizeof(utf8_4b_valid_first), &codepoint), 4, "Decode failed"); + mu_assert_eq(codepoint, 0x10000, "Code point incorrect"); + mu_assert_eq(rz_utf8_decode(utf8_4b_valid_last, sizeof(utf8_4b_valid_last), &codepoint), 4, "Decode failed"); + mu_assert_eq(codepoint, 0x10FFFD, "Code point incorrect"); + + const ut8 utf8_1b_invalid_F[] = { 0xFF }; + const ut8 utf8_2b_invalid_F[] = { 0xFF, 0x00 }; + const ut8 utf8_3b_invalid_F[] = { 0xFF, 0x00, 0x00 }; + mu_assert_eq(rz_utf8_decode(utf8_1b_invalid_F, sizeof(utf8_1b_invalid_F), &codepoint), 0, "Invalid decode, prefix bit false."); + mu_assert_eq(rz_utf8_decode(utf8_2b_invalid_F, sizeof(utf8_2b_invalid_F), &codepoint), 0, "Invalid decode, prefix bit false."); + mu_assert_eq(rz_utf8_decode(utf8_3b_invalid_F, sizeof(utf8_3b_invalid_F), &codepoint), 0, "Invalid decode, prefix bit false."); + + const ut8 utf8_2b_invalid_small_code_point[] = { 0xC0, 0x80 }; + const ut8 utf8_3b_invalid_small_code_point[] = { 0xE0, 0x80, 0x80 }; + const ut8 utf8_4b_invalid_small_code_point[] = { 0xF0, 0x80, 0x80, 0x80 }; + + mu_assert_eq(rz_utf8_decode(utf8_2b_invalid_small_code_point, sizeof(utf8_2b_invalid_small_code_point), &codepoint), 0, "Invalid decode, code point is too small for encoding."); + mu_assert_eq(rz_utf8_decode(utf8_3b_invalid_small_code_point, sizeof(utf8_3b_invalid_small_code_point), &codepoint), 0, "Invalid decode, code point is too small for encoding."); + mu_assert_eq(rz_utf8_decode(utf8_4b_invalid_small_code_point, sizeof(utf8_4b_invalid_small_code_point), &codepoint), 0, "Invalid decode, code point is too small for encoding."); + + mu_end; +} + /** * \brief Examples partially taken from: https://en.wikipedia.org/wiki/UTF-16#Examples */ @@ -468,6 +517,7 @@ bool test_rz_utf16_valid(void) { } bool all_tests() { + mu_run_test(test_rz_utf8_decode); mu_run_test(test_rz_utf16_decode); mu_run_test(test_rz_utf16_encode); mu_run_test(test_rz_utf32_decode); From 5eb5da17fd281829bccb56da56b2693c6768726b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 13:54:58 -0500 Subject: [PATCH 150/157] Add Unicdoe Format tables. --- librz/include/rz_util/rz_unicode.h | 1 + librz/util/unicode.c | 45 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/librz/include/rz_util/rz_unicode.h b/librz/include/rz_util/rz_unicode.h index 951258f52d3..42b1436aca4 100644 --- a/librz/include/rz_util/rz_unicode.h +++ b/librz/include/rz_util/rz_unicode.h @@ -37,6 +37,7 @@ RZ_API bool rz_unicode_code_point_is_legal_decode(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_control(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_surrogate(const RzCodePoint c); RZ_API bool rz_unicode_code_point_is_private(const RzCodePoint c); +RZ_API bool rz_unicode_code_point_is_format(const RzCodePoint c); RZ_API RzStrEnc rz_unicode_bom_encoding(const ut8 *ptr, size_t ptrlen); #endif // RZ_UNICODE_H diff --git a/librz/util/unicode.c b/librz/util/unicode.c index 070173a6055..4fb98684c5f 100644 --- a/librz/util/unicode.c +++ b/librz/util/unicode.c @@ -45,6 +45,39 @@ const RzUnicodeRangeTable private_ranges = { { 1048576, 1114109 }, }; +/** + * \brief Unicode format ranges. + * + * Table generated with `ucd-generate general-category`. + * See: https://github.com/BurntSushi/ucd-generate + * + * Unicode version: 16.0.0. + */ +const RzUnicodeRangeTable format_ranges = { + { 173, 173 }, + { 1536, 1541 }, + { 1564, 1564 }, + { 1757, 1757 }, + { 1807, 1807 }, + { 2192, 2193 }, + { 2274, 2274 }, + { 6158, 6158 }, + { 8203, 8207 }, + { 8234, 8238 }, + { 8288, 8292 }, + { 8294, 8303 }, + { 65279, 65279 }, + { 65529, 65531 }, + { 69821, 69821 }, + { 69837, 69837 }, + { 78896, 78911 }, + { 113824, 113827 }, + { 119155, 119162 }, + { 917505, 917505 }, + { 917536, 917631 }, + +}; + /** * \brief Unicode undefined ranges. * @@ -303,6 +336,17 @@ RZ_API bool rz_unicode_code_point_is_private(const RzCodePoint c) { return bin_search_range(c, private_ranges, RZ_ARRAY_SIZE(private_ranges)); } +/** + * \brief Returns true when the RzCodePoint is a Unicode format code point. + * + * \param c RzCodePoint value to test. + * + * \return True if the code point is a format code point, false otherwise. + */ +RZ_API bool rz_unicode_code_point_is_format(const RzCodePoint c) { + return bin_search_range(c, format_ranges, RZ_ARRAY_SIZE(format_ranges)); +} + /** * \brief Returns true when the RzCodePoint is a printable symbol. * Printable means: @@ -326,6 +370,7 @@ RZ_API bool rz_unicode_code_point_is_printable(const RzCodePoint c) { return rz_unicode_code_point_is_defined(c) && !rz_unicode_code_point_is_control(c) && !rz_unicode_code_point_is_surrogate(c) && + !rz_unicode_code_point_is_format(c) && !rz_unicode_code_point_is_private(c); } From cff4a3a65c7681d2887afb45cee0db2ad5a0f24a Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 13:57:36 -0500 Subject: [PATCH 151/157] Fixup UTF string ecaping. It does several changes: - The UTF decode functions reliably return 0 for invalid decodings. This is now handled. - Unicode code points which are valid decodes are escaped as \Uhhhhhh. - Invalid decodes get escaped as bytes \xhh. --- librz/core/cbin.c | 12 +++--- librz/util/str.c | 73 ++++++++++++++-------------------- test/db/archos/linux-any/cmd_i | 10 ++--- 3 files changed, 42 insertions(+), 53 deletions(-) diff --git a/librz/core/cbin.c b/librz/core/cbin.c index 95a05212780..f25056e625e 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -2973,6 +2973,10 @@ RZ_API bool rz_core_file_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFil const char *filename = get_filename(info, desc); char *escaped = NULL; + RzStrEscOptions opt = { 0 }; + opt.show_asciidot = false; + opt.esc_bslash = false; + escaped = rz_str_escape_utf8_keep_printable(filename, &opt); rz_cmd_state_output_set_columnsf(state, "ss", "field", "value"); @@ -2982,11 +2986,12 @@ RZ_API bool rz_core_file_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFil case RZ_OUTPUT_MODE_JSON: pj_o(state->d.pj); const char *file_tag = "file"; - if (rz_str_is_utf8(filename)) { + if (strlen(filename) == strlen(escaped)) { pj_ks(state->d.pj, file_tag, filename); } else { pj_kr(state->d.pj, file_tag, (const ut8 *)filename, strlen(filename)); } + free(escaped); if (desc) { ut64 fsz = rz_io_desc_size(desc); pj_ki(state->d.pj, "fd", desc->fd); @@ -3018,10 +3023,7 @@ RZ_API bool rz_core_file_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFil if (desc) { rz_table_add_rowf(state->d.t, "sd", "fd", desc->fd); } - RzStrEscOptions opt = { 0 }; - opt.show_asciidot = false; - opt.esc_bslash = false; - escaped = rz_str_escape_utf8_keep_printable(filename, &opt); + rz_table_add_rowf(state->d.t, "ss", "file", escaped); free(escaped); if (desc) { diff --git a/librz/util/str.c b/librz/util/str.c index 6ef89d48e21..0a39ea30645 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -1520,11 +1520,13 @@ RZ_API char *rz_str_sanitize_sdb_key(const char *s) { } /** - * \brief Converts unprintable characters to C-like backslash representation + * \brief Converts unprintable characters to C-like backslash representation. * - * \param p pointer to the original string - * \param dst pointer where pointer to the resulting characters sequence is put - * \param opt pointer to encoding options structure + * NOTE: The \p dst pointer is incremented by 2 to 4. + * + * \param p pointer to the original string. + * \param dst pointer where pointer to the resulting characters sequence is put. + * \param opt pointer to encoding options structure. **/ RZ_API void rz_str_byte_escape(const char *p, char **dst, RzStrEscOptions *opt) { char *q = *dst; @@ -1693,7 +1695,7 @@ static char *rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool char *new_buf, *q; const char *p, *end; RzCodePoint ch; - int i, len, ch_bytes; + int len, ch_bytes; if (!buf) { return NULL; @@ -1720,14 +1722,15 @@ static char *rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool len = strlen(buf); end = buf + len; } - /* Worst case scenario, we convert every byte to \xhh */ - new_buf = malloc(1 + (len * 4)); + /* Worst case scenario, we convert every byte to a \Uhhhhhh */ + new_buf = malloc(1 + (len * 8)); if (!new_buf) { return NULL; } p = buf; q = new_buf; while (p < end) { + size_t min_char_width; switch (enc) { case RZ_STRING_ENC_UTF16LE: case RZ_STRING_ENC_UTF16BE: @@ -1735,55 +1738,39 @@ static char *rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool case RZ_STRING_ENC_UTF32BE: if (enc == RZ_STRING_ENC_UTF16LE || enc == RZ_STRING_ENC_UTF16BE) { ch_bytes = rz_utf16_decode((ut8 *)p, end - p, &ch, enc == RZ_STRING_ENC_UTF16BE); + min_char_width = 2; } else { ch_bytes = rz_utf32_decode((ut8 *)p, end - p, &ch, enc == RZ_STRING_ENC_UTF32BE); - } - if (ch_bytes == 0) { - p++; - continue; + min_char_width = 4; } break; default: ch_bytes = rz_utf8_decode((ut8 *)p, end - p, &ch); - if (ch_bytes == 0) { - ch_bytes = 1; - } + min_char_width = 1; } if (show_asciidot && !IS_PRINTABLE(ch)) { *q++ = '.'; - } else if (ch > ASCII_LAST_CODE_POINT) { - if (keep_printable) { - q += rz_utf8_encode((ut8 *)q, ch); + } else if (keep_printable && ch_bytes != 0 && rz_unicode_code_point_is_printable(ch)) { + q += rz_utf8_encode((ut8 *)q, ch); + } else { + if (ch_bytes > 0) { + // Valid code point, but it should be escaped. + rz_snprintf(q, 9, "\\U%06" PFMT32x, ch); + q += 8; } else { - *q++ = '\\'; - *q++ = ch_bytes == 4 ? 'U' : 'u'; - for (i = ch_bytes == 4 ? 6 : 2; i >= 0; i -= 2) { - *q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf]; - *q++ = "0123456789abcdef"[ch >> 4 * i & 0xf]; + RzStrEscOptions opt = { 0 }; + opt.dot_nl = false; + opt.show_asciidot = false; + opt.esc_bslash = esc_bslash; + opt.esc_double_quotes = esc_double_quotes; + // Invalid code point. Escape as minimal number of invalid bytes. + for (size_t i = 0; i < min_char_width && p + i < end; i++) { + rz_str_byte_escape(p + i, &q, &opt); + // q is incremented in rz_str_byte_escape } } - } else { - int offset = enc == RZ_STRING_ENC_UTF16BE ? 1 : enc == RZ_STRING_ENC_UTF32BE ? 3 - : 0; - RzStrEscOptions opt = { 0 }; - opt.dot_nl = false; - opt.show_asciidot = false; - opt.esc_bslash = esc_bslash; - opt.esc_double_quotes = esc_double_quotes; - rz_str_byte_escape(p + offset, &q, &opt); - } - switch (enc) { - case RZ_STRING_ENC_UTF16LE: - case RZ_STRING_ENC_UTF16BE: - p += ch_bytes < 2 ? 2 : ch_bytes; - break; - case RZ_STRING_ENC_UTF32LE: - case RZ_STRING_ENC_UTF32BE: - p += 4; - break; - default: - p += ch_bytes; } + p += ch_bytes < 1 ? min_char_width : ch_bytes; } *q = '\0'; return new_buf; diff --git a/test/db/archos/linux-any/cmd_i b/test/db/archos/linux-any/cmd_i index a2605417eb3..9f9e17b7a11 100644 --- a/test/db/archos/linux-any/cmd_i +++ b/test/db/archos/linux-any/cmd_i @@ -14,11 +14,11 @@ $size=%v 1 .(show_fname \xf0\x82\x82\xac\\.bin) EOF EXPECT=< Date: Tue, 11 Feb 2025 14:00:12 -0500 Subject: [PATCH 152/157] Fix test --- test/db/cmd/regexp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/db/cmd/regexp b/test/db/cmd/regexp index ec472e2e3f4..7995d0e55d5 100644 --- a/test/db/cmd/regexp +++ b/test/db/cmd/regexp @@ -111,11 +111,11 @@ ps ascii unprintable @ hit.string.ascii.0 ps ascii unprintable @ hit.string.ascii.1 echo ---- /z "b.*d$" r -ps ascii @ hit.string.ascii.0 +ps ascii unprintable @ hit.string.ascii.0 EOF EXPECT=< Date: Tue, 11 Feb 2025 14:34:29 -0500 Subject: [PATCH 153/157] Enforce an alignment of at least 1. --- librz/core/canalysis.c | 4 ++-- librz/core/cconfig.c | 2 +- librz/main/rz-find.c | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index 897f3a2a0da..516e5e841cd 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -4746,7 +4746,7 @@ RZ_IPI void rz_core_analysis_value_pointers(RzCore *core, RzOutputMode mode) { char *tmp = rz_str_dup(analysisin); bool is_debug = rz_config_get_b(core->config, "cfg.debug"); int archAlign = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN); - rz_config_set_i(core->config, "search.align", archAlign); + rz_config_set_i(core->config, "search.align", archAlign < 1 ? 1 : archAlign); rz_config_set(core->config, "analysis.in", "io.maps.x"); rz_core_notify_done(core, "Finding xrefs in noncode section with analysis.in=io.maps"); @@ -4821,7 +4821,7 @@ RZ_IPI void rz_core_analysis_value_pointers(RzCore *core, RzOutputMode mode) { // end rz_config_set(core->config, "analysis.in", tmp); free(tmp); - rz_config_set_i(core->config, "search.align", o_align); + rz_config_set_i(core->config, "search.align", o_align < 1 ? 1 : o_align); } RZ_API int rz_core_get_stacksz(RzCore *core, ut64 from, ut64 to) { diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 96681cdf63f..f5cea7a527c 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -2394,7 +2394,7 @@ static bool cb_searchalign(void *user, void *data) { RzCore *core = (RzCore *)user; RzConfigNode *node = (RzConfigNode *)data; if (rz_bits_count_ones_ut64(node->i_value) != 1) { - RZ_LOG_ERROR("Alignment is only defined for '>0' and 'n^2'.\n"); + RZ_LOG_ERROR("Alignment is only defined for '>0' and 'n^2'. Is = %" PFMT64d "\n", node->i_value); return false; } core->search->align = node->i_value; diff --git a/librz/main/rz-find.c b/librz/main/rz-find.c index 79dcd0d44b4..5acfbdb8a0e 100644 --- a/librz/main/rz-find.c +++ b/librz/main/rz-find.c @@ -411,7 +411,7 @@ static int rzfind_open_file(RzfindOptions *ro, const char *file, const ut8 *data " -e search.align=%d" " -e search.from=%" PFMT64d " %s -qnc/m%s \"%s\"", - ro->align, ro->from, tostr, ro->json ? "j" : "", efile); + ro->align < 1 ? 1 : ro->align, ro->from, tostr, ro->json ? "j" : "", efile); free(tostr); goto done; } @@ -530,6 +530,10 @@ RZ_API int rz_main_rz_find(int argc, const char **argv) { switch (c) { case 'a': ro.align = rz_num_math(NULL, opt.arg); + if (rz_bits_count_ones_ut64(ro.align) != 1) { + RZ_LOG_ERROR("Alignment must only have one bit set.\n"); + return 1; + } break; case 'r': ro.rad = true; From 3a7aceb57719a381ad12c9f865d65eefe4d52b3b Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 14:50:10 -0500 Subject: [PATCH 154/157] Keep printable characters for symbol names. --- librz/core/cbin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librz/core/cbin.c b/librz/core/cbin.c index f25056e625e..00e081d9574 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -1390,7 +1390,7 @@ RZ_API void rz_core_sym_name_init(RZ_NONNULL RZ_OUT RzBinSymNames *names, RZ_NON .esc_double_quotes = false, .dot_nl = false, }; - names->symbolname = rz_str_escape_utf8(demangle && names->demname ? names->demname : names->name, &opt); + names->symbolname = rz_str_escape_utf8_keep_printable(demangle && names->demname ? names->demname : names->name, &opt); } /** From 954578034768cbdac432d8ad176a15401b653816 Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 14:50:38 -0500 Subject: [PATCH 155/157] Fix easy tests --- test/db/cmd/cmd_psj | 2 +- test/db/cmd/hex | 2 +- test/db/cmd/print | 4 ++-- test/db/cmd/va | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/db/cmd/cmd_psj b/test/db/cmd/cmd_psj index a4223ea5a07..42a464d7ea0 100644 --- a/test/db/cmd/cmd_psj +++ b/test/db/cmd/cmd_psj @@ -38,7 +38,7 @@ wz "...\"..����..." psj @!13 @e:str.encoding=utf8 EOF EXPECT=< Date: Tue, 11 Feb 2025 14:57:39 -0500 Subject: [PATCH 156/157] Add option to escape strings and keep printable and do so for disassembly. --- librz/core/disasm.c | 1 + librz/include/rz_util/rz_str.h | 1 + librz/util/str.c | 10 +++++----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/librz/core/disasm.c b/librz/core/disasm.c index ee2b5d0fc07..aa3f2e4a575 100644 --- a/librz/core/disasm.c +++ b/librz/core/disasm.c @@ -3750,6 +3750,7 @@ static char *ds_esc_str(RzDisasmState *ds, const char *str, int len, const char opt.show_asciidot = ds->show_asciidot; opt.esc_double_quotes = true; opt.esc_bslash = ds->core->print->esc_bslash; + opt.keep_printable = true; switch (strenc) { case RZ_STRING_ENC_8BIT: escstr = rz_str_escape_8bit(str, is_comment, &opt); diff --git a/librz/include/rz_util/rz_str.h b/librz/include/rz_util/rz_str.h index 141cd36160f..1b171d77026 100644 --- a/librz/include/rz_util/rz_str.h +++ b/librz/include/rz_util/rz_str.h @@ -44,6 +44,7 @@ typedef struct { bool esc_bslash; ///< When true, backslashes `\` are quoted with `\\` bool esc_double_quotes; ///< When true, double quotes `"` are quoted with `\"` bool dot_nl; ///< When true, \n is converted into the graphiz-compatible newline \l + bool keep_printable; ///< Keep all printable characters (excludes \n, \t etc.). } RzStrEscOptions; /** diff --git a/librz/util/str.c b/librz/util/str.c index 0a39ea30645..698f008728b 100644 --- a/librz/util/str.c +++ b/librz/util/str.c @@ -1777,7 +1777,7 @@ static char *rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool } RZ_API char *rz_str_escape_utf8(const char *buf, RzStrEscOptions *opt) { - return rz_str_escape_utf(buf, -1, RZ_STRING_ENC_UTF8, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, false); + return rz_str_escape_utf(buf, -1, RZ_STRING_ENC_UTF8, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, opt->keep_printable); } RZ_API char *rz_str_escape_utf8_keep_printable(const char *buf, RzStrEscOptions *opt) { @@ -1785,19 +1785,19 @@ RZ_API char *rz_str_escape_utf8_keep_printable(const char *buf, RzStrEscOptions } RZ_API char *rz_str_escape_utf16le(const char *buf, int buf_size, RzStrEscOptions *opt) { - return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF16LE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, false); + return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF16LE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, opt->keep_printable); } RZ_API char *rz_str_escape_utf32le(const char *buf, int buf_size, RzStrEscOptions *opt) { - return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF32LE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, false); + return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF32LE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, opt->keep_printable); } RZ_API char *rz_str_escape_utf16be(const char *buf, int buf_size, RzStrEscOptions *opt) { - return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF16BE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, false); + return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF16BE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, opt->keep_printable); } RZ_API char *rz_str_escape_utf32be(const char *buf, int buf_size, RzStrEscOptions *opt) { - return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF32BE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, false); + return rz_str_escape_utf(buf, buf_size, RZ_STRING_ENC_UTF32BE, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, opt->keep_printable); } static char *escape_utf8_for_json(const char *buf, int buf_size, bool mutf8) { From 6a94be986cd0c6e4f280b4745d934b00310fbe2a Mon Sep 17 00:00:00 2001 From: Rot127 Date: Tue, 11 Feb 2025 15:38:27 -0500 Subject: [PATCH 157/157] Fix alignment checks (default is now 1). --- librz/arch/analysis.c | 2 +- librz/arch/asm.c | 2 +- librz/arch/xrefs.c | 3 +++ librz/bin/format/mach0/fatmach0.c | 1 + librz/core/canalysis.c | 32 ++++++++++++++++--------------- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/librz/arch/analysis.c b/librz/arch/analysis.c index 70dda618a62..3c97b3b9f59 100644 --- a/librz/arch/analysis.c +++ b/librz/arch/analysis.c @@ -338,7 +338,7 @@ RZ_API bool rz_analysis_set_bits(RzAnalysis *analysis, int bits) { bool is_hack = is_arm_thumb_hack(analysis, bits); analysis->bits = bits; int v = rz_analysis_archinfo(analysis, RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN); - analysis->pcalign = RZ_MAX(0, v); + analysis->pcalign = RZ_MAX(1, v); rz_type_db_set_bits(analysis->typedb, bits); rz_type_db_set_address_bits(analysis->typedb, rz_analysis_get_address_bits(analysis)); if (!is_hack) { diff --git a/librz/arch/asm.c b/librz/arch/asm.c index 43f5728feb7..fa7c04f3bb7 100644 --- a/librz/arch/asm.c +++ b/librz/arch/asm.c @@ -874,7 +874,7 @@ RZ_API RzAsmCode *rz_asm_massemble(RzAsm *a, const char *assembly) { return rz_asm_code_free(acode); } lbuf = rz_str_dup(assembly); - acode->code_align = 0; + acode->code_align = 1; /* consider ,, an alias for a newline */ lbuf = rz_str_replace(lbuf, ",,", "\n", true); diff --git a/librz/arch/xrefs.c b/librz/arch/xrefs.c index c6a008a7004..3fc30a7f288 100644 --- a/librz/arch/xrefs.c +++ b/librz/arch/xrefs.c @@ -106,6 +106,9 @@ static bool set_xref(HtUP *m, RzAnalysisXRef *xref, bool from2to) { // Set a cross reference from FROM to TO. RZ_API bool rz_analysis_xrefs_set(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type) { + if (type == RZ_ANALYSIS_XREF_TYPE_NULL && (from == 0x8000033c || to == 0x8000033c)) { + printf("ASDASDASD\n"); + } if (!analysis || from == to) { return false; } diff --git a/librz/bin/format/mach0/fatmach0.c b/librz/bin/format/mach0/fatmach0.c index 135fadb7b24..7a6a1735d13 100644 --- a/librz/bin/format/mach0/fatmach0.c +++ b/librz/bin/format/mach0/fatmach0.c @@ -46,6 +46,7 @@ static int rz_bin_fatmach0_init(struct rz_bin_fatmach0_obj_t *bin) { bin->archs[i].offset = rz_read_be32(&archbytes[8]); bin->archs[i].size = rz_read_be32(&archbytes[12]); bin->archs[i].align = rz_read_be32(&archbytes[16]); + bin->archs[i].align = bin->archs[i].align < 1 ? 1 : bin->archs[i].align; } return true; } diff --git a/librz/core/canalysis.c b/librz/core/canalysis.c index 516e5e841cd..e87f8cc56b5 100644 --- a/librz/core/canalysis.c +++ b/librz/core/canalysis.c @@ -2949,6 +2949,10 @@ RZ_IPI void rz_core_add_string_ref(RzCore *core, ut64 xref_from, ut64 xref_to) { } } +static inline bool aligns(ut64 addr, size_t align) { + return align > 1 && addr % align == 0; +} + RZ_API int rz_core_search_value_in_range(RzCore *core, RzInterval search_itv, ut64 vmin, ut64 vmax, int vsize, inRangeCb cb, void *cb_user) { int i, align = core->search->align, hitctr = 0; @@ -2966,7 +2970,7 @@ RZ_API int rz_core_search_value_in_range(RzCore *core, RzInterval search_itv, ut return -1; } bool maybeThumb = false; - if (align && core->analysis->cur && core->analysis->cur->arch) { + if (align > 1 && core->analysis->cur && core->analysis->cur->arch) { if (!strcmp(core->analysis->cur->arch, "arm") && core->analysis->bits != 64) { maybeThumb = true; } @@ -3013,7 +3017,7 @@ RZ_API int rz_core_search_value_in_range(RzCore *core, RzInterval search_itv, ut if (rz_cons_is_breaked()) { goto beach; } - if (align && (addr) % align) { + if (!aligns(addr, align)) { continue; } int match = false; @@ -3059,7 +3063,7 @@ RZ_API int rz_core_search_value_in_range(RzCore *core, RzInterval search_itv, ut } if (match && value) { bool isValidMatch = true; - if (align && (value % align)) { + if (!aligns(value, align)) { // ignored .. unless we are analyzing arm/thumb and lower bit is 1 isValidMatch = false; if (maybeThumb && (value & 1)) { @@ -4704,20 +4708,18 @@ static void _CbInRangeAav(RzCore *core, ut64 from, ut64 to, int vsize, void *use int arch_align = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN); bool vinfun = rz_config_get_b(core->config, "analysis.vinfun"); int searchAlign = rz_config_get_i(core->config, "search.align"); - int align = (searchAlign > 0) ? searchAlign : arch_align; - if (align > 1) { - if ((from % align) || (to % align)) { - bool itsFine = false; - if (archIsThumbable(core)) { - if ((from & 1) || (to & 1)) { - itsFine = true; - } + int align = (searchAlign > 1) ? searchAlign : arch_align; + if (!aligns(from, align) || !aligns(to, align)) { + bool itsFine = false; + if (archIsThumbable(core)) { + if ((from & 1) || (to & 1)) { + itsFine = true; } - if (!itsFine) { - return; - } - RZ_LOG_DEBUG("Warning: aav: false positive in 0x%08" PFMT64x "\n", from); } + if (!itsFine) { + return; + } + RZ_LOG_DEBUG("Warning: aav: false positive in 0x%08" PFMT64x "\n", from); } if (!vinfun) { RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, from, -1);