mirror of
https://github.com/radareorg/radare2.git
synced 2025-01-09 23:11:41 +00:00
951 lines
22 KiB
C
951 lines
22 KiB
C
/* radare - LGPL - Copyright 2009-2017 - pancake, nibble */
|
|
|
|
#include <r_core.h>
|
|
#include <r_anal.h>
|
|
#include <r_sign.h>
|
|
#include <r_list.h>
|
|
#include <r_cons.h>
|
|
#include <r_util.h>
|
|
|
|
static bool addFcnBytes(RCore *core, RAnalFunction *fcn, const char *name, int type, int minzlen, int maxzlen) {
|
|
int fcnlen = 0, len = 0;
|
|
ut8 *buf = NULL, *mask = NULL;
|
|
char *zigname = NULL;
|
|
bool retval = true;
|
|
int curspace = core->anal->zign_spaces.space_idx;
|
|
|
|
fcnlen = r_anal_fcn_realsize (fcn);
|
|
|
|
if (fcnlen < minzlen) {
|
|
eprintf ("warn: omitting %s zignature is too small. Length is %d. Check zign.min.\n",
|
|
fcn->name, fcnlen);
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
len = R_MIN (fcnlen, maxzlen);
|
|
|
|
buf = malloc (len);
|
|
|
|
if (r_io_read_at (core->io, fcn->addr, buf, len) != len) {
|
|
eprintf ("error: cannot read at 0x%08"PFMT64x"\n", fcn->addr);
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (name) {
|
|
zigname = r_str_new (name);
|
|
} else {
|
|
if (curspace != -1) {
|
|
zigname = r_str_newf ("%s.", core->anal->zign_spaces.spaces[curspace]);
|
|
}
|
|
zigname = r_str_appendf (zigname, "%c.%s", type, fcn->name);
|
|
}
|
|
|
|
switch (type) {
|
|
case R_SIGN_EXACT:
|
|
mask = malloc (len);
|
|
memset (mask, 0xff, len);
|
|
retval = r_sign_add_exact (core->anal, zigname, len, buf, mask);
|
|
break;
|
|
case R_SIGN_ANAL:
|
|
retval = r_sign_add_anal (core->anal, zigname, len, buf);
|
|
break;
|
|
}
|
|
|
|
exit_function:
|
|
free (buf);
|
|
free (mask);
|
|
free (zigname);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static bool addHex(RCore *core, const char *name, int type, const char *hexbytes) {
|
|
ut8 *mask = NULL, *bytes = NULL;
|
|
int size = 0, blen = 0;
|
|
bool retval = true;
|
|
|
|
blen = strlen (hexbytes) + 4;
|
|
bytes = malloc (blen);
|
|
mask = malloc (blen);
|
|
|
|
size = r_hex_str2binmask (hexbytes, bytes, mask);
|
|
if (size <= 0) {
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
switch (type) {
|
|
case R_SIGN_EXACT:
|
|
retval = r_sign_add_exact (core->anal, name, size, bytes, mask);
|
|
break;
|
|
case R_SIGN_ANAL:
|
|
retval = r_sign_add_anal (core->anal, name, size, bytes);
|
|
break;
|
|
}
|
|
|
|
exit_function:
|
|
free (bytes);
|
|
free (mask);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int cmdAddBytes(void *data, const char *input, int type) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case ' ':
|
|
{
|
|
const char *name = NULL, *hexbytes = NULL;
|
|
char *args = NULL;
|
|
int n = 0;
|
|
bool retval = true;
|
|
|
|
args = r_str_new (input + 1);
|
|
n = r_str_word_set0 (args);
|
|
|
|
if (n != 2) {
|
|
eprintf ("usage: za%s name bytes\n", type == R_SIGN_ANAL? "a": "e");
|
|
retval = false;
|
|
goto exit_case;
|
|
}
|
|
|
|
name = r_str_word_get0 (args, 0);
|
|
hexbytes = r_str_word_get0 (args, 1);
|
|
|
|
if (!addHex (core, name, type, hexbytes)) {
|
|
eprintf ("error: cannot add zignature\n");
|
|
retval = false;
|
|
goto exit_case;
|
|
}
|
|
|
|
exit_case:
|
|
free (args);
|
|
return retval;
|
|
}
|
|
break;
|
|
case 'f':
|
|
{
|
|
RAnalFunction *fcni = NULL;
|
|
RListIter *iter = NULL;
|
|
const char *name = NULL, *zigname = NULL;
|
|
char *args = NULL;
|
|
int minzlen = r_config_get_i (core->config, "zign.min");
|
|
int maxzlen = r_config_get_i (core->config, "zign.max");
|
|
int n = 0;
|
|
bool retval = true;
|
|
|
|
args = r_str_new (r_str_trim_const (input + 1));
|
|
n = r_str_word_set0 (args);
|
|
|
|
if (n > 2) {
|
|
eprintf ("usage: za%sf [name] [zigname]\n", type == R_SIGN_ANAL? "a": "e");
|
|
retval = false;
|
|
goto exit_case_fcn;
|
|
}
|
|
|
|
switch (n) {
|
|
case 2:
|
|
zigname = r_str_word_get0 (args, 1);
|
|
case 1:
|
|
name = r_str_word_get0 (args, 0);
|
|
}
|
|
|
|
r_cons_break_push (NULL, NULL);
|
|
r_list_foreach (core->anal->fcns, iter, fcni) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
if ((!name && core->offset == fcni->addr) ||
|
|
(name && !strcmp (name, fcni->name))) {
|
|
if (!addFcnBytes (core, fcni, zigname, type, minzlen, maxzlen)) {
|
|
eprintf ("error: could not add zignature for fcn %s\n", fcni->name);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
r_cons_break_pop ();
|
|
|
|
exit_case_fcn:
|
|
free (args);
|
|
return retval;
|
|
}
|
|
break;
|
|
case 'F':
|
|
{
|
|
RAnalFunction *fcni = NULL;
|
|
RListIter *iter = NULL;
|
|
int minzlen = r_config_get_i (core->config, "zign.min");
|
|
int maxzlen = r_config_get_i (core->config, "zign.max");
|
|
|
|
r_cons_break_push (NULL, NULL);
|
|
r_list_foreach (core->anal->fcns, iter, fcni) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
if (!addFcnBytes (core, fcni, NULL, type, minzlen, maxzlen)) {
|
|
eprintf ("error: could not add zignature for fcn %s\n", fcni->name);
|
|
}
|
|
}
|
|
r_cons_break_pop ();
|
|
}
|
|
break;
|
|
case '?':
|
|
{
|
|
if (type == R_SIGN_ANAL) {
|
|
const char *help_msg[] = {
|
|
"Usage:", "zaa[fF] [args] ", "# Create anal zignature",
|
|
"zaa ", "name bytes", "create anal zignature",
|
|
"zaaf ", "[name] [zigname]", "create anal zignature for function",
|
|
"zaaF ", "", "generate anal zignatures for all functions",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
} else {
|
|
const char *help_msg[] = {
|
|
"Usage:", "zae[fF] [args] ", "# Create anal zignature",
|
|
"zae ", "name bytes", "create anal zignature",
|
|
"zaef ", "[name] [zigname]", "create anal zignature for function",
|
|
"zaeF ", "", "generate anal zignatures for all functions",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: za%s[fF] [args]\n", type == R_SIGN_ANAL? "a": "e");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool addFcnMetrics(RCore *core, RAnalFunction *fcn, const char *name) {
|
|
RSignMetrics metrics;
|
|
char *zigname = NULL;
|
|
bool retval = true;
|
|
int curspace = core->anal->zign_spaces.space_idx;
|
|
|
|
metrics.cc = r_anal_fcn_cc (fcn);
|
|
metrics.nbbs = r_list_length (fcn->bbs);
|
|
metrics.edges = r_anal_fcn_count_edges (fcn, &metrics.ebbs);
|
|
|
|
if (name) {
|
|
zigname = r_str_new (name);
|
|
} else {
|
|
if (curspace != -1) {
|
|
zigname = r_str_newf ("%s.", core->anal->zign_spaces.spaces[curspace]);
|
|
}
|
|
zigname = r_str_appendf (zigname, "%c.%s", R_SIGN_METRIC, fcn->name);
|
|
}
|
|
|
|
retval = r_sign_add_metric (core->anal, zigname, metrics);
|
|
|
|
free (zigname);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static bool parseMetricArgs(const char *args0, int nargs, RSignMetrics *metrics) {
|
|
const char *ptr = NULL;
|
|
int i = 0;
|
|
bool retval = true;
|
|
|
|
metrics->cc = -1;
|
|
metrics->nbbs = -1;
|
|
metrics->edges = -1;
|
|
metrics->ebbs = -1;
|
|
|
|
for (i = 0; i < nargs; i++) {
|
|
ptr = r_str_word_get0 (args0, i);
|
|
if (r_str_startswith (ptr, "cc=")) {
|
|
metrics->cc = atoi (ptr + 3);
|
|
} else if (r_str_startswith (ptr, "nbbs=")) {
|
|
metrics->nbbs = atoi (ptr + 5);
|
|
} else if (r_str_startswith (ptr, "edges=")) {
|
|
metrics->edges = atoi (ptr + 6);
|
|
} else if (r_str_startswith (ptr, "ebbs=")) {
|
|
metrics->ebbs = atoi (ptr + 5);
|
|
} else {
|
|
retval = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int cmdAddMetric(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case ' ':
|
|
{
|
|
RSignMetrics metrics;
|
|
const char *name = NULL, *args0 = NULL;
|
|
char *args = NULL;
|
|
int n = 0;
|
|
bool retval = true;
|
|
|
|
args = r_str_new (input + 1);
|
|
n = r_str_word_set0 (args);
|
|
|
|
if (n < 2) {
|
|
eprintf ("usage: zam name metrics\n");
|
|
retval = false;
|
|
goto exit_case;
|
|
}
|
|
|
|
name = r_str_word_get0 (args, 0);
|
|
args0 = r_str_word_get0 (args, 1);
|
|
|
|
if (!parseMetricArgs (args0, n - 1, &metrics)) {
|
|
eprintf ("error: invalid arguments\n");
|
|
retval = false;
|
|
goto exit_case;
|
|
}
|
|
|
|
if (!r_sign_add_metric (core->anal, name, metrics)) {
|
|
eprintf ("error: cannot add zignature\n");
|
|
retval = false;
|
|
goto exit_case;
|
|
}
|
|
|
|
exit_case:
|
|
free (args);
|
|
return retval;
|
|
}
|
|
break;
|
|
case 'f':
|
|
{
|
|
RAnalFunction *fcni = NULL;
|
|
RListIter *iter = NULL;
|
|
const char *name = NULL, *zigname = NULL;
|
|
char *args = NULL;
|
|
int n = 0;
|
|
bool retval = true;
|
|
|
|
args = r_str_new (r_str_trim_const (input + 1));
|
|
n = r_str_word_set0 (args);
|
|
|
|
if (n > 2) {
|
|
eprintf ("usage: zamf [name] [zigname]\n");
|
|
retval = false;
|
|
goto exit_case_fcn;
|
|
}
|
|
|
|
switch (n) {
|
|
case 2:
|
|
zigname = r_str_word_get0 (args, 1);
|
|
case 1:
|
|
name = r_str_word_get0 (args, 0);
|
|
}
|
|
|
|
r_cons_break_push (NULL, NULL);
|
|
r_list_foreach (core->anal->fcns, iter, fcni) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
if ((!name && core->offset == fcni->addr) ||
|
|
(name && !strcmp (name, fcni->name))) {
|
|
if (!addFcnMetrics (core, fcni, zigname)) {
|
|
eprintf ("error: could not add zignature for fcn %s\n", fcni->name);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
r_cons_break_pop ();
|
|
|
|
exit_case_fcn:
|
|
free (args);
|
|
return retval;
|
|
}
|
|
break;
|
|
case 'F':
|
|
{
|
|
RAnalFunction *fcni = NULL;
|
|
RListIter *iter = NULL;
|
|
|
|
r_cons_break_push (NULL, NULL);
|
|
r_list_foreach (core->anal->fcns, iter, fcni) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
if (!addFcnMetrics (core, fcni, NULL)) {
|
|
eprintf ("error: could not add zignature for fcn %s\n", fcni->name);
|
|
}
|
|
}
|
|
r_cons_break_pop ();
|
|
}
|
|
break;
|
|
case '?':
|
|
if (input[1] == '?') {
|
|
const char *help_msg[] = {
|
|
"Examples:", "Metric Zignatures", " examples and documentation",
|
|
"cc", "", "cyclomatic complexity",
|
|
"edges", "", "number of edges",
|
|
"nbbs", "", "number of basic blocks",
|
|
"ebbs ", "", "number of end basic blocks",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
r_cons_printf ("Examples:\n"
|
|
" zam foo cc=2 nbbs=3 edges=3 ebbs=1\n"
|
|
" zam bar nbbs=3 edges=3\n");
|
|
} else {
|
|
const char *help_msg[] = {
|
|
"Usage:", "zam[fF?] [args] ", "# Create metric zignature",
|
|
"zam?? ", "", "show metrics help",
|
|
"zam ", "name metrics", "create metric zignature",
|
|
"zamf ", "[name] [zigname]", "create metric zignature for function",
|
|
"zamF ", "", "generate metric zignatures for all functions",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: zam[fF] [args]\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int cmdAdd(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case 'a':
|
|
return cmdAddBytes (data, input + 1, R_SIGN_ANAL);
|
|
case 'e':
|
|
return cmdAddBytes (data, input + 1, R_SIGN_EXACT);
|
|
case 'm':
|
|
return cmdAddMetric (data, input + 1);
|
|
case '?':
|
|
{
|
|
const char *help_msg[] = {
|
|
"Usage:", "za[aemg] [args] ", "# Add zignature",
|
|
"zaa", "[?]", "add anal zignature",
|
|
"zae", "[?]", "add exact-match zignature",
|
|
"zam", "[?]", "add metric zignature",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: za[aemg] [args]\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool loadGzSdb(RAnal *a, const char *filename) {
|
|
ut8 *buf = NULL;
|
|
int size = 0;
|
|
char *tmpfile = NULL;
|
|
bool retval = true;
|
|
|
|
if (!r_file_exists (filename)) {
|
|
eprintf ("error: file %s does not exist\n", filename);
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (!(buf = r_file_gzslurp (filename, &size, 0))) {
|
|
eprintf ("error: cannot decompress file\n");
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (!(tmpfile = r_file_temp ("r2zign"))) {
|
|
eprintf ("error: cannot create temp file\n");
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (!r_file_dump (tmpfile, buf, size, 0)) {
|
|
eprintf ("error: cannot dump file\n");
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (!r_sign_load (a, tmpfile)) {
|
|
eprintf ("error: cannot load file\n");
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (!r_file_rm (tmpfile)) {
|
|
eprintf ("error: cannot delete temp file\n");
|
|
retval = false;
|
|
goto exit_function;
|
|
}
|
|
|
|
exit_function:
|
|
free (buf);
|
|
free (tmpfile);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int cmdFile(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case ' ':
|
|
{
|
|
const char *filename;
|
|
|
|
if (input[1] != '\x00') {
|
|
filename = input + 1;
|
|
return r_sign_load (core->anal, filename);
|
|
} else {
|
|
eprintf ("usage: zo filename\n");
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case 's':
|
|
{
|
|
const char *filename;
|
|
|
|
if (input[1] == ' ' && input[2] != '\x00') {
|
|
filename = input + 2;
|
|
return r_sign_save (core->anal, filename);
|
|
} else {
|
|
eprintf ("usage: zos filename\n");
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case 'z':
|
|
{
|
|
const char *filename = NULL;
|
|
|
|
if (input[1] == ' ' && input[2] != '\x00') {
|
|
filename = input + 2;
|
|
} else {
|
|
eprintf ("usage: zoz filename\n");
|
|
return false;
|
|
}
|
|
|
|
return loadGzSdb (core->anal, filename);
|
|
}
|
|
break;
|
|
case '?':
|
|
{
|
|
const char *help_msg[] = {
|
|
"Usage:", "zo[zs] filename ", "# Manage zignature files",
|
|
"zo ", "filename", "load zinatures from sdb file",
|
|
"zoz ", "filename", "load zinatures from gzipped sdb file",
|
|
"zos ", "filename", "save zignatures to sdb file",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: zo[zs] filename\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int cmdSpace(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
RSpaces *zs = &core->anal->zign_spaces;
|
|
|
|
switch (*input) {
|
|
case '+':
|
|
if (input[1] != '\x00') {
|
|
r_space_push (zs, input + 1);
|
|
} else {
|
|
eprintf ("usage: zs+zignspace\n");
|
|
return false;
|
|
}
|
|
break;
|
|
case 'r':
|
|
if (input[1] == ' ' && input[2] != '\x00') {
|
|
r_space_rename (zs, NULL, input + 2);
|
|
} else {
|
|
eprintf ("usage: zsr newname\n");
|
|
return false;
|
|
}
|
|
break;
|
|
case '-':
|
|
if (input[1] == '\x00') {
|
|
r_space_pop (zs);
|
|
} else if (input[1] == '*') {
|
|
r_space_unset (zs, NULL);
|
|
} else {
|
|
r_space_unset (zs, input+1);
|
|
}
|
|
break;
|
|
case 'j':
|
|
case '*':
|
|
case '\0':
|
|
r_space_list (zs, input[0]);
|
|
break;
|
|
case ' ':
|
|
if (input[1] != '\x00') {
|
|
r_space_set (zs, input + 1);
|
|
} else {
|
|
eprintf ("usage: zs zignspace\n");
|
|
return false;
|
|
}
|
|
break;
|
|
case '?':
|
|
{
|
|
const char *help_msg[] = {
|
|
"Usage:", "zs[+-*] [namespace] ", "# Manage zignspaces",
|
|
"zs", "", "display zignspaces",
|
|
"zs ", "zignspace", "select zignspace",
|
|
"zs ", "*", "select all zignspaces",
|
|
"zs-", "zignspace", "delete zignspace",
|
|
"zs-", "*", "delete all zignspaces",
|
|
"zs+", "zignspace", "push previous zignspace and set",
|
|
"zs-", "", "pop to the previous zignspace",
|
|
"zsr ", "newname", "rename selected zignspace",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
int i, count = 0;
|
|
|
|
for (i = 0; i < R_FLAG_SPACES_MAX; i++) {
|
|
if (!zs->spaces[i]) {
|
|
continue;
|
|
}
|
|
r_cons_printf ("%02d %c %s\n", count,
|
|
(i == zs->space_idx)? '*': ' ',
|
|
zs->spaces[i]);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int cmdFlirt(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case 'd':
|
|
// TODO
|
|
if (input[1] != ' ') {
|
|
eprintf ("usage: zfd filename\n");
|
|
return false;
|
|
}
|
|
r_sign_flirt_dump (core->anal, input + 2);
|
|
break;
|
|
case 's':
|
|
// TODO
|
|
if(input[1] != ' ') {
|
|
eprintf ("usage: zfs filename\n");
|
|
return false;
|
|
}
|
|
r_sign_flirt_scan (core->anal, input + 2);
|
|
break;
|
|
case 'z':
|
|
// TODO
|
|
break;
|
|
case '?':
|
|
{
|
|
const char *help_msg[] = {
|
|
"Usage:", "zf[dsz] filename ", "# Manage FLIRT signatures",
|
|
"zfd ", "filename", "open FLIRT file and dump",
|
|
"zfs ", "filename", "open FLIRT file and scan",
|
|
"zfz ", "filename", "open FLIRT file and get sig commands (zfz flirt_file > zignatures.sig)",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: zf[dsz] filename\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
struct ctxSearchCB {
|
|
RCore *core;
|
|
bool rad;
|
|
int count;
|
|
};
|
|
|
|
static void addFlag(RCore *core, RSignItem *it, ut64 addr, int size, int count, bool rad) {
|
|
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
|
|
char *name;
|
|
|
|
name = r_str_newf ("%s.%s_%d", zign_prefix, it->name, count);
|
|
|
|
if (rad) {
|
|
r_cons_printf ("f %s %d @ 0x%08"PFMT64x"\n", name, size, addr);
|
|
} else {
|
|
r_flag_set(core->flags, name, addr, size);
|
|
}
|
|
|
|
free(name);
|
|
}
|
|
|
|
static int metricMatchCB(RSignItem *it, RAnalFunction *fcn, void *user) {
|
|
struct ctxSearchCB *ctx = (struct ctxSearchCB *) user;
|
|
|
|
// TODO(nibble): use one counter per metric zign instead of ctx->count
|
|
addFlag (ctx->core, it, fcn->addr, r_anal_fcn_realsize (fcn), ctx->count, ctx->rad);
|
|
ctx->count++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int searchHitCB(RSearchKeyword *kw, RSignItem *it, ut64 addr, void *user) {
|
|
struct ctxSearchCB *ctx = (struct ctxSearchCB *) user;
|
|
|
|
addFlag (ctx->core, it, addr, kw->keyword_length, kw->count, ctx->rad);
|
|
ctx->count++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool searchRange(RCore *core, ut64 from, ut64 to, bool rad, struct ctxSearchCB *ctx) {
|
|
RSignSearch *ss;
|
|
ut8 *buf = malloc (core->blocksize);
|
|
ut64 at;
|
|
int rlen;
|
|
bool retval = true;
|
|
|
|
ss = r_sign_search_new ();
|
|
ss->search->align = r_config_get_i (core->config, "search.align");
|
|
r_sign_search_init (core->anal, ss, searchHitCB, ctx);
|
|
|
|
r_cons_break_push (NULL, NULL);
|
|
for (at = from; at < to; at += core->blocksize) {
|
|
if (r_cons_is_breaked ()) {
|
|
retval = false;
|
|
break;
|
|
}
|
|
rlen = R_MIN (core->blocksize, to - at);
|
|
if (!r_io_read_at (core->io, at, buf, rlen)) {
|
|
retval = false;
|
|
break;
|
|
}
|
|
if (r_sign_search_update (core->anal, ss, &at, buf, rlen) == -1) {
|
|
eprintf ("search: update read error at 0x%08"PFMT64x"\n", at);
|
|
retval = false;
|
|
break;
|
|
}
|
|
}
|
|
r_cons_break_pop ();
|
|
|
|
free (buf);
|
|
r_sign_search_free (ss);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static bool search(RCore *core, bool rad) {
|
|
struct ctxSearchCB metric_match_ctx = { core, rad, 0 };
|
|
struct ctxSearchCB bytes_search_ctx = { core, rad, 0 };
|
|
RList *list;
|
|
RListIter *iter;
|
|
RAnalFunction *fcni = NULL;
|
|
RIOMap *map;
|
|
bool retval = true;
|
|
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
|
|
const char *mode = r_config_get (core->config, "search.in");
|
|
ut64 sin_from = UT64_MAX, sin_to = UT64_MAX;
|
|
int hits = 0;
|
|
|
|
if (rad) {
|
|
r_cons_printf ("fs+%s\n", zign_prefix);
|
|
} else {
|
|
if (!r_flag_space_push (core->flags, zign_prefix)) {
|
|
eprintf ("error: cannot create flagspace\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Anal/Exact search
|
|
list = r_core_get_boundaries_prot (core, R_IO_EXEC | R_IO_WRITE | R_IO_READ, mode, &sin_from, &sin_to);
|
|
if (list) {
|
|
r_list_foreach (list, iter, map) {
|
|
eprintf ("[+] searching 0x%08"PFMT64x" - 0x%08"PFMT64x"\n", map->from, map->to);
|
|
retval &= searchRange (core, map->from, map->to, rad, &bytes_search_ctx);
|
|
}
|
|
r_list_free (list);
|
|
} else {
|
|
eprintf ("[+] searching 0x%08"PFMT64x" - 0x%08"PFMT64x"\n", sin_from, sin_to);
|
|
retval = searchRange (core, sin_from, sin_to, rad, &bytes_search_ctx);
|
|
}
|
|
|
|
// Metric search
|
|
eprintf ("[+] searching function metrics\n");
|
|
r_cons_break_push (NULL, NULL);
|
|
r_list_foreach (core->anal->fcns, iter, fcni) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
r_sign_match_metric (core->anal, fcni, metricMatchCB, &metric_match_ctx);
|
|
}
|
|
r_cons_break_pop ();
|
|
|
|
if (rad) {
|
|
r_cons_printf ("fs-\n");
|
|
} else {
|
|
if (!r_flag_space_pop (core->flags)) {
|
|
eprintf ("error: cannot restore flagspace\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
hits = bytes_search_ctx.count + metric_match_ctx.count;
|
|
eprintf ("hits: %d\n", hits);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int cmdSearch(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case '\x00':
|
|
case '*':
|
|
return search (core, input[0] == '*');
|
|
case '?':
|
|
{
|
|
const char *help_msg[] = {
|
|
"Usage:", "z/[*] ", "# Search signatures (see 'e?search' for options)",
|
|
"z/ ", "", "search zignatures on range and flag matches",
|
|
"z/* ", "", "search zignatures on range and output radare commands",
|
|
NULL};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: z/[*]\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int cmdCheck(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
RSignSearch *ss;
|
|
RListIter *iter;
|
|
RAnalFunction *fcni = NULL;
|
|
ut64 at = core->offset;
|
|
bool retval = true;
|
|
bool rad = input[0] == '*';
|
|
struct ctxSearchCB bytes_search_ctx = { core, rad, 0 };
|
|
struct ctxSearchCB metric_match_ctx = { core, rad, 0 };
|
|
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
|
|
int hits = 0;
|
|
|
|
if (rad) {
|
|
r_cons_printf ("fs+%s\n", zign_prefix);
|
|
} else {
|
|
if (!r_flag_space_push (core->flags, zign_prefix)) {
|
|
eprintf ("error: cannot create flagspace\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Anal/Exact search
|
|
eprintf ("[+] searching 0x%08"PFMT64x" - 0x%08"PFMT64x"\n", at, at + core->blocksize);
|
|
ss = r_sign_search_new ();
|
|
r_sign_search_init (core->anal, ss, searchHitCB, &bytes_search_ctx);
|
|
if (r_sign_search_update (core->anal, ss, &at, core->block, core->blocksize) == -1) {
|
|
eprintf ("search: update read error at 0x%08"PFMT64x"\n", at);
|
|
retval = false;
|
|
}
|
|
r_sign_search_free (ss);
|
|
|
|
// Metric search
|
|
eprintf ("[+] searching function metrics\n");
|
|
r_cons_break_push (NULL, NULL);
|
|
r_list_foreach (core->anal->fcns, iter, fcni) {
|
|
if (r_cons_is_breaked ()) {
|
|
break;
|
|
}
|
|
if (fcni->addr == core->offset) {
|
|
r_sign_match_metric (core->anal, fcni, metricMatchCB, &metric_match_ctx);
|
|
break;
|
|
}
|
|
}
|
|
r_cons_break_pop ();
|
|
|
|
if (rad) {
|
|
r_cons_printf ("fs-\n");
|
|
} else {
|
|
if (!r_flag_space_pop (core->flags)) {
|
|
eprintf ("error: cannot restore flagspace\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
hits = bytes_search_ctx.count + metric_match_ctx.count;
|
|
eprintf ("hits: %d\n", hits);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int cmd_zign(void *data, const char *input) {
|
|
RCore *core = (RCore *) data;
|
|
|
|
switch (*input) {
|
|
case '\0':
|
|
case '*':
|
|
case 'j':
|
|
r_sign_list (core->anal, input[0]);
|
|
break;
|
|
case '-':
|
|
r_sign_delete (core->anal, input + 1);
|
|
break;
|
|
case 'o':
|
|
return cmdFile (data, input + 1);
|
|
case 'a':
|
|
return cmdAdd (data, input + 1);
|
|
case 'f':
|
|
return cmdFlirt (data, input + 1);
|
|
case '/':
|
|
return cmdSearch (data, input + 1);
|
|
case 'c':
|
|
return cmdCheck (data, input + 1);
|
|
case 's':
|
|
return cmdSpace (data, input + 1);
|
|
case '?':
|
|
{
|
|
const char* help_msg[] = {
|
|
"Usage:", "z[*j-aof/cs] [args] ", "# Manage zignatures",
|
|
"z", "", "show zignagures",
|
|
"z*", "", "show zignatures in radare format",
|
|
"zj", "", "show zignatures in json format",
|
|
"z-", "zignature", "delete zignature",
|
|
"z-", "*", "delete all zignatures",
|
|
"za", "[?]", "add zignature",
|
|
"zo", "[?]", "manage zignature files",
|
|
"zf", "[?]", "manage FLIRT signatures",
|
|
"z/", "[?]", "search zignatures",
|
|
"zc", "", "check zignatures at address",
|
|
"zs", "[?]", "manage zignspaces",
|
|
"NOTE:", "", "bytes can contain '..' (dots) to specify a binary mask",
|
|
NULL
|
|
};
|
|
r_core_cmd_help (core, help_msg);
|
|
}
|
|
break;
|
|
default:
|
|
eprintf ("usage: z[*j-aof/cs] [args]\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|