* Initial working basic block conditional decompilation

- Only 'test' opcode for x86 is currently supported (just for testing)
  - analysis backend generates RAnalValue's for each argument
  - compiles a cmp+cjmp into a RAnalCond class
  - de/serializes the RAnalCond into an evaluable string
  - Make anal api more stable
* Fix a memory leak in anal_bb
* Reassign anal->reg into dbg->reg
  - Replicate dbg->reg into dbg->anal->reg
  - Such nasty cascade assignation..
This commit is contained in:
pancake 2010-06-16 21:44:19 +02:00
parent a580ff4fa8
commit e36ef11025
13 changed files with 117 additions and 91 deletions

View File

@ -11,7 +11,7 @@ foo: pre libr_anal.${EXT_SO} libr_anal.${EXT_AR} plugins
include ${STATIC_ANAL_PLUGINS}
#STATIC_OBJS=$(subst ..,p/..,$(subst anal_,p/anal_,$(STATIC_OBJ)))
STATIC_OBJS=$(subst ../ar,p/../ar,$(subst anal_,p/anal_,$(STATIC_OBJ)))
OBJ=${STATIC_OBJS} ctx.o reflines.o ref.o aop.o fcn.o bb.o var.o anal.o cond.o
OBJ=${STATIC_OBJS} ctx.o reflines.o ref.o aop.o fcn.o bb.o var.o anal.o cond.o value.o
pre:
if [ ! -e libr_anal.${EXT_SO} ]; then rm -f ${STATIC_OBJS} ; fi

View File

