rizin/librz/main/rz-sign.c

220 lines
5.9 KiB
C

// SPDX-FileCopyrightText: 2021 RizinOrg <info@rizin.re>
// SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_main.h>
#include <rz_core.h>
enum rz_sign_option {
RZ_SIGN_OPT_NONE = 0,
RZ_SIGN_OPT_CONVERT_FLIRT,
RZ_SIGN_OPT_CREATE_FLIRT,
RZ_SIGN_OPT_DUMP_FLIRT,
};
static void rz_sign_show_help(void) {
printf("%s%s%s", Color_CYAN, "Usage: ", Color_RESET);
printf("rz-sign [-aqv] [-e k=v] (-c pat sig | -o sig bin | -d sig)\n");
const char *options[] = {
// clang-format off
"-h", "", "Show this help",
"-a, -aa", "", "Add extra 'a' to analysis command (available only with -o option)",
"-e", "k=v", "Set an evaluable config variable (available only with -o option)",
"-c", "output.pat input.sig", "Parse a FLIRT signature and convert it to its other format",
"-o", "output.sig input.bin", "Perform an analysis on the binary and generate the FLIRT signature",
"-d", "flirt.sig", "Parse a FLIRT signature and dump its content",
"-q", "", "Quiet mode",
"-v", "", "Show version information",
// clang-format on
};
rz_print_colored_help(options, RZ_ARRAY_SIZE(options), false);
printf("Examples:\n"
" rz-sign -d signature.sig\n"
" rz-sign -c new_signature.pat old_signature.sig\n"
" rz-sign -o libc.sig libc.so.6\n");
}
static void perform_analysis(RzCore *core, size_t complexity) {
const char *cmd = NULL;
switch (complexity) {
case 0: cmd = "aa"; break;
case 1: cmd = "aaa"; break;
default: cmd = "aaaa"; break;
}
rz_core_cmd0(core, cmd);
}
RZ_API int rz_main_rz_sign(int argc, const char **argv) {
RzListIter *it;
const char *input_file = NULL;
const char *output_file = NULL;
char *config = NULL;
RzCore *core = NULL;
RzList *evars = NULL;
bool quiet = false;
RzGetopt opt;
int ret = 0;
ut32 n_nodes = 0;
int c, option = RZ_SIGN_OPT_NONE;
size_t complexity = 0;
evars = rz_list_newf(free);
if (!evars) {
RZ_LOG_ERROR("rz-sign: cannot allocate RzList\n");
return -1;
}
rz_getopt_init(&opt, argc, argv, "aqhdc:o:e:v");
while ((c = rz_getopt_next(&opt)) != -1) {
switch (c) {
case 'a':
complexity++;
break;
case 'c':
if (option != RZ_SIGN_OPT_NONE) {
RZ_LOG_ERROR("rz-sign: cannot combine option -%c with previous options\n", c);
ret = -1;
goto rz_sign_end;
}
option = RZ_SIGN_OPT_CONVERT_FLIRT;
output_file = opt.arg;
break;
case 'o':
if (option != RZ_SIGN_OPT_NONE) {
RZ_LOG_ERROR("rz-sign: cannot combine option -%c with previous options\n", c);
ret = -1;
goto rz_sign_end;
}
option = RZ_SIGN_OPT_CREATE_FLIRT;
output_file = opt.arg;
break;
case 'd':
if (option != RZ_SIGN_OPT_NONE) {
RZ_LOG_ERROR("rz-sign: cannot combine option -%c with previous options\n", c);
ret = -1;
goto rz_sign_end;
}
option = RZ_SIGN_OPT_DUMP_FLIRT;
break;
case 'e':
if (!(config = rz_str_dup(opt.arg)) || !rz_list_append(evars, config)) {
free(config);
RZ_LOG_ERROR("rz-sign: cannot add evaluable config variable '%s' to RzList\n", opt.arg);
ret = -1;
goto rz_sign_end;
}
break;
case 'q':
quiet = true;
break;
case 'v': {
RzPath *sys_path = rz_path_new();
if (!sys_path) {
ret = -1;
goto rz_sign_end;
}
size_t print_val = rz_main_version_print(sys_path, "rz-sign");
rz_path_free(sys_path);
ret = print_val;
goto rz_sign_end;
}
case 'h':
rz_sign_show_help();
goto rz_sign_end;
default:
RZ_LOG_ERROR("rz-sign: invalid option -%c\n", c);
rz_sign_show_help();
ret = -1;
goto rz_sign_end;
}
}
if (opt.ind >= argc) {
RZ_LOG_ERROR("rz-sign: input file was not provided\n");
rz_sign_show_help();
ret = -1;
goto rz_sign_end;
}
input_file = argv[opt.ind];
if (option == RZ_SIGN_OPT_CREATE_FLIRT && complexity > 2) {
RZ_LOG_ERROR("rz-sign: Invalid analysis complexity (too many -a defined, max -aa)\n");
rz_sign_show_help();
ret = -1;
goto rz_sign_end;
}
core = rz_core_new();
if (!core) {
RZ_LOG_ERROR("rz-sign: Cannot allocate RzCore\n");
ret = -1;
goto rz_sign_end;
}
rz_config_set_b(core->config, "scr.interactive", false);
rz_config_set_b(core->config, "analysis.apply.signature", false);
rz_cons_reset();
rz_cons_set_interactive(false);
rz_core_loadlibs(core, RZ_CORE_LOADLIBS_ALL);
if (!rz_core_file_open(core, input_file, 0, 0)) {
RZ_LOG_ERROR("rz-sign: Could not open file %s\n", input_file);
ret = -1;
goto rz_sign_end;
}
(void)rz_core_bin_load(core, NULL, UT64_MAX);
(void)rz_core_bin_update_arch_bits(core);
// quiet mode
if (quiet) {
rz_config_set_b(core->config, "scr.prompt", false);
rz_config_set_i(core->config, "scr.color", COLOR_MODE_DISABLED);
}
// set all evars
rz_list_foreach (evars, it, config) {
if (!rz_config_eval(core->config, config)) {
RZ_LOG_ERROR("rz-sign: invalid option '%s'\n", config);
ret = -1;
goto rz_sign_end;
}
}
switch (option) {
case RZ_SIGN_OPT_CONVERT_FLIRT:
// convert a flirt file from .pat to .sig or viceversa
if (!rz_core_flirt_convert_file(core, input_file, output_file)) {
ret = -1;
} else if (!quiet) {
rz_cons_printf("rz-sign: %s was converted to %s.\n", input_file, output_file);
}
break;
case RZ_SIGN_OPT_CREATE_FLIRT:
// run analysis to find functions
perform_analysis(core, complexity);
// create flirt file
if (!rz_core_flirt_create_file(core, output_file, &n_nodes)) {
ret = -1;
} else if (!quiet) {
rz_cons_printf("rz-sign: written %u signatures to %s.\n", n_nodes, output_file);
}
break;
case RZ_SIGN_OPT_DUMP_FLIRT:
if (!rz_core_flirt_dump_file(input_file)) {
ret = -1;
}
break;
default:
RZ_LOG_ERROR("rz-sign: missing option, please set -c or -d or -o\n");
ret = -1;
break;
}
rz_cons_flush();
rz_sign_end:
rz_list_free(evars);
rz_core_free(core);
return ret;
}