Initial support for 'an' aka no-return analysis points

This commit is contained in:
pancake 2015-11-12 13:47:44 +01:00
parent c0da7a1c9e
commit d91df64286
6 changed files with 167 additions and 1 deletions

View File

@ -75,6 +75,7 @@ R_API RAnal *r_anal_new() {
RAnal *anal = R_NEW0 (RAnal);
if (!anal) return NULL;
anal->os = strdup (R_SYS_OS);
anal->noreturn = r_list_newf ((RListFree)&r_anal_noreturn_free);
anal->reflines = anal->reflines2 = NULL;
anal->esil_goto_limit = R_ANAL_ESIL_GOTO_LIMIT;
anal->limit = NULL;
@ -132,6 +133,7 @@ R_API RAnal *r_anal_free(RAnal *a) {
/* TODO: Free anals here */
R_FREE (a->cpu);
r_list_free (a->plugins);
r_list_free (a->noreturn);
a->fcns->free = r_anal_fcn_free;
r_list_free (a->fcns);
r_space_fini (&a->meta_spaces);
@ -404,3 +406,93 @@ R_API int r_anal_archinfo(RAnal *anal, int query) {
}
return -1;
}
R_API void r_anal_noreturn_free(RAnalNoreturn *nr) {
free (nr->name);
free (nr);
}
R_API void r_anal_noreturn_list(RAnal *anal, int mode) {
RListIter *iter;
RAnalNoreturn *nr;
r_list_foreach (anal->noreturn, iter, nr) {
switch (mode) {
case 1:
case '*':
case 'r':
if (nr->name) anal->cb_printf ("ann %s\n", nr->name);
else anal->cb_printf ("0x%08"PFMT64x"\n", nr->addr);
break;
default:
if (nr->name) anal->cb_printf ("%s\n", nr->name);
else anal->cb_printf ("0x%08"PFMT64x"\n", nr->addr);
break;
}
}
}
R_API bool r_anal_noreturn_add(RAnal *anal, const char *name, ut64 addr) {
RAnalNoreturn *nr = R_NEW0(RAnalNoreturn);
if (!nr) return false;
if (name && *name) nr->name = strdup (name);
nr->addr = addr;
if (!nr->name && !nr->addr) {
free (nr);
return false;
}
r_list_append (anal->noreturn, nr);
return true;
}
R_API int r_anal_noreturn_drop(RAnal *anal, const char *expr) {
bool ret = false;
if (!strcmp (expr, "*")) {
if (!r_list_empty (anal->noreturn)) {
r_list_free (anal->noreturn);
anal->noreturn = r_list_newf ((RListFree)&r_anal_noreturn_free);
ret = true;
}
} else {
RListIter *iter, *iter2;
RAnalNoreturn *nr;
if (!strncmp (expr, "0x", 2)) {
ut64 n = r_num_math (NULL, expr);
r_list_foreach_safe (anal->noreturn, iter, iter2, nr) {
if (nr->addr == n) {
r_list_delete (anal->noreturn, iter);
ret = true;
}
}
} else {
r_list_foreach_safe (anal->noreturn, iter, iter2, nr) {
if (r_str_glob (nr->name, expr)) {
r_list_delete (anal->noreturn, iter);
ret = true;
}
}
}
}
return ret;
}
R_API bool r_anal_noreturn_at(RAnal *anal, ut64 addr) {
RListIter *iter;
RAnalNoreturn *nr;
RAnalFunction *f = r_anal_get_fcn_at (anal, addr, 0);
RFlagItem *fi = anal->flb.get_at (anal->flb.f, addr);
r_list_foreach (anal->noreturn, iter, nr) {
if (nr->name) {
RFlagItem *fi2 = anal->flb.get (anal->flb.f, nr->name);
if (fi2 && fi2->offset == addr)
return true;
if (f && !strcmp (f->name, nr->name))
return true;
if (fi && fi->name && !strcmp (fi->name, nr->name))
return true;
} else {
if (addr == nr->addr)
return true;
}
}
return false;
}

View File

@ -448,6 +448,11 @@ repeat:
}
break;
case R_ANAL_OP_TYPE_JMP:
if (r_anal_noreturn_at (anal, op.jump)) {
FITFCNSZ ();
r_anal_op_fini (&op);
return R_ANAL_RET_END;
}
if (anal->opt.eobjmp) {
FITFCNSZ();
op.jump = UT64_MAX;
@ -583,6 +588,11 @@ repeat:
break;
case R_ANAL_OP_TYPE_CCALL:
case R_ANAL_OP_TYPE_CALL:
if (r_anal_noreturn_at (anal, op.jump)) {
FITFCNSZ ();
r_anal_op_fini (&op);
return R_ANAL_RET_END;
}
(void)r_anal_fcn_xref_add (anal, fcn, op.addr, op.jump, R_ANAL_REF_TYPE_CALL);
#if CALL_IS_EOB
recurseAt (op.jump);

View File

@ -1991,6 +1991,52 @@ static void cmd_anal_esil(RCore *core, const char *input) {
}
}
static void cmd_anal_noreturn(RCore *core, const char *input) {
const char* help_msg[] = {
"Usage:", "an [-][0xaddr|symname]", " manage no-return marks",
"an[a]", " 0x3000", "stop function analysis if call/jmp to this address",
"an[n]", " sym.imp.exit", "same as above but for flag/fcn names",
"an", "-*", "remove all no-return references",
"an", "", "list them all",
"ao*", "", "display opcode in r commands",
NULL};
switch (input[0]) {
case '-':
r_anal_noreturn_drop (core->anal, input+1);
break;
case ' ':
if (input[1] == '0' && input[2] == 'x') {
r_anal_noreturn_add (core->anal, NULL,
r_num_math (core->num, input+1));
} else {
r_anal_noreturn_add (core->anal, input+1,
r_num_math (core->num, input+1));
}
break;
case 'a':
if (input[1] == ' ') {
r_anal_noreturn_add (core->anal, NULL,
r_num_math (core->num, input+1));
} else r_core_cmd_help (core, help_msg);
break;
case 'n':
if (input[1] == ' ') {
} else r_core_cmd_help (core, help_msg);
break;
case '*':
case 'r':
r_anal_noreturn_list (core->anal, 1);
break;
case 0:
r_anal_noreturn_list (core->anal, 0);
break;
default:
case '?':
r_core_cmd_help (core, help_msg);
break;
}
}
static void cmd_anal_opcode(RCore *core, const char *input) {
int l, len = core->blocksize;
ut32 tbs = core->blocksize;
@ -3099,6 +3145,7 @@ static int cmd_anal(void *data, const char *input) {
"ah", "[?lba-]", "analysis hints (force opcode size, ...)",
"ai", " [addr]", "address information (show perms, stack, heap, ...)",
"ao", "[e?] [len]", "analyze Opcodes (or emulate it)",
"an", "[an-] [...]", "manage no-return addresses/symbols/functions",
"ar", "", "like 'dr' but for the esil vm. (registers)",
"ax", "[?ld-*]", "manage refs/xrefs (see also afx?)",
"as", " [num]", "analyze syscall using dbg.reg",
@ -3123,6 +3170,7 @@ static int cmd_anal(void *data, const char *input) {
case 'r': cmd_anal_reg (core, input+1); break; // "ar"
case 'e': cmd_anal_esil (core, input+1); break; // "ae"
case 'o': cmd_anal_opcode (core, input+1); break;
case 'n': cmd_anal_noreturn (core, input+1); break; // "an"
case 'F':
r_core_anal_fcn (core, core->offset, UT64_MAX, R_ANAL_REF_TYPE_NULL, 1);
break;

View File

@ -622,6 +622,7 @@ R_API const char *r_flag_color(RFlag *f, RFlagItem *it, const char *color) {
R_API int r_flag_bind (RFlag *f, RFlagBind *fb) {
fb->f = f;
fb->get = r_flag_get;
fb->get_at = r_flag_get_at;
fb->set = r_flag_set;
fb->set_fs = r_flag_space_set;
return 0;

View File

@ -634,6 +634,7 @@ typedef struct r_anal_t {
RAnalOptions opt;
RList *reflines;
RList *reflines2;
RList *noreturn;
} RAnal;
typedef struct r_anal_hint_t {
@ -927,7 +928,13 @@ typedef struct r_anal_reil {
char pc[8];
} RAnalReil;
#define ESIL_INTERNAL_PREFIX '$' //must be a char
typedef struct r_anal_noreturn_t {
char *name;
ut64 addr;
} RAnalNoreturn;
// must be a char
#define ESIL_INTERNAL_PREFIX '$'
#define ESIL struct r_anal_esil_t
typedef struct r_anal_esil_callbacks_t {
@ -1476,6 +1483,12 @@ R_API void r_anal_unset_limits(RAnal *anal);
/* ESIL to REIL */
R_API int r_anal_esil_to_reil_setup (RAnalEsil *esil, RAnal *anal, int romem, int stats);
/* no-return stuff */
R_API void r_anal_noreturn_list(RAnal *anal, int mode);
R_API void r_anal_noreturn_free(RAnalNoreturn *nr);
R_API bool r_anal_noreturn_add(RAnal *anal, const char *name, ut64 addr);
R_API int r_anal_noreturn_drop(RAnal *anal, const char *expr);
/* plugin pointers */
extern RAnalPlugin r_anal_plugin_null;
extern RAnalPlugin r_anal_plugin_csr;

View File

@ -60,6 +60,7 @@ typedef struct r_flag_t {
#include <r_flags.h> // compile time line, no linkage needed
typedef RFlagItem* (*RFlagGet)(RFlag *f, const char *name);
typedef RFlagItem* (*RFlagGetAt)(RFlag *f, ut64 addr);
typedef RFlagItem* (*RFlagSet)(RFlag *f, const char *name, ut64 addr, ut32 size, int dup);
typedef int (*RFlagSetSpace)(RFlag *f, const char *name);
@ -67,6 +68,7 @@ typedef struct r_flag_bind_t {
int init;
RFlag *f;
RFlagGet get;
RFlagGetAt get_at;
RFlagSet set;
RFlagSetSpace set_fs;
} RFlagBind;