@ -7,9 +7,7 @@
#include <r_list.h>
R_API RAnalOp *r_anal_aop_new() {
RAnalOp *aop;
aop = R_NEW (RAnalOp);
RAnalOp *aop = R_NEW (RAnalOp);
if (aop) {
memset (aop, 0, sizeof (RAnalOp));
aop->mnemonic = NULL;
@ -26,10 +24,16 @@ R_API RList *r_anal_aop_list_new() {
return list;
}
R_API void r_anal_aop_free(void *aop) {
if (aop)
free (((RAnalOp*)aop)->mnemonic);
free (aop);
R_API void r_anal_aop_free(void *_aop) {
if (_aop) {
RAnalOp *aop = _aop;
r_anal_value_free (aop->src[0]);
r_anal_value_free (aop->src[1]);
r_anal_value_free (aop->src[2]);
r_anal_value_free (aop->dst);
free (aop->mnemonic);
free (aop);
}
}
R_API int r_anal_aop(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {

View File

@ -42,7 +42,7 @@ R_API void r_anal_bb_free(void *_bb) {
}
R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len, int head) {
RAnalOp *aop;
RAnalOp *aop = NULL;
int oplen, idx = 0;
if (bb->addr == -1)
@ -65,13 +65,7 @@ R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len,
if (head) bb->type = R_ANAL_BB_TYPE_HEAD;
switch (aop->type) {
case R_ANAL_OP_TYPE_CMP:
bb->cond = r_anal_cond_new ();
// TODO fill conditional information
//bb->cond->type = 0; // UNKNOWN
bb->cond->arg[0] = r_anal_value_new_from_aop(aop, 0);
bb->cond->arg[1] = r_anal_value_new_from_aop(aop, 1);
// bb->src = { 0,0,0,0,0 }
// bb->dst = { 0,0,0,0,0 }
bb->cond = r_anal_cond_new_from_aop (aop);
break;
case R_ANAL_OP_TYPE_CJMP:
if (bb->cond) {
@ -81,18 +75,23 @@ R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len,
bb->fail = aop->fail;
bb->jump = aop->jump;
bb->type |= R_ANAL_BB_TYPE_BODY;
r_anal_aop_free (aop);
return R_ANAL_RET_END;
case R_ANAL_OP_TYPE_JMP:
bb->jump = aop->jump;
bb->type |= R_ANAL_BB_TYPE_BODY;
r_anal_aop_free (aop);
return R_ANAL_RET_END;
case R_ANAL_OP_TYPE_UJMP:
bb->type |= R_ANAL_BB_TYPE_FOOT;
r_anal_aop_free (aop);
return R_ANAL_RET_END;
case R_ANAL_OP_TYPE_RET:
bb->type |= R_ANAL_BB_TYPE_LAST;
r_anal_aop_free (aop);
return R_ANAL_RET_END;
}
r_anal_aop_free (aop);
}
return bb->size;
}

View File

@ -47,6 +47,19 @@ R_API char *r_anal_cond_to_string(RAnalCond *cond) {
return out;
}
R_API RAnalCond *r_anal_cond_new_from_aop(RAnalOp *op) {
RAnalCond *cond;
if (!(cond = r_anal_cond_new()))
return NULL;
//v->reg[0] = op->src[0];
//v->reg[1] = op->src[1];
cond->arg[0] = op->src[0];
op->src[0] = NULL;
// TODO: moar!
//cond->arg[1] = op->src[1];
return cond;
}
R_API RAnalCond *r_anal_cond_new_from_string(const char *str) {
RAnalCond *cond = R_NEW (RAnalCond);
// TODO: find '<','=','>','!'...

View File

@ -114,11 +114,20 @@ static int aop(RAnal *anal, RAnalOp *aop, ut64 addr, const ut8 *data, int len) {
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
int src = buf[1]&7;
int dst = (buf[1]&0x38)>>3;
aop->src[0] = r_reg_get (anal->reg, testregs[src%8], R_REG_TYPE_GPR);
aop->src[1] = r_reg_get (anal->reg, testregs[dst%8], R_REG_TYPE_GPR);
if (aop->src[0] == aop->src[1])
aop->src[0] = r_anal_value_new ();
aop->src[0]->reg = r_reg_get (anal->reg, testregs[src%8], R_REG_TYPE_GPR);
aop->src[1] = r_anal_value_new ();
aop->src[1]->reg = r_reg_get (anal->reg, testregs[dst%8], R_REG_TYPE_GPR);
aop->src[2] = NULL;
//eprintf ("REGZ (%s)\n", anal->reg);
//eprintf ("REG IZ: (%s)\n", testregs[src%8]);
//eprintf ("REG IZ: %p (%s)\n", aop->src[0], aop->src[0]->reg->name);
if (aop->src[0]->reg == aop->src[1]->reg) {
//eprintf ("fruity\n");
r_anal_value_free (aop->src[1]);
aop->src[1] = NULL;
// eprintf ("0x%"PFMT64x": (%02x) %d %d\n", addr, buf[1], src, dst);
}
//eprintf ("0x%"PFMT64x": (%02x) %d %d\n", addr, buf[1], src, dst);
} else if (buf[1]<0xc0) { // test [eax+delta], eax
/* not yet supported */
}

View File

@ -22,25 +22,21 @@ R_API void r_anal_value_free(RAnalValue *value) {
R_API st64 r_anal_value_eval(RAnalValue *value) {
/* OMFG TODO.. this is done by r_num_shit */
// r_num_math (anal->num, ...);
#warning TODO r_anal_value_eval
return 0LL;
}
R_API char *r_anal_value_to_string (RAnalValue *value) {
char *out = r_str_new ("");
if (value->memref) out = r_str_concat (out, "[");
if (value->mul) out = r_str_concatf (out, "%d*", value->mul);
if (value->regbase) out = r_str_concatf (out, "%s+", value->regbase->name);
if (value->regdelta) out = r_str_concatf (out, "%s+", value->regdelta->name);
if (value->base!=0) out = r_str_concatf (out, "0x%"PFMT64x, value->base);
if (value->delta>0) out = r_str_concatf (out, "+%d", value->delta);
else if (value->delta<0) out = r_str_concatf (out, "%d", value->delta);
if (value->memref) out = r_str_concat (out, "]");
if (value) {
if (value->memref) out = r_str_concat (out, "[");
if (value->mul) out = r_str_concatf (out, "%d*", value->mul);
if (value->reg) out = r_str_concatf (out, "%s", value->reg->name);
if (value->regdelta) out = r_str_concatf (out, "+%s", value->regdelta->name);
if (value->base!=0) out = r_str_concatf (out, "0x%"PFMT64x, value->base);
if (value->delta>0) out = r_str_concatf (out, "+%d", value->delta);
else if (value->delta<0) out = r_str_concatf (out, "%d", value->delta);
if (value->memref) out = r_str_concat (out, "]");
}
return out;
}
R_API RAnalValue *r_anal_value_new_from_aop(RAnalOp *op, int idx) {
RAnalValue *v = R_NEW (RAnalValue);
if (idx<0 || idx> sizeof(op->arg) || !op->arg[idx])
return NULL;
TODO
return v;
}

View File

@ -36,22 +36,22 @@ static char *r_core_anal_graph_label(RCore *core, struct r_anal_bb_t *bb, int op
return NULL;
for(i=j=0;cmdstr[i];i++,j++) {
switch(cmdstr[i]) {
case 0x1b:
/* skip ansi chars */
for(i++;cmdstr[i]&&cmdstr[i]!='m'&&cmdstr[i]!='H'&&cmdstr[i]!='J';i++);
j--;
break;
case '"':
str[j]='\\';
str[++j]='"';
break;
case '\n':
case '\r':
str[j]='\\';
str[++j]='l';
break;
default:
str[j]=cmdstr[i];
case 0x1b:
/* skip ansi chars */
for(i++;cmdstr[i]&&cmdstr[i]!='m'&&cmdstr[i]!='H'&&cmdstr[i]!='J';i++);
j--;
break;
case '"':
str[j]='\\';
str[++j]='"';
break;
case '\n':
case '\r':
str[j]='\\';
str[++j]='l';
break;
default:
str[j]=cmdstr[i];
}
}
str[j]='\0';
@ -170,9 +170,7 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
r_cons_printf ("0x%08"PFMT64x" ", bbi->jump);
r_cons_printf ("0x%08"PFMT64x" ", bbi->fail);
if (bbi->type == R_ANAL_BB_TYPE_NULL)
r_cons_printf ("n");
else {
if (bbi->type != R_ANAL_BB_TYPE_NULL) {
if ((bbi->type & R_ANAL_BB_TYPE_BODY))
r_cons_printf ("b");
if ((bbi->type & R_ANAL_BB_TYPE_FOOT))
@ -181,7 +179,7 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
r_cons_printf ("h");
if ((bbi->type & R_ANAL_BB_TYPE_LAST))
r_cons_printf ("l");
}
} else r_cons_printf ("n");
if ((bbi->diff == R_ANAL_DIFF_MATCH))
r_cons_printf (" m");
@ -216,7 +214,9 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
else if ((bbi->diff == R_ANAL_DIFF_UNMATCH))
r_cons_printf ("unmatch");
else r_cons_printf ("new");
r_cons_printf ("\n");
r_cons_printf (" cond=\"%s\"\n", bbi->cond?
r_anal_cond_to_string (bbi->cond):"none");
}
}
r_cons_flush ();
@ -226,7 +226,6 @@ R_API int r_core_anal_bb_list(RCore *core, int rad) {
R_API int r_core_anal_bb_seek(RCore *core, ut64 addr) {
struct r_anal_bb_t *bbi;
RListIter *iter;
r_list_foreach (core->anal->bbs, iter, bbi)
if (addr >= bbi->addr && addr < bbi->addr+bbi->size)
return r_core_seek (core, bbi->addr, R_FALSE);
@ -252,7 +251,7 @@ R_API int r_core_anal_fcn(RCore *core, ut64 at, ut64 from, int depth) {
if (from == refi->addr)
return R_FALSE;
}
if (!(ref = r_anal_ref_new())) {
if (!(ref = r_anal_ref_new ())) {
eprintf ("Error: new (xref)\n");
return R_ANAL_RET_ERROR;
}
@ -338,10 +337,7 @@ R_API int r_core_anal_fcn_list(RCore *core, int rad) {
RListIter *iter, *iter2;
r_list_foreach (core->anal->fcns, iter, fcni)
if (rad) {
r_cons_printf ("af+ 0x%08"PFMT64x" %"PFMT64d" %s (%c)\n",
fcni->addr, fcni->size, fcni->name, fcni->diff?fcni->diff:'n');
} else {
if (!rad) {
r_cons_printf ("[0x%08"PFMT64x"] size=%"PFMT64d" name=%s",
fcni->addr, fcni->size, fcni->name);
r_cons_printf (" diff=%s", fcni->diff=='m'?"match": fcni->diff=='u'?"unmatch": "new");
@ -359,7 +355,8 @@ R_API int r_core_anal_fcn_list(RCore *core, int rad) {
r_anal_var_type_to_str (core->anal, vari->type));
}
r_cons_newline ();
}
} else r_cons_printf ("af+ 0x%08"PFMT64x" %"PFMT64d" %s (%c)\n",
fcni->addr, fcni->size, fcni->name, fcni->diff?fcni->diff:'n');
r_cons_flush ();
return R_TRUE;
}
@ -392,7 +389,6 @@ R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts) {
R_API int r_core_anal_graph_fcn(RCore *core, char *fname, int opts) {
RListIter *iter;
RAnalFcn *fcni;
r_list_foreach (core->anal->fcns, iter, fcni)
if (!strcmp (fname, fcni->name))
return r_core_anal_graph (core, fcni->addr, opts);

View File

@ -149,8 +149,8 @@ static void r_print_disasm(RPrint *p, RCore *core, ut64 addr, ut8 *buf, int len,
stackptr += analop.stackptr;
}
if (show_bytes) {
char pad[64];
char *str, *extra = " ";
char *str, pad[64];
const char *extra = " ";
if (!flag) {
str = strdup (asmop.buf_hex);
if (strlen (str) > nb) {
@ -499,6 +499,7 @@ static void cmd_reg(RCore *core, const char *str) {
r_cons_printf ("%s\n", core->dbg->reg_profile);
else eprintf ("No register profile defined. Try 'dr.'\n");
} else r_reg_set_profile (core->dbg->reg, str+2);
core->anal->reg = core->dbg->reg;
break;
case 't':
for (i=0; (name=r_reg_get_type (i));i++)

View File

@ -114,7 +114,7 @@ static int config_asm_bits_callback(void *user, void *data) {
RConfigNode *node = (RConfigNode *) data;
int ret = r_asm_set_bits (core->assembler, node->i_value);
if (ret == R_FALSE) {
struct r_asm_plugin_t *h = core->assembler->cur;
RAsmPlugin *h = core->assembler->cur;
if (h) {
eprintf ("Cannot set bits %"PFMT64d" to '%s'\n",
node->i_value, h->name);

View File

@ -7,6 +7,7 @@ static ut64 num_callback(RNum *userptr, const char *str, int *ok) {
RCore *core = (RCore *)userptr; // XXX ?
RFlagItem *flag;
RAnalOp aop;
ut64 ret;
if (str[0]=='$') {
/* analyze opcode */
@ -46,11 +47,11 @@ static ut64 num_callback(RNum *userptr, const char *str, int *ok) {
case '?': return core->num->value;
}
}
flag = r_flag_get (core->flags, str);
if (flag) *ok = R_TRUE;
else *ok = R_FALSE;
return (flag)?flag->offset:0LL;
if ( (flag = r_flag_get (core->flags, str)) ) {
ret = flag->offset;
*ok = R_TRUE;
} else *ok = ret = 0;
return ret;
}
R_API RCore *r_core_new() {
@ -158,7 +159,7 @@ R_API int r_core_init(RCore *core) {
core->flags = r_flag_new ();
core->dbg = r_debug_new (R_TRUE);
core->dbg->anal = core->anal; // XXX: dupped instance.. can cause lost pointerz
core->dbg->anal->reg = core->anal->reg; // XXX: dupped instance.. can cause lost pointerz
// core->dbg->anal->reg = core->anal->reg; // XXX: dupped instance.. can cause lost pointerz
core->sign->printf = r_cons_printf;
core->io->printf = r_cons_printf;
core->dbg->printf = r_cons_printf;

View File

@ -33,6 +33,7 @@ R_API int r_debug_use(RDebug *dbg, const char *str) {
if (h->reg_profile) {
free (dbg->reg_profile);
dbg->reg_profile = dbg->h->reg_profile ();
dbg->anal->reg = dbg->reg;
r_reg_set_profile_string (dbg->reg, dbg->reg_profile);
}
return R_TRUE;

View File

@ -132,6 +132,17 @@ typedef struct r_anal_t {
struct list_head anals; // XXX: use RList here
} RAnal;
// mul*value+regbase+regidx+delta
typedef struct r_anal_value_t {
int memref; // is memory reference? or value?
ut64 base ; // numeric address
int delta; // numeric delta
int mul; // multiplier (reg*4+base)
// TODO: add multiplier
RRegisterItem *reg; // register index used (-1 if no reg)
RRegisterItem *regdelta; // register index used (-1 if no reg)
} RAnalValue;
typedef struct r_anal_aop_t {
char *mnemonic; /* mnemonic */
ut64 addr; /* address */
@ -147,23 +158,11 @@ typedef struct r_anal_aop_t {
st64 ref; /* reference to memory */ /* XXX signed? */
ut64 value; /* reference to value */ /* XXX signed? */
st64 stackptr; /* stack pointer */
RRegisterItem *src[3];
RRegisterItem *dst;
RAnalValue *src[3];
RAnalValue *dst;
int refptr;
} RAnalOp;
//mov 0x8175780(,%eax,4),%eax
// value+regbase+regidx+delta
typedef struct r_anal_value_t {
int memref; // is memory reference? or value?
ut64 base ; // numeric address
int delta; // numeric delta
int mul; // multiplier (reg*4+base)
// TODO: add multiplier
RRegisterItem *regbase; // register index used (-1 if no reg)
RRegisterItem *regdelta; // register index used (-1 if no reg)
} RAnalValue;
#define R_ANAL_COND_SINGLE(x) (!x->arg[1] || x->arg[0]==x->arg[1])
typedef struct r_anal_cond_t {
@ -314,7 +313,14 @@ R_API int r_anal_var_access_add(RAnal *anal, RAnalVar *var, ut64 from, int set);
R_API int r_anal_var_access_del(RAnal *anal, RAnalVar *var, ut64 from);
R_API RAnalVarAccess *r_anal_var_access_get(RAnal *anal, RAnalVar *var, ut64 from);
R_API RAnalValue *r_anal_value_new();
R_API RAnalValue *r_anal_value_new_from_string(const char *str);
R_API st64 r_anal_value_eval(RAnalValue *value);
R_API char *r_anal_value_to_string (RAnalValue *value);
R_API void r_anal_value_free(RAnalValue *value);
R_API RAnalCond *r_anal_cond_new();
R_API RAnalCond *r_anal_cond_new_from_aop(RAnalOp *op);
#define r_anal_cond_free(x) free(x);
R_API int r_anal_cond_eval(RAnalCond *cond);
R_API char *r_anal_cond_to_string(RAnalCond *cond);

View File

@ -176,11 +176,11 @@ static void emit_while_end (const char *labelback) {
#if SYNTAX_ATT
rcc_printf (" pop %%"R_AX"\n");
rcc_printf (" cmp $0, %%"R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
rcc_printf (" jnz %s\n", labelback);
rcc_printf (" bne %s\n", labelback);
#else
rcc_printf (" pop "R_AX"\n");
rcc_printf (" test "R_AX", "R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
rcc_printf (" jnz %s\n", labelback);
rcc_printf (" cmp "R_AX", $0\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
rcc_printf (" bne %s\n", labelback);
#endif
}