Initial support for analyzing and graphing generic switch tables

This commit is contained in:
pancake 2016-12-29 03:34:16 +01:00
parent 96dbf57b30
commit dc0e8ff820
4 changed files with 104 additions and 16 deletions

View File

@ -111,16 +111,15 @@ R_API void r_anal_ex_clone_op_switch_to_bb (RAnalBlock *bb, RAnalOp *op) {
RListIter *iter;
RAnalCaseOp *caseop = NULL;
if (op->switch_op) {
if (!op->switch_op) {
bb->switch_op = r_anal_switch_op_new (op->switch_op->addr,
op->switch_op->min_val,
op->switch_op->max_val);
if (bb->switch_op){
r_list_foreach (op->switch_op->cases, iter, caseop) {
r_anal_switch_op_add_case (bb->switch_op, caseop->addr,
caseop->value, caseop->jump);
}
op->switch_op->min_val,
op->switch_op->max_val);
}
if (bb->switch_op) {
r_list_foreach (op->switch_op->cases, iter, caseop) {
r_anal_switch_op_add_case (bb->switch_op, caseop->addr,
caseop->value, caseop->jump);
}
}
}

View File

@ -473,6 +473,48 @@ static int skip_hp(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, RAnalBlock *bb,
return 0;
}
R_API int r_anal_case(RAnal *anal, RAnalFunction *fcn, ut64 addr_bbsw, ut64 addr, ut8 *buf, ut64 len, int reftype) {
RAnalOp op = {0};
int oplen, idx = 0;
while (idx < len) {
if ((len - idx) < 5) {
break;
}
r_anal_op_fini (&op);
if ((oplen = r_anal_op (anal, &op, addr + idx, buf + idx, len - idx)) < 1) {
return 0;
}
switch (op.type) {
case R_ANAL_OP_TYPE_TRAP:
case R_ANAL_OP_TYPE_RET:
case R_ANAL_OP_TYPE_JMP:
// eprintf ("CASE AT 0x%llx size %d\n", addr, idx + oplen);
anal->cb_printf ("afb+ 0x%"PFMT64x" 0x%"PFMT64x" %d\n",
fcn->addr, addr, idx + oplen);
anal->cb_printf ("afbe 0x%"PFMT64x" 0x%"PFMT64x"\n",
addr_bbsw, addr);
return idx + oplen;
}
idx += oplen;
}
return idx;
}
static int walk_switch(RAnal *anal, RAnalFunction *fcn, ut64 from, ut64 at) {
ut8 buf[1024];
int i;
eprintf ("WALK SWITCH TABLE INTO (0x%llx) %llx\n", from, at);
for (i = 0; i < 10; i++) {
anal->iob.read_at (anal->iob.io, at, buf, sizeof (buf));
int sz = r_anal_case (anal, fcn, from, at, buf, sizeof (buf), 0);
if (sz < 1) {
break;
}
at += sz;
}
return 0;
}
static int fcn_recurse(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut8 *buf, ut64 len, int depth) {
int continue_after_jump = anal->opt.afterjmp;
int noncode = anal->opt.noncode;
@ -882,10 +924,10 @@ repeat:
return R_ANAL_RET_END;
#if JMP_IS_EOB_RANGE > 0
} else {
if (op.jump < addr-JMP_IS_EOB_RANGE && op.jump<addr) {
if (op.jump < addr - JMP_IS_EOB_RANGE && op.jump<addr) {
gotoBeach (R_ANAL_RET_END);
}
if (op.jump > addr+JMP_IS_EOB_RANGE) {
if (op.jump > addr + JMP_IS_EOB_RANGE) {
gotoBeach (R_ANAL_RET_END);
}
#endif
@ -966,8 +1008,9 @@ repeat:
}
}
}
walk_switch (anal, fcn, op.addr, op.addr + op.size);
}
if (anal->cur) {
if (anal->cur) {
/* if UJMP is in .plt section just skip it */
RIOSection *s = anal->iob.section_vget (anal->iob.io, addr);
if (s && s->name) {
@ -977,7 +1020,9 @@ repeat:
if (!in_plt) goto river;
}
} else {
if (in_plt) goto river;
if (in_plt) {
goto river;
}
}
}
}

View File

@ -833,6 +833,35 @@ static int anal_fcn_list_bb(RCore *core, const char *input) {
return true;
}
static bool anal_bb_edge (RCore *core, const char *input) {
// "afbe" switch-bb-addr case-bb-addr
char *arg = strdup (r_str_chop_ro(input));
char *sp = strchr (arg, ' ');
if (sp) {
*sp++ = 0;
ut64 sw_at = r_num_math (core->num, arg);
ut64 cs_at = r_num_math (core->num, sp);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, sw_at, 0);
if (fcn) {
RAnalBlock *bb;
RListIter *iter;
r_list_foreach (fcn->bbs, iter, bb) {
if (sw_at >= bb->addr && sw_at < (bb->addr + bb->size)) {
if (!bb->switch_op) {
bb->switch_op = r_anal_switch_op_new (
sw_at, 0, 0);
}
r_anal_switch_op_add_case (bb->switch_op, cs_at, 0, cs_at);
}
}
free (arg);
return true;
}
}
free (arg);
return false;
}
static bool anal_fcn_del_bb(RCore *core, const char *input) {
ut64 addr = r_num_math (core->num, input);
if (!addr) {
@ -1057,10 +1086,12 @@ static void r_core_anal_fmap (RCore *core, const char *input) {
}
static bool fcnNeedsPrefix(const char *name) {
if (!strncmp (name, "entry", 5))
if (!strncmp (name, "entry", 5)) {
return false;
if (!strncmp (name, "main", 4))
}
if (!strncmp (name, "main", 4)) {
return false;
}
return (!strchr (name, '.'));
}
@ -1373,7 +1404,10 @@ static int cmd_anal_fcn(RCore *core, const char *input) {
case 'b': // "afb"
switch (input[2]) {
case '-':
anal_fcn_del_bb (core, input +3);
anal_fcn_del_bb (core, input + 3);
break;
case 'e':
anal_bb_edge (core, input + 3);
break;
case 0:
case ' ':

View File

@ -1800,6 +1800,16 @@ static int get_bbnodes(RAGraph *g, RCore *core, RAnalFunction *fcn) {
free (title);
r_agraph_add_edge (g, u, v);
}
if (bb->switch_op) {
RListIter *it;
RAnalCaseOp *cop;
r_list_foreach (bb->switch_op->cases, it, cop) {
title = get_title (cop->addr);
v = r_agraph_get_node (g, title);
free (title);
r_agraph_add_edge (g, u, v);
}
}
}
ret = true;