2017-02-09 23:02:39 +00:00
|
|
|
/* radare - LGPL - Copyright 2017 - pancake */
|
|
|
|
|
|
|
|
/* blaze is the codename for the new analysis engine for radare2 */
|
|
|
|
/* by --pancake thanks to @defragger and @nguyen for ideas */
|
|
|
|
|
|
|
|
#include <r_core.h>
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ut64 addr;
|
|
|
|
ut64 len;
|
|
|
|
ut8 *buf;
|
|
|
|
ut64 bb_addr;
|
|
|
|
RList *bbs;
|
|
|
|
RList *nextbbs;
|
|
|
|
RList *fcnents;
|
|
|
|
Sdb *bbdb; /* bbaddr=bbsize */
|
|
|
|
Sdb *fcdb; /* fcnaddr */
|
|
|
|
ut64 last;
|
|
|
|
bool wasPad;
|
|
|
|
RCore *core;
|
|
|
|
} AbbState;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ut64 addr;
|
|
|
|
int bits;
|
|
|
|
int type;
|
|
|
|
char *name;
|
|
|
|
} AbbAddr;
|
|
|
|
|
|
|
|
static int bbExist(AbbState *abb, ut64 addr) {
|
|
|
|
RAnalBlock *bb;
|
|
|
|
RListIter *iter;
|
|
|
|
if (abb->bbdb) {
|
2017-02-20 01:54:16 +00:00
|
|
|
return (int) sdb_num_get (abb->bbdb, sdb_fmt (0, "0x%08" PFMT64x, addr), NULL);
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
r_list_foreach (abb->bbs, iter, bb) {
|
|
|
|
if (bb->addr == addr) {
|
|
|
|
return bb->size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-26 22:01:49 +00:00
|
|
|
#if 0
|
2017-02-13 16:14:08 +00:00
|
|
|
static int fcnExist(AbbState *abb, ut64 addr) {
|
2017-02-20 01:54:16 +00:00
|
|
|
AbbAddr *a;
|
2017-02-13 16:14:08 +00:00
|
|
|
RListIter *iter;
|
|
|
|
#if 0
|
|
|
|
if (abb->bbdb) {
|
2017-02-20 01:54:16 +00:00
|
|
|
return (int) sdb_num_get (abb->bbdb, sdb_fmt (0, "fcn.0x%08" PFMT64x, addr), NULL);
|
2017-02-13 16:14:08 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
r_list_foreach (abb->fcnents, iter, a) {
|
|
|
|
if (a->addr == addr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-02-26 22:01:49 +00:00
|
|
|
#endif
|
2017-02-13 16:14:08 +00:00
|
|
|
|
2017-02-10 01:05:58 +00:00
|
|
|
static AbbState *abbstate_new(ut64 len) {
|
2017-02-09 23:02:39 +00:00
|
|
|
ut8 *buf = malloc (len);
|
|
|
|
if (!buf) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
AbbState *abb = R_NEW0 (AbbState);
|
|
|
|
if (!abb) {
|
|
|
|
free (buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
abb->buf = buf;
|
|
|
|
abb->len = len;
|
|
|
|
abb->bbs = r_list_new ();
|
|
|
|
if (!abb->bbs) {
|
|
|
|
free (buf);
|
2017-03-15 11:12:01 +00:00
|
|
|
return NULL;
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
abb->nextbbs = r_list_newf (free);
|
|
|
|
abb->fcnents = r_list_newf (free);
|
|
|
|
abb->bbdb = sdb_new0 ();
|
|
|
|
// TODO: add more boring nullchks
|
|
|
|
return abb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void abbstate_free(AbbState *as) {
|
|
|
|
r_list_free (as->bbs);
|
|
|
|
r_list_free (as->nextbbs);
|
|
|
|
sdb_free (as->bbdb);
|
|
|
|
sdb_free (as->fcdb);
|
|
|
|
free (as->buf);
|
|
|
|
free (as);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool appendNextBB(AbbState *abb, ut64 addr, int bits, int type) {
|
|
|
|
RListIter *iter;
|
|
|
|
// RAnalBlock *bb;
|
|
|
|
AbbAddr *n;
|
2017-02-13 16:14:08 +00:00
|
|
|
if (!addr || addr == UT64_MAX || bbExist (abb, addr)) {
|
2017-02-09 23:02:39 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
// XXX slow path use SDB HERE
|
2017-02-09 23:02:39 +00:00
|
|
|
r_list_foreach (abb->nextbbs, iter, n) {
|
|
|
|
if (addr == n->addr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n = R_NEW0 (AbbAddr);
|
|
|
|
n->addr = addr;
|
|
|
|
n->bits = bits;
|
|
|
|
n->type = type;
|
|
|
|
r_list_append (abb->nextbbs, n);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static RAnalBlock *parseOpcode(AbbState *abb, RAnalOp *aop) {
|
2017-02-13 16:14:08 +00:00
|
|
|
RFlagItem *fi = r_flag_get_i (abb->core->flags, aop->addr + aop->size);
|
2017-02-20 01:54:16 +00:00
|
|
|
bool eob = fi? true: false; //strncmp (fi->name, "sym.", 4): false;
|
2017-02-13 16:14:08 +00:00
|
|
|
if (eob) {
|
|
|
|
aop->fail = UT64_MAX;
|
|
|
|
}
|
|
|
|
// eprintf ("0x%llx\n", aop->addr);
|
2017-02-09 23:02:39 +00:00
|
|
|
switch (aop->type) {
|
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
|
|
case R_ANAL_OP_TYPE_NOP:
|
|
|
|
abb->wasPad = true;
|
|
|
|
/* do nothing */
|
|
|
|
return NULL;
|
|
|
|
case R_ANAL_OP_TYPE_SWI:
|
|
|
|
return NULL;
|
|
|
|
case R_ANAL_OP_TYPE_RET:
|
|
|
|
case R_ANAL_OP_TYPE_UJMP:
|
|
|
|
case R_ANAL_OP_TYPE_RJMP:
|
|
|
|
case R_ANAL_OP_TYPE_MJMP:
|
|
|
|
eob = true;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
2017-02-13 16:14:08 +00:00
|
|
|
//eprintf ("CALL 0x%"PFMT64x"\n", aop->addr);
|
2017-02-09 23:02:39 +00:00
|
|
|
if (aop->jump != UT64_MAX) {
|
2017-02-13 16:14:08 +00:00
|
|
|
#if 0
|
|
|
|
RFlagItem *fi = r_flag_get_i (abb->core->flags, aop->jump);
|
|
|
|
if (fi) {
|
|
|
|
if (r_anal_noreturn_at_name (abb->core->anal, fi->name)) {
|
2017-02-20 01:54:16 +00:00
|
|
|
//if (r_anal_noreturn_at_addr (abb->core->anal, aop->jump))
|
2017-02-13 16:14:08 +00:00
|
|
|
eob = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2017-02-09 23:02:39 +00:00
|
|
|
appendNextBB (abb, aop->jump, 0, 'c');
|
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
#if 0
|
|
|
|
if (aop->fail != UT64_MAX && !eob) {
|
2017-02-09 23:02:39 +00:00
|
|
|
appendNextBB (abb, aop->fail, 0, 0);
|
|
|
|
}
|
2017-02-20 01:54:16 +00:00
|
|
|
aop->jump = aop->fail; //UT64_MAX;
|
|
|
|
aop->fail = UT64_MAX;
|
2017-02-13 16:14:08 +00:00
|
|
|
#endif
|
2017-02-09 23:02:39 +00:00
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
|
|
if (aop->jump != UT64_MAX) {
|
|
|
|
appendNextBB (abb, aop->jump, 0, 0);
|
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
if (aop->fail != UT64_MAX && !eob) {
|
2017-02-09 23:02:39 +00:00
|
|
|
appendNextBB (abb, aop->fail, 0, 0);
|
|
|
|
}
|
|
|
|
eob = true;
|
|
|
|
break;
|
2017-02-13 16:14:08 +00:00
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
eob = true;
|
|
|
|
if (aop->jump != UT64_MAX) {
|
|
|
|
appendNextBB (abb, aop->jump, 0, 0);
|
|
|
|
}
|
|
|
|
break;
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
if (abb->wasPad) {
|
|
|
|
abb->wasPad = false;
|
|
|
|
eob = true;
|
|
|
|
}
|
|
|
|
if (eob) {
|
2017-02-13 16:14:08 +00:00
|
|
|
if (aop->addr < abb->bb_addr) {
|
|
|
|
abb->bb_addr = aop->addr;
|
|
|
|
}
|
2017-02-09 23:02:39 +00:00
|
|
|
RAnalBlock *bb = R_NEW0 (RAnalBlock);
|
|
|
|
bb->jump = aop->jump;
|
|
|
|
bb->fail = aop->fail;
|
|
|
|
bb->addr = abb->bb_addr;
|
|
|
|
bb->size = aop->addr - abb->bb_addr + aop->size;
|
2017-02-13 16:14:08 +00:00
|
|
|
if (bb->size < 1) {
|
2017-02-20 01:54:16 +00:00
|
|
|
eprintf ("Invalid block size at 0x%08"PFMT64x "\n", bb->addr);
|
2017-02-13 16:14:08 +00:00
|
|
|
// XXX
|
|
|
|
bb->size = aop->size;
|
|
|
|
}
|
2017-02-09 23:02:39 +00:00
|
|
|
abb->bb_addr = bb->addr + bb->size;
|
|
|
|
return bb;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find functions
|
|
|
|
|
2017-02-10 01:05:58 +00:00
|
|
|
#define F(x, ...) sdb_fmt (0, x, ...)
|
2017-02-09 23:02:39 +00:00
|
|
|
|
|
|
|
static RAnalBlock *getBlock(AbbState *abb, ut64 addr) {
|
2017-02-10 01:05:58 +00:00
|
|
|
return sdb_ptr_get (abb->bbdb, sdb_fmt (0, "ptr.0x%08" PFMT64x, addr), NULL);
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void printBasicBlocks(AbbState *abb, ut64 fcnaddr, ut64 addr) {
|
|
|
|
RAnalBlock *bb = getBlock (abb, addr);
|
|
|
|
if (!bb) {
|
2017-02-10 01:05:58 +00:00
|
|
|
eprintf ("Missing basic block for 0x%08" PFMT64x "\n", addr);
|
2017-02-09 23:02:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-02-10 01:05:58 +00:00
|
|
|
if (sdb_bool_get (abb->bbdb, sdb_fmt (0, "bb.0x%08" PFMT64x ".0x%08" PFMT64x, fcnaddr, addr), NULL)) {
|
2017-02-09 23:02:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-02-10 01:05:58 +00:00
|
|
|
sdb_bool_set (abb->bbdb, sdb_fmt (0, "used.0x%08" PFMT64x, addr), true, 0);
|
|
|
|
sdb_bool_set (abb->bbdb, sdb_fmt (0, "bb.0x%08" PFMT64x ".0x%08" PFMT64x, fcnaddr, addr), true, 0);
|
|
|
|
r_cons_printf ("afb+ 0x%08" PFMT64x " 0x%08" PFMT64x " %d", fcnaddr, bb->addr, bb->size);
|
2017-02-09 23:02:39 +00:00
|
|
|
if (bb->jump != UT64_MAX) {
|
2017-02-20 01:54:16 +00:00
|
|
|
r_cons_printf (" 0x%08" PFMT64x, bb->jump);
|
|
|
|
if (bb->fail != UT64_MAX) {
|
|
|
|
r_cons_printf (" 0x%08" PFMT64x, bb->fail);
|
|
|
|
}
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
2017-02-10 01:05:58 +00:00
|
|
|
r_cons_newline ();
|
2017-02-09 23:02:39 +00:00
|
|
|
if (bb->jump != UT64_MAX) {
|
|
|
|
printBasicBlocks (abb, fcnaddr, bb->jump);
|
|
|
|
}
|
|
|
|
if (bb->fail != UT64_MAX) {
|
|
|
|
printBasicBlocks (abb, fcnaddr, bb->fail);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-24 09:46:13 +00:00
|
|
|
static void printFunction(RCore *core, ut64 addr, const char *name) {
|
|
|
|
const char *pfx = r_config_get (core->config, "anal.fcnprefix");
|
|
|
|
if (!pfx) {
|
|
|
|
pfx = "fcn";
|
|
|
|
}
|
|
|
|
char *_name = name? (char *) name: r_str_newf ("%s.%" PFMT64x, pfx, addr);
|
2017-02-10 01:05:58 +00:00
|
|
|
r_cons_printf ("af+ 0x%08" PFMT64x " %s\n", addr, _name);
|
2017-02-09 23:02:39 +00:00
|
|
|
if (!name) {
|
|
|
|
free (_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void findFunctions(RCore *core, AbbState *abb) {
|
|
|
|
/*
|
|
|
|
we consider functions to be the basic blocks referenced by CALLs
|
|
|
|
*/
|
|
|
|
RListIter *iter;
|
|
|
|
AbbAddr *a;
|
|
|
|
eprintf ("Found %d functions\n", r_list_length (abb->fcnents));
|
|
|
|
r_list_foreach (abb->fcnents, iter, a) {
|
2017-03-24 09:46:13 +00:00
|
|
|
printFunction (core, a->addr, NULL); //a->name);
|
2017-02-09 23:02:39 +00:00
|
|
|
printBasicBlocks (abb, a->addr, a->addr);
|
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
RAnalBlock *bb;
|
|
|
|
r_list_foreach (abb->bbs, iter, bb) {
|
|
|
|
// if there's a flag, consider it a function
|
|
|
|
RFlagItem *fi = r_flag_get_i (core->flags, bb->addr);
|
|
|
|
if (fi) {
|
2017-03-24 09:46:13 +00:00
|
|
|
printFunction (core, bb->addr, fi->name);
|
2017-02-13 16:14:08 +00:00
|
|
|
} else {
|
|
|
|
// eprintf ("# orphan bb 0x%08"PFMT64x"\n", bb->addr);
|
2017-03-24 09:46:13 +00:00
|
|
|
printFunction (core, bb->addr, NULL);
|
2017-02-13 16:14:08 +00:00
|
|
|
}
|
|
|
|
printBasicBlocks (abb, bb->addr, bb->addr);
|
2017-02-20 01:54:16 +00:00
|
|
|
// printFunction (a->addr, a->name);
|
2017-02-13 16:14:08 +00:00
|
|
|
// printBasicBlocks (abb, ->addr, a->addr);
|
|
|
|
}
|
2017-02-09 23:02:39 +00:00
|
|
|
#if 0
|
|
|
|
RAnalBlock *bb;
|
|
|
|
/* false positives ahead */
|
|
|
|
/* mark all non-function bbs as functions */
|
|
|
|
r_cons_printf ("# orphan basic blocks considered function entry points\n");
|
|
|
|
r_list_foreach (abb->bbs, iter, bb) {
|
|
|
|
if (sdb_bool_get (abb->bbdb, sdb_fmt (0, "used.0x%08"PFMT64x, bb->addr), 0)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
printFunction (bb->addr, NULL);
|
|
|
|
printBasicBlocks (abb, bb->addr, bb->addr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-03-30 08:53:40 +00:00
|
|
|
typedef enum bb_type {
|
|
|
|
TRAP,
|
|
|
|
NORMAL,
|
|
|
|
JUMP,
|
|
|
|
FAIL,
|
|
|
|
CALL,
|
|
|
|
} bb_type_t;
|
|
|
|
|
|
|
|
typedef struct bb {
|
|
|
|
ut64 start;
|
|
|
|
ut64 end;
|
|
|
|
ut64 jump;
|
|
|
|
ut64 fail;
|
|
|
|
int score;
|
|
|
|
int called;
|
|
|
|
int reached;
|
|
|
|
bb_type_t type;
|
|
|
|
} bb_t;
|
|
|
|
|
|
|
|
static int bb_cmp (void *_a, void *_b) {
|
|
|
|
bb_t *a = (bb_t*)_a;
|
|
|
|
bb_t *b = (bb_t*)_b;
|
|
|
|
return b->start - a->start;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_bb (bb_t* bb, ut64 start, ut64 end, ut64 jump, ut64 fail, bb_type_t type, int score, int reached, int called) {
|
|
|
|
if (bb) {
|
|
|
|
bb->start = start;
|
|
|
|
bb->end = end;
|
|
|
|
bb->jump = jump;
|
|
|
|
bb->fail = fail;
|
|
|
|
bb->type = type;
|
|
|
|
bb->score = score;
|
|
|
|
bb->reached = reached;
|
|
|
|
bb->called = called;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_bb (RList *block_list, ut64 start, ut64 end, ut64 jump, ut64 fail, bb_type_t type, int score) {
|
|
|
|
bb_t *bb = (bb_t*) R_NEW0 (bb_t);
|
|
|
|
if (!bb) {
|
|
|
|
eprintf ("Failed to calloc mem for new basic block!\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
init_bb (bb, start, end, jump, fail, type, score, 0, 0);
|
|
|
|
if (jump < UT64_MAX) {
|
|
|
|
bb_t *jump_bb = (bb_t*) R_NEW0 (bb_t);
|
|
|
|
if (!jump_bb) {
|
|
|
|
eprintf ("Failed to allocate memory for jump block\n");
|
|
|
|
free (bb);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (type == CALL) {
|
|
|
|
init_bb (jump_bb, jump, UT64_MAX, UT64_MAX, UT64_MAX, CALL, 0, 1, 1);
|
|
|
|
} else {
|
|
|
|
init_bb (jump_bb, jump, UT64_MAX, UT64_MAX, UT64_MAX, JUMP, 0, 1, 0);
|
|
|
|
}
|
|
|
|
r_list_append (block_list, jump_bb);
|
|
|
|
}
|
|
|
|
if (fail < UT64_MAX) {
|
|
|
|
bb_t *fail_bb = (bb_t*) R_NEW0 (bb_t);
|
|
|
|
if (!fail_bb) {
|
|
|
|
eprintf ("Failed to allocate memory for fail block\n");
|
|
|
|
free (bb);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
init_bb (fail_bb, fail, UT64_MAX, UT64_MAX, UT64_MAX, FAIL, 0, 1, 0);
|
|
|
|
r_list_append (block_list, fail_bb);
|
|
|
|
}
|
|
|
|
r_list_append (block_list, bb);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump_block(bb_t *block) {
|
|
|
|
eprintf ("s: 0x%"PFMT64x" e: 0x%"PFMT64x" j: 0x%"PFMT64x" f: 0x%"PFMT64x"\n"
|
|
|
|
, block->start, block->end, block->jump, block->fail);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump_blocks (RList* list) {
|
|
|
|
RListIter *iter;
|
|
|
|
bb_t *block = NULL;
|
|
|
|
r_list_foreach (list, iter, block) {
|
|
|
|
dump_block(block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define Fhandled(x) sdb_fmt(0, "handled.%"PFMT64x"", x)
|
2017-02-09 23:02:39 +00:00
|
|
|
R_API bool core_anal_bbs(RCore *core, ut64 len) {
|
2017-03-30 08:53:40 +00:00
|
|
|
ut64 cur = 0;
|
|
|
|
ut64 start = core->offset;
|
|
|
|
ut64 size = len;
|
|
|
|
ut64 b_start = start;
|
|
|
|
RAnalOp *op;
|
|
|
|
RListIter *iter;
|
|
|
|
int block_score = 0;
|
|
|
|
RList *block_list;
|
|
|
|
bb_t *block = NULL;
|
|
|
|
|
|
|
|
Sdb *sdb = sdb_new0 ();
|
|
|
|
if (!sdb) {
|
|
|
|
eprintf ("Failed to initialize sdb db\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
block_list = r_list_newf(free);
|
|
|
|
|
|
|
|
while (cur < size) {
|
|
|
|
op = r_core_anal_op (core, start + cur);
|
|
|
|
|
|
|
|
if (!op || !op->mnemonic) {
|
|
|
|
block_score -= 10;
|
|
|
|
cur += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op->mnemonic[0] == '?') {
|
|
|
|
eprintf ("Cannot analyze opcode at %"PFMT64x"\n", start + cur);
|
|
|
|
block_score -= 10;
|
|
|
|
cur += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switch (op->type) {
|
|
|
|
case R_ANAL_OP_TYPE_NOP:
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
|
|
add_bb (block_list, op->jump, UT64_MAX, UT64_MAX, UT64_MAX, CALL, block_score);
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_UCALL:
|
|
|
|
case R_ANAL_OP_TYPE_ICALL:
|
|
|
|
case R_ANAL_OP_TYPE_RCALL:
|
|
|
|
case R_ANAL_OP_TYPE_IRCALL:
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_UJMP:
|
|
|
|
case R_ANAL_OP_TYPE_RJMP:
|
|
|
|
case R_ANAL_OP_TYPE_IJMP:
|
|
|
|
case R_ANAL_OP_TYPE_IRJMP:
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
add_bb (block_list, b_start, start + cur + op->size, op->jump, UT64_MAX, NORMAL, block_score);
|
|
|
|
b_start = start + cur + op->size;
|
|
|
|
block_score = 0;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_TRAP:
|
|
|
|
// we dont want to add trap stuff
|
|
|
|
if (b_start < start + cur) {
|
|
|
|
add_bb (block_list, b_start, start + cur, UT64_MAX, UT64_MAX, NORMAL, block_score);
|
|
|
|
}
|
|
|
|
b_start = start + cur + op->size;
|
|
|
|
block_score = 0;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_RET:
|
|
|
|
add_bb (block_list, b_start, start + cur + op->size, UT64_MAX, UT64_MAX, NORMAL, block_score);
|
|
|
|
b_start = start + cur + op->size;
|
|
|
|
block_score = 0;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
|
|
add_bb (block_list, b_start, start + cur + op->size, op->jump, start + cur + op->size, NORMAL, block_score);
|
|
|
|
b_start = start + cur + op->size;
|
|
|
|
block_score = 0;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_UNK:
|
|
|
|
case R_ANAL_OP_TYPE_ILL:
|
|
|
|
block_score -= 10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cur += op->size;
|
|
|
|
r_anal_op_free (op);
|
|
|
|
op = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//eprintf ("Before sort:\n");
|
|
|
|
//dump_blocks( block_list);
|
|
|
|
//eprintf ("After sort:\n");
|
|
|
|
RList *result = r_list_newf (free);
|
|
|
|
if (!result) {
|
|
|
|
eprintf ("Failed to create resulting list\n");
|
|
|
|
//TODO handle error
|
|
|
|
}
|
|
|
|
|
|
|
|
r_list_sort (block_list, (RListComparator)bb_cmp);
|
|
|
|
//dump_blocks( block_list);
|
|
|
|
eprintf ("First run creates %d blocks\n", block_list->length);
|
|
|
|
eprintf ("## Sorting done ###\n");
|
|
|
|
while (block_list->length > 0) {
|
|
|
|
block = r_list_pop (block_list);
|
|
|
|
if (!block) {
|
|
|
|
eprintf ("Failed to get next block from list\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block_list->length > 0) {
|
|
|
|
bb_t *next_block = (bb_t*) r_list_iter_get_data (block_list->tail);
|
|
|
|
if (!next_block) {
|
|
|
|
eprintf ("No next block to compare with!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// current block is just a split block
|
|
|
|
if (block->start == next_block->start && block->end == UT64_MAX) {
|
|
|
|
if (block->type != CALL && next_block->type != CALL) {
|
|
|
|
next_block->reached += 1;
|
|
|
|
}
|
|
|
|
free (block);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// block and next_block share the same start so we copy the
|
|
|
|
// contenct of the block into the next_block and skip the current one
|
|
|
|
if (block->start == next_block->start && next_block->end == UT64_MAX) {
|
|
|
|
*next_block = *block;
|
|
|
|
if (next_block->type != CALL) {
|
|
|
|
next_block->reached += 1;
|
|
|
|
}
|
|
|
|
free (block);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block->end < UT64_MAX && next_block->start < block->end && next_block->start > block->start) {
|
|
|
|
if (next_block->jump == UT64_MAX) {
|
|
|
|
next_block->jump = block->jump;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (next_block->fail == UT64_MAX) {
|
|
|
|
next_block->fail = block->fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_block->end = block->end;
|
|
|
|
block->end = next_block->start;
|
|
|
|
block->jump = next_block->start;
|
|
|
|
block->fail = UT64_MAX;
|
|
|
|
next_block->type = block->type;
|
|
|
|
if (next_block->type != CALL) {
|
|
|
|
next_block->reached += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_io_is_valid_offset (core->io, block->start, false)) {
|
|
|
|
if (block->score >= 0) {
|
|
|
|
sdb_ptr_set (sdb, sdb_fmt (0, "bb.0x%08"PFMT64x, block->start), block, 0);
|
|
|
|
r_list_append (result, block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// finally search for functions
|
|
|
|
// we simply assume that non reached blocks or called blocks
|
|
|
|
// are functions
|
|
|
|
r_list_foreach (result, iter, block) {
|
|
|
|
if (block && (block->reached == 0 || block->called >= 1)) {
|
|
|
|
printFunction(core, block->start, NULL);
|
|
|
|
RStack *stack = r_stack_newf (100, free);
|
|
|
|
bb_t *jump = NULL;
|
|
|
|
bb_t *fail = NULL;
|
|
|
|
|
|
|
|
if (!r_stack_push (stack, (void*)block)) {
|
|
|
|
eprintf ("Failed to push initial block\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
bb_t *cur = NULL;
|
|
|
|
while (!r_stack_is_empty (stack)) {
|
|
|
|
cur = (bb_t*) r_stack_pop (stack);
|
|
|
|
if (!cur) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sdb_num_set (sdb, Fhandled(cur->start), 1, 0);
|
|
|
|
// we ignore negative blocks
|
|
|
|
if ((st64)(cur->end - cur->start) < 0) {
|
2017-04-11 22:05:29 +00:00
|
|
|
// XXX leak of crash free (cur);
|
2017-03-30 08:53:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
r_cons_printf ("afb+ 0x%08" PFMT64x " 0x%08" PFMT64x " %llu 0x%08"PFMT64x" 0x%08"PFMT64x"\n"
|
|
|
|
, block->start, cur->start, cur->end - cur->start, cur->jump, cur->fail);
|
|
|
|
|
|
|
|
if (cur->jump < UT64_MAX && !sdb_num_get (sdb, Fhandled(cur->jump), NULL)) {
|
|
|
|
jump = sdb_ptr_get (sdb, sdb_fmt (0, "bb.0x%08"PFMT64x, cur->jump), NULL);
|
|
|
|
if (!jump) {
|
|
|
|
eprintf ("Failed to get jump block\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!r_stack_push (stack, (void*)jump)) {
|
|
|
|
eprintf ("Failed to push jump block to stack\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur->fail < UT64_MAX && !sdb_num_get (sdb, Fhandled(cur->fail), NULL)) {
|
|
|
|
fail = sdb_ptr_get (sdb, sdb_fmt (0, "bb.0x%08" PFMT64x, cur->fail), NULL);
|
|
|
|
if (!fail) {
|
|
|
|
eprintf ("Failed to get fail block\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!r_stack_push (stack, (void*)fail)) {
|
|
|
|
eprintf ("Failed to push jump block to stack\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_stack_free (stack);
|
2017-03-31 09:49:06 +00:00
|
|
|
// free (block);
|
2017-03-30 08:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-31 09:49:06 +00:00
|
|
|
// sdb_free (sdb);
|
2017-03-30 08:53:40 +00:00
|
|
|
eprintf ("After merge %d blocks\n", result->length);
|
2017-04-05 08:41:19 +00:00
|
|
|
r_list_free (result);
|
2017-03-30 08:53:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API bool core_anal_bbs2(RCore *core, ut64 len) {
|
2017-02-09 23:02:39 +00:00
|
|
|
AbbState *abb = abbstate_new (len);
|
|
|
|
if (!abb) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int i;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
RAnalOp aop;
|
|
|
|
//RListIter *iter;
|
|
|
|
ut64 at = core->offset;
|
|
|
|
abb->addr = at;
|
2017-02-20 01:54:16 +00:00
|
|
|
(void) r_io_read_at (core->io, abb->addr, abb->buf, len);
|
2017-02-09 23:02:39 +00:00
|
|
|
int ti = -1;
|
2017-02-13 16:14:08 +00:00
|
|
|
int oi = 0;
|
2017-02-09 23:02:39 +00:00
|
|
|
abb->last = at;
|
2017-02-13 16:14:08 +00:00
|
|
|
abb->core = core;
|
|
|
|
abb->bb_addr = abb->addr;
|
2017-02-09 23:02:39 +00:00
|
|
|
r_cons_break_push (NULL, NULL);
|
2017-02-10 01:05:58 +00:00
|
|
|
eprintf ("Analyzing basic blocks from 0x%08" PFMT64x " to 0x%08" PFMT64x "\n", abb->addr, abb->addr + len);
|
2017-02-13 16:14:08 +00:00
|
|
|
|
2017-02-10 01:05:58 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
2017-02-09 23:02:39 +00:00
|
|
|
if (r_cons_is_breaked ()) {
|
|
|
|
break;
|
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
oi = i;
|
|
|
|
ut64 obb_addr = abb->bb_addr;
|
2017-02-20 01:54:16 +00:00
|
|
|
mountain:
|
2017-04-05 08:41:19 +00:00
|
|
|
if (r_anal_op (core->anal, &aop, abb->addr + i, abb->buf + i, R_MIN (R_MAX (0, len - i), 16)) < 1) {
|
2017-02-09 23:02:39 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int next = bbExist (abb, at + i);
|
|
|
|
if (next > 0) {
|
|
|
|
i += next - 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bb = parseOpcode (abb, &aop);
|
|
|
|
if (bb) {
|
|
|
|
/* register basic block */
|
|
|
|
RFlagItem *fi = r_flag_get_i (core->flags, bb->addr);
|
|
|
|
if (fi || i == 0) {
|
|
|
|
AbbAddr *n = R_NEW0 (AbbAddr);
|
2017-02-13 16:14:08 +00:00
|
|
|
n->name = fi? fi->name: NULL;
|
2017-02-09 23:02:39 +00:00
|
|
|
n->addr = bb->addr;
|
|
|
|
n->bits = 0; //bb->bits;
|
|
|
|
// move this logic into a separate function
|
2017-02-13 16:14:08 +00:00
|
|
|
if (fi) {
|
|
|
|
if (fi->name && !strncmp (fi->name, "str.", 4)) {
|
|
|
|
/* do nothing here */
|
|
|
|
} else {
|
|
|
|
n->type = 'c'; // call function :D
|
|
|
|
}
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
r_list_append (abb->fcnents, n);
|
|
|
|
}
|
|
|
|
/* register basic block */
|
2017-02-10 01:05:58 +00:00
|
|
|
sdb_num_set (abb->bbdb, sdb_fmt (0, "0x%08" PFMT64x, bb->addr), bb->size, 0);
|
|
|
|
sdb_ptr_set (abb->bbdb, sdb_fmt (0, "ptr.0x%08" PFMT64x, bb->addr), bb, 0);
|
2017-02-13 16:14:08 +00:00
|
|
|
if (bb->addr) {
|
|
|
|
r_list_append (abb->bbs, bb);
|
|
|
|
/* walk child blocks */
|
|
|
|
if (!r_list_empty (abb->nextbbs)) {
|
|
|
|
do {
|
|
|
|
AbbAddr *nat = r_list_pop (abb->nextbbs);
|
|
|
|
if (nat->type == 'c') {
|
|
|
|
// eprintf ("CALL %llx\n", nat->addr);
|
|
|
|
r_list_append (abb->fcnents, nat);
|
|
|
|
}
|
|
|
|
if (!bbExist (abb, nat->addr)) {
|
|
|
|
if (nat->addr > at && nat->addr < at + len) {
|
|
|
|
if (ti == -1) {
|
|
|
|
ti = i;
|
|
|
|
}
|
|
|
|
i = nat->addr - at;
|
|
|
|
abb->bb_addr = nat->addr;
|
|
|
|
if (nat->type == 'c') {
|
2017-02-20 01:54:16 +00:00
|
|
|
// r_list_append (abb->fcnents, nat);
|
2017-02-13 16:14:08 +00:00
|
|
|
} else {
|
|
|
|
free (nat);
|
|
|
|
}
|
|
|
|
goto mountain;
|
2017-02-09 23:02:39 +00:00
|
|
|
} else {
|
2017-02-13 16:14:08 +00:00
|
|
|
eprintf ("Out of bounds basic block for 0x%08" PFMT64x "\n", nat->addr);
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
free (nat);
|
|
|
|
} while (!r_list_empty (abb->nextbbs));
|
2017-04-05 08:41:19 +00:00
|
|
|
ti = -1;
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
2017-02-13 16:14:08 +00:00
|
|
|
i = oi;
|
|
|
|
abb->bb_addr = obb_addr;
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += aop.size - 1;
|
|
|
|
r_anal_op_fini (&aop);
|
|
|
|
}
|
|
|
|
r_cons_break_pop ();
|
2017-02-10 01:05:58 +00:00
|
|
|
|
2017-02-09 23:02:39 +00:00
|
|
|
eprintf ("Found %d basic blocks\n", r_list_length (abb->bbs));
|
|
|
|
findFunctions (core, abb);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// show results
|
|
|
|
r_list_foreach (abb->bbs, iter, bb) {
|
|
|
|
RFlagItem *f = r_flag_get_at (core->flags, bb->addr, true);
|
|
|
|
char *name;
|
|
|
|
if (f) {
|
|
|
|
if (f->offset != bb->addr) {
|
|
|
|
name = r_str_newf ("%s+0x%x", f->name, bb->addr - f->offset);
|
|
|
|
} else {
|
|
|
|
name = strdup (f->name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
name = r_str_newf ("bb.%"PFMT64x, bb->addr);
|
|
|
|
}
|
2017-02-20 01:54:16 +00:00
|
|
|
r_cons_printf ("agn 0x%08"PFMT64x " \"%s\"\n", bb->addr, name);
|
2017-02-09 23:02:39 +00:00
|
|
|
free (name);
|
|
|
|
}
|
|
|
|
r_list_foreach (abb->bbs, iter, bb) {
|
|
|
|
if (bb->jump != UT64_MAX) {
|
2017-02-20 01:54:16 +00:00
|
|
|
r_cons_printf ("age 0x%08"PFMT64x " 0x%08"PFMT64x "\n", bb->addr, bb->jump);
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
if (bb->fail != UT64_MAX) {
|
2017-02-20 01:54:16 +00:00
|
|
|
r_cons_printf ("age 0x%08"PFMT64x " 0x%08"PFMT64x "\n", bb->addr, bb->fail);
|
2017-02-09 23:02:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
abbstate_free (abb);
|
|
|
|
return true;
|
|
|
|
}
|