Skip to content

Commit

Permalink
Unfinished reimplementation of /x.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rot127 committed Dec 12, 2024
1 parent 098c69f commit b59292d
Show file tree
Hide file tree
Showing 17 changed files with 822 additions and 198 deletions.
32 changes: 22 additions & 10 deletions librz/core/cconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -3757,14 +3767,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETOPTIONS(n, "auto", "rosections", "raw", NULL);

/* 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");
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");
SETI("search.to", UT64_MAX, "Search end address");
n = NODECB("search.in", "io.maps", &cb_search_in);
Expand All @@ -3776,10 +3779,19 @@ 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.");

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");
SETBPREF("search.flags", "true", "All search results are flagged, otherwise only printed");
SETBPREF("search.overlap", "false", "Look for overlapped search hits");
SETICB("search.kwidx", 0, &cb_search_kwidx, "Store last search index count");
SETBPREF("search.show", "true", "Show search results");
SETI("search.to", -1, "Search end address");
n = NODECB("search.case_sensitive", "smart", &cb_search_case_sensitive);
SETDESC(n, "Set grep(~) as case smart/sensitive/insensitive");
SETOPTIONS(n, "smart", "sensitive", "insensitive", NULL);
Expand Down
149 changes: 147 additions & 2 deletions librz/core/cmd/cmd_search.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
#include <rz_core.h>
#include <rz_io.h>
#include <rz_list.h>
#include <rz_search.h>
#include <rz_types_base.h>
#include "../core_private.h"

#include "cmd_search_rop.c"
#include <rz_util/rz_assert.h>
#include <rz_vector.h>

#define AES_SEARCH_LENGTH 40
#define PRIVATE_KEY_SEARCH_LENGTH 11
Expand Down Expand Up @@ -1724,7 +1727,119 @@ 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; \
} \
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"))); \
core->in_search = true;

#define CMD_SEARCH_END() \
do { \
rz_search_opt_free(search_opts); \
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 false;
}

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) {
Expand Down Expand Up @@ -1803,7 +1918,37 @@ 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_inverse_match(search_opts, false);
opt_applid &= rz_search_opt_set_buffer_size(search_opts, RZ_MAX(pattern->length, RZ_SEARCH_MIN_BUFFER_SIZE));
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"
Expand Down
9 changes: 5 additions & 4 deletions librz/core/cmd_descs/cmd_descs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1695,9 +1695,10 @@ 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: '<mask>:<resulting bytes>'", .arg_str = NULL, .comment = "/x ff43:ffd0" },
{ .text = "Hexadecimal search of the bytes with bytes mask and wildcard. Pattern: '<mask>:<resulting bytes>'.", .arg_str = NULL, .comment = "/x ff43:f..0" },
{ 0 },
};
static const RzCmdDescDetail cmd_search_hex_details[] = {
Expand All @@ -1706,7 +1707,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,

Expand Down
13 changes: 7 additions & 6 deletions librz/core/cmd_descs/cmd_search.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -301,18 +301,19 @@ 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"
- 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: '<mask>:<resulting bytes>'"
comment: "/x ff43:ffd0"

- text: "Hexadecimal search of the bytes with bytes mask and wildcard. Pattern: '<mask>:<resulting bytes>'."
comment: "/x ff43:f..0"
- name: "/z"
summary: String search.
subcommands:
Expand Down
Loading

0 comments on commit b59292d

Please sign in to comment.