Apply types on matching zignature data ##signatures (#15746)

* Implement new zignature types format
  * Adapt zignature types deserialization to new format
* Integrate fcn types when zignatures match
This commit is contained in:
Óscar Carrasco 2020-01-16 09:26:03 +00:00 committed by radare
parent 3c788a4967
commit 0efbb81c91
6 changed files with 182 additions and 31 deletions

View File

@ -67,6 +67,40 @@ R_API RList *r_sign_fcn_vars(RAnal *a, RAnalFunction *fcn) {
return ret;
}
R_API RList *r_sign_fcn_types(RAnal *a, RAnalFunction *fcn) {
// From anal/types/*:
// Get key-value types from sdb matching "func.%s", fcn->name
// Get func.%s.args (number of args)
// Get type,name pairs
// Put everything in RList following the next format:
// types: main.ret=%type%, main.args=%num%, main.arg.0="int,argc", ...
r_return_val_if_fail (a && fcn, NULL);
RList *ret = r_list_newf ((RListFree) free);
char *args_expr = r_str_newf ("func.%s.args", fcn->name), *arg = NULL;
const char *ret_type = sdb_const_get (a->sdb_types, r_str_newf ("func.%s.ret", fcn->name), 0);
const char *fcntypes = sdb_const_get (a->sdb_types, args_expr, 0);
int argc = 0;
if (fcntypes) {
if (ret_type) {
r_list_append (ret, r_str_newf ("func.%s.ret=%s", fcn->name, ret_type));
}
argc = atoi (fcntypes);
r_list_append (ret, r_str_newf ("func.%s.args=%d", fcn->name, argc));
for (int i = 0; i < argc; i++) {
arg = sdb_get (a->sdb_types, r_str_newf ("func.%s.arg.%d", fcn->name, i), 0);
r_list_append (ret, r_str_newf ("func.%s.arg.%d=\"%s\"", fcn->name, i, arg));
}
}
free (arg);
free (args_expr);
return ret;
}
R_API RList *r_sign_fcn_xrefs(RAnal *a, RAnalFunction *fcn) {
RListIter *iter = NULL;
RAnalRef *refi = NULL;
@ -119,12 +153,35 @@ R_API RList *r_sign_fcn_refs(RAnal *a, RAnalFunction *fcn) {
return ret;
}
static RList *zign_types_to_list(RAnal *a, char *types) {
RList *ret = r_list_newf ((RListFree) free);
unsigned int i = 0, prev = 0, len = strlen (types);
bool quoted = false;
char *token = NULL;
for (i = 0; i <= len; i++) {
if (types[i] == '"') {
quoted = !quoted;
}
else if ((types[i] == ',' && !quoted) || types[i] == '\0') {
token = r_str_ndup (types + prev, i - prev);
if (token) {
prev = i + 1;
r_list_append (ret, strdup (token));
}
}
}
free (token);
return ret;
}
R_API bool r_sign_deserialize(RAnal *a, RSignItem *it, const char *k, const char *v) {
char *refs = NULL;
char *vars = NULL;
char *types = NULL;
const char *token = NULL;
int i = 0, n = 0, nrefs = 0, nvars = 0, ntypes = 0, size = 0, w = 0;
int i = 0, n = 0, nrefs = 0, nvars = 0, size = 0, w = 0;
r_return_val_if_fail (a && it && k && v, false);
@ -225,13 +282,7 @@ R_API bool r_sign_deserialize(RAnal *a, RSignItem *it, const char *k, const char
break;
case R_SIGN_TYPES:
types = r_str_new (token);
ntypes = r_str_split (types, ',');
if (ntypes > 0) {
it->types = r_list_newf ((RListFree) free);
for (i = 0; i < ntypes; i++) {
r_list_append (it->types, r_str_newf (r_str_word_get0 (types, i)));
}
}
it->types = zign_types_to_list (a, types);
break;
case R_SIGN_BBHASH:
if (token[0] != 0) {
@ -2081,7 +2132,7 @@ static int typesMatchCB(RSignItem *it, void *user) {
return 1;
}
// TODO(nibble | oxcabe): slow operation, add cache
types = r_anal_types_from_fcn (ctx->anal, ctx->fcn);
types = r_sign_fcn_types (ctx->anal, ctx->fcn);
if (!types) {
return 1;
}

View File

@ -833,6 +833,11 @@ static void __add_vars_sdb(RCore *core, RAnalFunction *fcn) {
arg_count++;
}
}
if (arg_count > 0) {
char *query = r_str_newf ("anal/types/func.%s.args=%d", fcn->name, arg_count);
sdb_querys (core->sdb, NULL, 0, query);
free (query);
}
}
static bool cmd_anal_aaft(RCore *core) {

View File

@ -161,7 +161,7 @@ static bool addFcnVars(RCore *core, RAnalFunction *fcn, const char *name) {
}
static bool addFcnTypes(RCore *core, RAnalFunction *fcn, const char *name) {
RList *types = r_anal_types_from_fcn (core->anal, fcn);
RList *types = r_sign_fcn_types (core->anal, fcn);
if (!types) {
return false;
}
@ -731,21 +731,116 @@ struct ctxSearchCB {
const char *prefix;
};
static void addFlag(RCore *core, RSignItem *it, ut64 addr, int size, int count, const char* prefix, bool rad) {
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
char *name = r_str_newf ("%s.%s.%s_%d", zign_prefix, prefix, it->name, count);
if (!name) {
return;
}
if (rad) {
r_cons_printf ("f %s %d @ 0x%08"PFMT64x"\n", name, size, addr);
if (it->realname) {
r_cons_printf ("\"afn %s @ 0x%08"PFMT64x"\"\n", it->realname, addr); // XXX command injection
static bool __fcnstrValidField(char *field, int i) {
char *arg_number = r_str_newf ("%d", i);
int is_ret = strcmp (field, "ret");
int is_args = strcmp (field, "args");
int is_arg = strcmp (field, "arg");
int is_arg_number = strcmp (field, arg_number);
free (arg_number);
return !(is_ret && is_args && is_arg && is_arg_number);
}
static const char *types_list_to_fcnstr(RList *types) {
char *type_kv = NULL, *k = NULL, *v = NULL;
char *field = NULL, *name = NULL, *rettype = NULL;
char *arg = NULL, *ret = NULL;
int nargs = 0, i = 0, j = 0;
RList *args = r_list_new ();
RListIter *iter;
r_list_foreach (types, iter, type_kv) {
k = strtok (type_kv, "=");
v = strtok (NULL, "\0");
strtok (k, ".");
name = strtok (NULL, ".");
field = strtok (NULL, ".");
while (!__fcnstrValidField (field, i) && field) {
name = field;
field = strtok (NULL, ".");
}
if (!strcmp (field, "args")) {
nargs = atoi (v);
} else if (!strcmp (field, "ret")) {
rettype = v;
} else {
if (i < nargs) {
arg = strdup (v);
for (j = 0; j < strlen (arg); j++) {
if (arg[j] == ',') {
arg[j] = ' ';
}
}
r_list_append (args, r_str_ndup (arg + 1,
strlen (arg) - 2));
free (arg);
}
i++;
}
} else {
r_flag_set (core->flags, name, addr, size);
}
free (name);
if (!rettype) {
rettype = strdup ("void"); // workaround for "afs" bug
}
ret = r_str_newf ("%s %s(", rettype, name);
r_list_foreach (args, iter, arg) {
if (iter != r_list_tail (args)) {
ret = r_str_newf ("%s%s, ", ret, arg);
}
}
if (r_list_length (args) > 0) {
ret = r_str_newf ("%s%s);", ret, (char *)r_list_get_top (args));
} else {
ret = r_str_newf ("%s);", ret);
}
r_list_free (args);
return ret;
}
static void addFlag(RCore *core, RSignItem *it, ut64 addr, int size, int count, const char* prefix, bool rad) {
RAnalFunction *fcn = NULL;
const char *zign_prefix = r_config_get (core->config, "zign.prefix");
char *name = NULL;
if (it->types) {
const char *fcnstr = types_list_to_fcnstr (it->types);
char *fcnstr_copy = strdup (fcnstr);
fcn = r_anal_get_fcn_in (core->anal, it->addr, 0);
if (fcn) {
const char *fcn_name = strrchr (r_str_trim_tail (strtok (fcnstr_copy, "(")), ' ');
// __setFunctionName() ; cmd_anal.c:2535 ; Expand into R_API function
free (fcn->name);
fcn->name = strdup (fcn_name + 1);
if (core->anal->cb.on_fcn_rename) {
core->anal->cb.on_fcn_rename (core->anal, core->anal->user, fcn, fcn->name);
}
r_anal_str_to_fcn (core->anal, fcn, fcnstr);
}
if (fcnstr_copy) {
free (fcnstr_copy);
}
}
name = r_name_filter2 (r_str_newf ("%s.%s.%s_%d", zign_prefix, prefix, it->name, count));
if (name) {
if (rad) {
r_cons_printf ("f %s %d @ 0x%08"PFMT64x"\n", name, size, addr);
if (it->realname) {
r_cons_printf ("\"afn %s @ 0x%08"PFMT64x"\"\n", it->realname, addr); // XXX command injection
}
} else {
r_flag_set (core->flags, name, addr, size);
}
free (name);
}
}
static int searchHitCB(RSignItem *it, RSearchKeyword *kw, ut64 addr, void *user) {
@ -884,7 +979,7 @@ static bool search(RCore *core, bool rad, bool only_func) {
}
// Function search
// TODO (oxcabe): This big conditionals should be refactored into a variable
// TODO (oxcabe): Refactor big conditional
if (useGraph || useOffset || useRefs || useHash || (useBytes && only_func) || useTypes) {
eprintf ("[+] searching function metrics\n");
r_cons_break_push (NULL, NULL);
@ -943,7 +1038,7 @@ TODO: add useXRefs, useName
}
hits = bytes_search_ctx.count + graph_match_ctx.count +
offset_match_ctx.count + refs_match_ctx.count + hash_match_ctx.count;
offset_match_ctx.count + refs_match_ctx.count + hash_match_ctx.count + types_match_ctx.count;
eprintf ("hits: %d\n", hits);
return retval;

View File

@ -2083,7 +2083,6 @@ R_API void r_anal_class_list(RAnal *anal, int mode);
R_API void r_anal_class_list_bases(RAnal *anal, const char *class_name);
R_API void r_anal_class_list_vtables(RAnal *anal, const char *class_name);
R_API RList *r_anal_types_from_fcn(RAnal *anal, RAnalFunction *fcn);
R_API RAnalEsilCFG *r_anal_esil_cfg_expr(RAnalEsilCFG *cfg, RAnal *anal, const ut64 off, char *expr);
R_API RAnalEsilCFG *r_anal_esil_cfg_op(RAnalEsilCFG *cfg, RAnal *anal, RAnalOp *op);
R_API void r_anal_esil_cfg_merge_blocks(RAnalEsilCFG *cfg);

View File

@ -132,6 +132,7 @@ R_API void r_sign_item_free(RSignItem *item);
R_API RList *r_sign_fcn_refs(RAnal *a, RAnalFunction *fcn);
R_API RList *r_sign_fcn_xrefs(RAnal *a, RAnalFunction *fcn);
R_API RList *r_sign_fcn_vars(RAnal *a, RAnalFunction *fcn);
R_API RList *r_sign_fcn_types(RAnal *a, RAnalFunction *fcn);
R_API int r_sign_is_flirt(RBuffer *buf);
R_API void r_sign_flirt_dump(const RAnal *anal, const char *flirt_file);

View File

@ -424,7 +424,7 @@ zigs:main:
realname: main
refs: sym.print
vars: b-4, b-16, r110, r114
types: int, char **, int64_t
types: func.main.ret=int, func.main.args=2, func.main.arg.0="int,argc", func.main.arg.1="char **,argv"
bbhash: 9890426532f35eb3a80fe773d887714fe27d13ea125ad7e90beab16a51b74496
EOF
CMDS=<<EOF
@ -447,7 +447,7 @@ zigs:main:
realname: main
refs: sym.print
vars: b-4, b-16, r110, r114
types: int, char **, int64_t
types: func.main.ret=int, func.main.args=2, func.main.arg.0="int,argc", func.main.arg.1="char **,argv"
bbhash: 9890426532f35eb3a80fe773d887714fe27d13ea125ad7e90beab16a51b74496
EOF
CMDS=<<EOF
@ -469,7 +469,7 @@ main:
addr: 0x0040055b
refs: sym.print
vars: b-4, b-16, r110, r114
types: int, char **, int64_t
types: func.main.ret=int, func.main.args=2, func.main.arg.0="int,argc", func.main.arg.1="char **,argv"
bbhash: 9890426532f35eb3a80fe773d887714fe27d13ea125ad7e90beab16a51b74496
EOF
CMDS=<<EOF
@ -491,7 +491,7 @@ foobar:
realname: main
refs: sym.print
vars: b-4, b-16, r110, r114
types: int, char **, int64_t
types: func.main.ret=int, func.main.args=2, func.main.arg.0="int,argc", func.main.arg.1="char **,argv"
bbhash: 9890426532f35eb3a80fe773d887714fe27d13ea125ad7e90beab16a51b74496
EOF
CMDS=<<EOF
@ -514,7 +514,7 @@ foobar:
realname: main
refs: sym.print
vars: b-4, b-16, r110, r114
types: int, char **, int64_t
types: func.main.ret=int, func.main.args=2, func.main.arg.0="int,argc", func.main.arg.1="char **,argv"
bbhash: 9890426532f35eb3a80fe773d887714fe27d13ea125ad7e90beab16a51b74496
EOF
CMDS=<<EOF