Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 3871 configure bin hashes #3951

Merged
merged 12 commits into from
Nov 5, 2023
68 changes: 36 additions & 32 deletions librz/bin/bfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ static ut64 buf_compute_hashes(const ut8 *buf, ut64 size, void *user) {
}

/**
* Return a pvector of RzBinFileHash structures with the hashes md5, sha1, sha256, crc32 and entropy
* Return a pvector of RzBinFileHash structures with the hashes configured in bin.hashes.default
* computed over the whole \p bf .
*/
RZ_API RZ_OWN RzPVector /*<RzBinFileHash *>*/ *rz_bin_file_compute_hashes(RzBin *bin, RzBinFile *bf, ut64 limit) {
Expand Down Expand Up @@ -426,43 +426,47 @@ RZ_API RZ_OWN RzPVector /*<RzBinFileHash *>*/ *rz_bin_file_compute_hashes(RzBin
if (!md) {
goto rz_bin_file_compute_hashes_bad;
}
RzListIter *hash_algos_iter = bin->default_hashes ? rz_list_iterator(bin->default_hashes) : NULL;

if (!rz_hash_cfg_configure(md, "md5") ||
!rz_hash_cfg_configure(md, "sha1") ||
!rz_hash_cfg_configure(md, "sha256") ||
!rz_hash_cfg_configure(md, "crc32") ||
!rz_hash_cfg_configure(md, "entropy")) {
goto rz_bin_file_compute_hashes_bad;
}
if (!rz_hash_cfg_init(md)) {
goto rz_bin_file_compute_hashes_bad;
}
if (hash_algos_iter) {
wargio marked this conversation as resolved.
Show resolved Hide resolved
while (hash_algos_iter) {
char *algo = rz_list_iter_get(hash_algos_iter);
if (!rz_hash_cfg_configure(md, algo)) {
goto rz_bin_file_compute_hashes_bad;
}
}

if (rz_buf_fwd_scan(buf, 0, buf_size, buf_compute_hashes, md) != buf_size) {
goto rz_bin_file_compute_hashes_bad;
}
if (!rz_hash_cfg_init(md)) {
goto rz_bin_file_compute_hashes_bad;
}

if (!rz_hash_cfg_final(md)) {
goto rz_bin_file_compute_hashes_bad;
}
if (rz_buf_fwd_scan(buf, 0, buf_size, buf_compute_hashes, md) != buf_size) {
goto rz_bin_file_compute_hashes_bad;
}

if (!add_file_hash(md, "md5", file_hashes) ||
!add_file_hash(md, "sha1", file_hashes) ||
!add_file_hash(md, "sha256", file_hashes) ||
!add_file_hash(md, "crc32", file_hashes) ||
!add_file_hash(md, "entropy", file_hashes)) {
goto rz_bin_file_compute_hashes_bad;
}
if (!rz_hash_cfg_final(md)) {
goto rz_bin_file_compute_hashes_bad;
}

if (o->plugin && o->plugin->hashes) {
RzPVector *plugin_hashes = o->plugin->hashes(bf);
void **it;
rz_pvector_foreach (plugin_hashes, it) {
RzBinFileHash *h = *it;
rz_pvector_push(file_hashes, h);
hash_algos_iter = rz_list_iterator(bin->default_hashes);

while (hash_algos_iter) {
char *algo = rz_list_iter_get(hash_algos_iter);
if (!add_file_hash(md, algo, file_hashes)) {
goto rz_bin_file_compute_hashes_bad;
}
}

if (o->plugin && o->plugin->hashes) {
RzPVector *plugin_hashes = o->plugin->hashes(bf);
void **it;
rz_pvector_foreach (plugin_hashes, it) {
RzBinFileHash *h = *it;
rz_pvector_push(file_hashes, h);
}
plugin_hashes->v.free = NULL;
rz_pvector_free(plugin_hashes);
}
plugin_hashes->v.free = NULL;
rz_pvector_free(plugin_hashes);
}

// TODO: add here more rows
Expand Down
66 changes: 66 additions & 0 deletions librz/core/cconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -2450,6 +2450,68 @@ static bool cb_binverbose(void *user, void *data) {
return true;
}

static bool cb_binhashesdefault(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
if (*node->value == '?') {
print_node_options(node);
rz_cons_printf("Multiple algorithms can be specified in a comma-separated list (no spaces).\n");
return false;
}

char *algos[] = {
"md5",
"sha1",
"sha256",
"crc32",
"crc64",
"entropy",
"blake3",
"sm3",
};

free(core->bin->default_hashes);
if (*node->value) {
char *delim = ",";
char *value = strdup(node->value);
if (!value) {
rz_sys_perror("strdup");
return false;
}
RzList *algo_list = rz_list_newf((RzListFree)free);
char *token = strtok(value, delim);
while (token) {
for (int i = 0; i < RZ_ARRAY_SIZE(algos); i++) {
if (algos[i] != NULL && !strcmp(token, algos[i])) {
char *hash = strdup(algos[i]);
if (hash) {
rz_list_append(algo_list, hash);
} else {
rz_sys_perror("strdup");
rz_list_free(algo_list);
free(value);
return false;
}
algos[i] = NULL;
break;
} else if (i == RZ_ARRAY_SIZE(algos) - 1) {
RZ_LOG_ERROR("core: bin.hashes.default: invalid or duplicate value: %s\n", node->value);
rz_list_free(algo_list);
free(value);
return false;
}
}
token = strtok(NULL, delim);
}
free(value);
core->bin->default_hashes = algo_list;
return true;
} else {
core->bin->default_hashes = NULL;
return true;
}
wargio marked this conversation as resolved.
Show resolved Hide resolved
}

static bool cb_debase64(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
Expand Down Expand Up @@ -3245,6 +3307,10 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETCB("bin.debase64", "false", &cb_debase64, "Try to debase64 all strings");
SETBPREF("bin.classes", "true", "Load classes from rbin on startup");
SETCB("bin.verbose", "false", &cb_binverbose, "Show RzBin warnings when loading binaries");
SETCB("bin.hashes.default", "md5,sha1,sha256,crc32,entropy", &cb_binhashesdefault, "Select hash algorithms");
n = NODECB("bin.hashes.default", "md5,sha1,sha256,crc32,entropy", &cb_binhashesdefault);
SETDESC(n, "Select hashing algorithms");
SETOPTIONS(n, "md5", "sha1", "sha256", "crc32", "entropy", "blake3", "sm3", NULL);
wargio marked this conversation as resolved.
Show resolved Hide resolved

/* prj */
SETPREF("prj.file", "", "Path of the currently opened project");
Expand Down
31 changes: 20 additions & 11 deletions librz/core/cmd/cmd_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -622,10 +622,16 @@ RZ_IPI RzCmdStatus rz_cmd_info_hashes_handler(RzCore *core, int argc, const char
GET_CHECK_CUR_BINFILE(core);

RzPVector *new_hashes = rz_bin_file_compute_hashes(core->bin, bf, limit);
if (!new_hashes) {
RZ_LOG_ERROR("core: Computing file hashes failed\n")
return RZ_CMD_STATUS_ERROR;
}
RzPVector *old_hashes = rz_bin_file_set_hashes(core->bin, new_hashes);
bool equal = true;
bool equal = false;
if (new_hashes && old_hashes && !rz_pvector_empty(new_hashes) && !rz_pvector_empty(old_hashes)) {
if (!is_equal_file_hashes(new_hashes, old_hashes, &equal)) {
if (is_equal_file_hashes(new_hashes, old_hashes, &equal)) {
equal = true;
} else {
RZ_LOG_ERROR("core: Cannot compare file hashes\n");
rz_pvector_free(old_hashes);
return RZ_CMD_STATUS_ERROR;
Expand Down Expand Up @@ -653,20 +659,23 @@ RZ_IPI RzCmdStatus rz_cmd_info_hashes_handler(RzCore *core, int argc, const char
break;
case RZ_OUTPUT_MODE_STANDARD:
if (!equal) {
size_t min_len = RZ_MIN(rz_pvector_len(old_hashes), rz_pvector_len(new_hashes));
for (int i = 0; i < min_len; i++) {
fh_new = (RzBinFileHash *)rz_pvector_at(new_hashes, i);
fh_old = (RzBinFileHash *)rz_pvector_at(old_hashes, i);
if (strcmp(fh_new->type, fh_old->type)) {
size_t max_len = RZ_MAX(rz_pvector_len(old_hashes), rz_pvector_len(new_hashes));
for (int i = 0; i < max_len; i++) {
fh_new = i < rz_pvector_len(new_hashes) ? (RzBinFileHash *)rz_pvector_at(new_hashes, i) : NULL;
fh_old = i < rz_pvector_len(old_hashes) ? (RzBinFileHash *)rz_pvector_at(old_hashes, i) : NULL;
if (fh_new && fh_old && strcmp(fh_new->type, fh_old->type)) {
RZ_LOG_ERROR("core: Wrong file hashes structure");
}
if (!strcmp(fh_new->hex, fh_old->hex)) {
if (fh_new && fh_old && !strcmp(fh_new->hex, fh_old->hex)) {
fprintf(stderr, "= %s %s\n", fh_new->type, fh_new->hex); // output one line because hash remains same `= hashtype hashval`
} else {
// output diff-like two lines, one with old hash val `- hashtype hashval` and one with new `+ hashtype hashval`
fprintf(stderr, "- %s %s\n+ %s %s\n",
fh_old->type, fh_old->hex,
fh_new->type, fh_new->hex);
if (fh_old) {
fprintf(stderr, "- %s %s\n", fh_old->type, fh_old->hex);
}
if (fh_new) {
fprintf(stderr, "+ %s %s\n", fh_new->type, fh_new->hex);
}
}
}
} else { // hashes are equal
Expand Down
4 changes: 2 additions & 2 deletions librz/hash/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ RZ_API void rz_hash_cfg_free(RZ_NONNULL RzHashCfg *md) {
/**
* \brief Allocates and configures the plugin message digest context
*
* message digest allocates internally a HashCfgConfig which
* contains all the needed informations to the plugin to work.
* message digest internally allocates a HashCfgConfig which
* contains all the information needed for the plugin to work.
* */
RZ_API bool rz_hash_cfg_configure(RZ_NONNULL RzHashCfg *md, RZ_NONNULL const char *name) {
rz_return_val_if_fail(md && name, false);
Expand Down
1 change: 1 addition & 0 deletions librz/include/rz_bin.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ struct rz_bin_t {
bool is_reloc_patched; // used to indicate whether relocations were patched or not
RzDemangler *demangler;
RzHash *hash;
RzList /*<char *>*/ *default_hashes; // bin.hashes.default
};

typedef struct rz_bin_xtr_metadata_t {
Expand Down
16 changes: 15 additions & 1 deletion test/db/cmd/cmd_i
Original file line number Diff line number Diff line change
Expand Up @@ -4637,7 +4637,7 @@ EXPECT_ERR=<<EOF
EOF
RUN

NAME=it2
NAME=iT2
FILE=--
CMDS=<<EOF
mkdir .tmp
Expand Down Expand Up @@ -4671,6 +4671,20 @@ entropy 2.959094
EOF
RUN

NAME=iT3
FILE==
CMDS=iT; e bin.hashes.default=sm3,sha1; iT
EXPECT=<<EOF
md5 bf619eac0cdf3f68d496ea9344137e8b
sha1 5c3eb80066420002bc3dcc7ca4ab6efad7ed4ae5
sha256 076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560
crc32 b2aa7578
entropy 0.000000
sm3 8b63e00c479bc948f58d360e3831bc32e3924fa25d126a221ec9ad7fc6223462
sha1 5c3eb80066420002bc3dcc7ca4ab6efad7ed4ae5
EOF
RUN

NAME=isq. (malloc)
FILE=malloc://512
CMDS=isq.
Expand Down
2 changes: 2 additions & 0 deletions test/integration/test_bin.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

bool test_rz_bin(void) {
RzBin *bin = rz_bin_new();
const char* default_algos[] = {"md5", "sha1", "sha256", "crc32", "entropy"};
bin->default_hashes = rz_list_new_from_array(default_algos, sizeof(default_algos)/sizeof(default_algos[0]));
wargio marked this conversation as resolved.
Show resolved Hide resolved
RzIO *io = rz_io_new();
rz_io_bind(io, &bin->iob);

Expand Down
Loading