Add core.anal plugin `a2f` command. Fix a bug in x86.cs, align comments at right

This commit is contained in:
pancake 2014-11-13 03:36:48 +01:00
parent a8023c7b6f
commit 6d4529ffbf
13 changed files with 356 additions and 15 deletions

View File

@ -254,11 +254,15 @@ static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) {
case X86_INS_JMP:
case X86_INS_LJMP:
// TODO: what if UJMP?
op->jump = INSOP(0).imm;
op->type = R_ANAL_OP_TYPE_JMP;
if (a->decode) {
ut64 dst = INSOP(0).imm;
esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc);
if (INSOP(0).type == X86_OP_IMM) {
op->jump = INSOP(0).imm;
op->type = R_ANAL_OP_TYPE_JMP;
if (a->decode) {
ut64 dst = INSOP(0).imm;
esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc);
}
} else {
op->type = R_ANAL_OP_TYPE_UJMP;
}
break;
case X86_INS_IN:

View File

@ -307,6 +307,8 @@ R_API int r_asm_disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
op->size = 4;
if (len<1)
return 0;
// on mips/arm/sparc .. use word size
sprintf (op->buf_asm,".byte 0x%02x %d", buf[0], len);
if (a->cur && a->cur->disassemble)
ret = a->cur->disassemble (a, op, buf, len);
oplen = r_asm_op_get_size (op);

View File

@ -763,3 +763,15 @@ R_API void r_cons_highlight (const char *word) {
I.highlight = NULL;
}
}
R_API char *r_cons_lastline () {
char *b = I.buffer+I.buffer_len;
while (b >I.buffer) {
if (*b=='\n') {
b++;
break;
}
b--;
}
return b;
}

View File

@ -205,7 +205,7 @@ R_API RAnalOp* r_core_anal_op(RCore *core, ut64 addr) {
{
RAsmOp asmop;
r_asm_set_pc (core->assembler, addr);
if (r_asm_disassemble (core->assembler, &asmop, buf, len)>0) {
if (r_asm_disassemble (core->assembler, &asmop, ptr, len)>0) {
op.mnemonic = strdup (asmop.buf_asm);
}
}

View File

@ -855,7 +855,8 @@ R_API int r_core_config_init(RCore *core) {
SETPREF("asm.bytes", "true", "Display the bytes of each instruction");
SETPREF("asm.flagsinbytes", "false", "Display flags inside the bytes space");
SETPREF("asm.cmtflgrefs", "true", "Show comment flags associated to branch referece");
SETPREF("asm.cmtright", "false", "Show comments at right of disassembly if they fit in screen");
SETPREF("asm.cmtright", "true", "Show comments at right of disassembly if they fit in screen");
SETI("asm.cmtcol", 80, "Align comments at column 60");
SETPREF("asm.comments", "true", "Show comments in disassembly view");
SETPREF("asm.decode", "false", "Use code analysis as a disassembler");
SETPREF("asm.indent", "false", "Indent disassembly based on reflines depth");

View File

@ -63,6 +63,7 @@ typedef struct r_disam_options_t {
int show_flags;
int show_bytes;
int show_comments;
int cmtcol;
int show_fcnlines;
int show_cmtflgrefs;
int show_cycles;
@ -139,6 +140,7 @@ typedef struct r_disam_options_t {
} RDisasmState;
static void handle_reflines_init (RCore *core, RDisasmState *ds);
static void handle_comment_align (RCore *core, RDisasmState *ds);
static RDisasmState * handle_init_ds (RCore * core);
static void handle_set_pre (RDisasmState *ds, const char * str);
static void handle_build_op_str (RCore *core, RDisasmState *ds);
@ -242,6 +244,7 @@ static RDisasmState * handle_init_ds (RCore * core) {
ds->show_bytes = r_config_get_i (core->config, "asm.bytes");
ds->show_fcnlines = r_config_get_i (core->config, "asm.fcnlines");
ds->show_comments = r_config_get_i (core->config, "asm.comments");
ds->cmtcol = r_config_get_i (core->config, "asm.cmtcol");
ds->show_cmtflgrefs = r_config_get_i (core->config, "asm.cmtflgrefs");
ds->show_cycles = r_config_get_i (core->config, "asm.cycles");
ds->show_stackptr = r_config_get_i (core->config, "asm.stackptr");
@ -936,6 +939,7 @@ static void handle_control_flow_comments (RCore * core, RDisasmState *ds) {
item = r_flag_get_i (core->flags, ds->analop.jump);
if (item && item->comment) {
if (ds->show_color) r_cons_strcat (ds->pal_comment);
handle_comment_align (core, ds);
r_cons_printf (" ; ref to %s: %s\n", item->name, item->comment);
handle_print_color_reset(core, ds);
}
@ -1335,6 +1339,7 @@ static void handle_print_import_name (RCore * core, RDisasmState *ds) {
if (ds->show_color)
r_cons_strcat (ds->color_fname);
// TODO: handle somehow ordinals import
handle_comment_align (core, ds);
r_cons_printf (" ; (imp.%s)", rel->import->name);
handle_print_color_reset (core, ds);
}
@ -1354,6 +1359,7 @@ static void handle_print_fcn_name (RCore * core, RDisasmState *ds) {
if (f && !strstr (ds->opstr, f->name)) {
if (ds->show_color)
r_cons_strcat (ds->color_fname);
handle_comment_align (core, ds);
r_cons_printf (" ; (%s)", f->name);
handle_print_color_reset (core, ds);
}
@ -1434,6 +1440,27 @@ static void handle_print_cc_update (RCore *core, RDisasmState *ds) {
}
}
// align for comment
static void handle_comment_align (RCore *core, RDisasmState *ds) {
const int cmtcol = ds->cmtcol;
char *ll;
if (!ds->show_comment_right_default)
return;
ll = r_cons_lastline ();
if (ll) {
int cols = r_cons_get_size (NULL);
int ansilen = r_str_ansi_len (ll);
if (cmtcol+10>=cols) {
r_cons_newline ();
r_cons_memset (' ', 10);
} else if (ansilen < cmtcol) {
int len = cmtcol - ansilen;
if (len < cols)
r_cons_memset (' ', cmtcol-ansilen);
}
}
}
static void handle_print_dwarf (RCore *core, RDisasmState *ds) {
if (ds->show_dwarf) {
ds->sl = r_bin_addr2text (core->bin, ds->at);
@ -1442,6 +1469,7 @@ static void handle_print_dwarf (RCore *core, RDisasmState *ds) {
if (ds->sl) {
if ((!ds->osl || (ds->osl && strcmp (ds->sl, ds->osl)))) {
handle_set_pre (ds, " ");
handle_comment_align (core, ds);
if (ds->show_color)
r_cons_printf ("%s ; %s"Color_RESET"%s",
ds->pal_comment, ds->sl, ds->pre);
@ -1513,14 +1541,17 @@ static void handle_print_ptr (RCore *core, RDisasmState *ds, int len, int idx) {
case 8: n &= UT64_MAX; break;
}
n32 = n;
handle_comment_align (core, ds);
if (n==UT32_MAX || n==UT64_MAX) {
r_cons_printf (" ; [:%d]=-1", ds->analop.refptr);
r_cons_printf (" ; [0x%"PFMT64x":%d]=-1", p, ds->analop.refptr);
} else if (n == n32 && (n32>-512 && n32 <512)) {
r_cons_printf (" ; [:%d]=%"PFMT64d, ds->analop.refptr, n);
r_cons_printf (" ; [0x%"PFMT64x":%d]=%"PFMT64d, p, ds->analop.refptr, n);
} else {
r_cons_printf (" ; [:%d]=0x%"PFMT64x, ds->analop.refptr, n);
r_cons_printf (" ; [0x%"PFMT64x":%d]=0x%"PFMT64x, p, ds->analop.refptr, n);
}
}
handle_comment_align (core, ds);
f = r_flag_get_i (core->flags, p);
if (f) {
r_str_filter (msg, 0);
@ -1607,9 +1638,7 @@ static void handle_print_relocs (RCore *core, RDisasmState *ds) {
static void handle_print_comments_right (RCore *core, RDisasmState *ds) {
handle_print_relocs (core, ds);
if (ds->show_comments && ds->show_comment_right && ds->comment) {
int c = r_cons_get_column ();
if (c<ds->ocols)
r_cons_memset (' ', ds->ocols-c);
handle_comment_align (core, ds);
if (ds->show_color)
r_cons_strcat (ds->color_comment);
r_cons_strcat (" ; ");
@ -1659,6 +1688,7 @@ static void handle_print_refptr_meta_infos (RCore *core, RDisasmState *ds, ut64
static void handle_print_as_string(RCore *core, RDisasmState *ds) {
char *str = r_num_as_string (NULL, ds->analop.ptr);
if (str) {
handle_comment_align (core, ds);
r_cons_printf (" ; \"%s\"", str);
}
free (str);

View File

@ -20,7 +20,7 @@ LDFLAGS+=${LINK}
foo: all
ALL_TARGETS=
PLUGS=java.mk
PLUGS=java.mk anal.mk
include $(PLUGS)

12
libr/core/p/anal.mk Normal file
View File

@ -0,0 +1,12 @@
CORE_OBJ_ANAL=core_anal.o
STATIC_OBJ+=${CORE_OBJ_ANAL}
CORE_TARGET_ANAL=core_anal.${EXT_SO}
ALL_TARGETS+=${CORE_TARGET_ANAL}
${CORE_TARGET_ANAL}: ${CORE_OBJ_ANAL}
${CC} $(call libname,core_anal) ${CFLAGS} \
-o core_anal.${EXT_SO} \
$(SHLR)/sdb/src/libsdb.a \
${CORE_OBJ_ANAL}

277
libr/core/p/core_anal.c Normal file
View File

@ -0,0 +1,277 @@
/* radare - Copyright 2014 pancake */
#include <r_types.h>
#include <r_core.h>
#define MAXFCNSIZE 4096
static ut64 sdb_array_get_closer_num (Sdb *db, const char *key, ut64 addr) {
const char *s = sdb_const_get (db, key, NULL);
const char *next = NULL;
const char *ptr = NULL;
ut64 num, closer = UT64_MAX;
if (!s) return UT64_MAX;
ptr = s;
do {
const char *str = sdb_const_anext (ptr, &next);
num = sdb_atoi (str);
if (addr == num)
return closer;
if (addr<num)
continue;
if (closer > (addr - num))
closer = num;
ptr = next;
} while (next);
return closer;
}
#define Fbb(x) sdb_fmt(0,"bb.%"PFMT64x,x)
#define FbbTo(x) sdb_fmt(0,"bb.%"PFMT64x".to",x)
static int bbAdd (Sdb *db, ut64 from, ut64 to, ut64 jump, ut64 fail) {
ut64 last, addr = sdb_array_get_closer_num (db, "bbs", from);
int add = 1;
if (addr == UT64_MAX) {
// add = 1;
} else if (addr == from) {
// check if size is the same,
eprintf ("basic block already analyzed\n");
add = 0;
} else {
last = sdb_num_get (db, Fbb(addr), NULL);
if (last) {
if (from >= addr && from < last) {
eprintf ("OVERLAPS MUST SPLIT\n");
add = 0;
}
}
}
if (add) {
eprintf ("ADD NEW BB %llx\n", from);
sdb_array_add_num (db, "bbs", from, 0);
sdb_num_set (db, Fbb(from), to, 0);
if (jump != UT64_MAX)
sdb_array_set_num (db, FbbTo(from), 0, jump, 0);
if (fail != UT64_MAX)
sdb_array_set_num (db, FbbTo(from), 1, fail, 0);
}
return 0;
}
int analyzeIterative (RCore *core, Sdb *db, ut64 addr) {
#define addCall(x) sdb_array_add_num (db, "calls", x, 0);
#define addUcall(x) sdb_array_add_num (db, "ucalls", x, 0);
#define addUjmp(x) sdb_array_add_num (db, "ujmps", x, 0);
#define addCjmp(x) sdb_array_add_num (db, "cjmps", x, 0);
#define addRet(x) sdb_array_add_num (db, "rets", x, 0);
#define bbAddOpcode(x) sdb_array_insert_num (db, sdb_fmt (0, "bb.%"PFMT64x, bb_begin), -1, x, 0);
/* this loop creates basic blocks */
ut64 oaddr = addr;
RAnalOp *op;
int cur = 0;
int fcn_size = 0;
ut64 bb_end = addr;
ut64 bb_begin = addr;
eprintf ("-> 0x%08"PFMT64x"\n", addr);
for (;;) {
op = r_core_anal_op (core, addr + cur);
if (!op) {
eprintf ("Cannot analyze opcode at %d\n", addr+cur);
return R_FALSE;
}
eprintf ("0x%08"PFMT64x" %s\n", addr + cur, op->mnemonic);
bb_end += op->size;
fcn_size += op->size;
bbAddOpcode (addr+cur);
switch (op->type) {
case R_ANAL_OP_TYPE_NOP:
/* If placed at the begining..just skip them */
if (cur == 0) {
eprintf ("NOPSKIP %d\n", op->size);
oaddr += op->size;
bb_begin = addr = oaddr;
fcn_size -= op->size;
cur -= op->size;
}
break;
case R_ANAL_OP_TYPE_CALL:
/* A call instruction implies that the destination
* is a new function unless the address is inside
* the same range than the current function */
addCall (op->jump);
// add call reference
break;
case R_ANAL_OP_TYPE_UCALL:
/* unknown calls depend on ESIL or DEBUG tracing
* information to know the destination, we can mark
* those 'calls' for later adding tracepoints in
* there to record all possible destinations */
addUcall (addr+cur);
break;
case R_ANAL_OP_TYPE_UJMP:
/* an unknown jump use to go into computed destinations
* outside the current function, but it may result
* on an antidisasm trick */
addUjmp (addr+cur);
/* An unknown jump breaks the basic blocks */
goto endOfFunction;
case R_ANAL_OP_TYPE_TRAP:
addRet (addr + cur);
goto endOfFunction;
case R_ANAL_OP_TYPE_RET:
addRet (addr + cur);
goto endOfFunction;
case R_ANAL_OP_TYPE_CJMP:
/* jumps use to go into the same function, so we*/
addCjmp (op->jump);
bbAdd (db, bb_begin, bb_end, op->jump, bb_end);
bb_begin = bb_end;
break;
case R_ANAL_OP_TYPE_JMP:
/* jumps usually go to the same function, but they
* can be used */
goto endOfFunction;
case R_ANAL_OP_TYPE_UNK:
eprintf ("Unknown instruction at 0x%08"PFMT64x"\n", addr+cur);
goto endOfFunction;
case R_ANAL_OP_TYPE_ILL:
eprintf ("HLT\n");
goto endOfFunction;
}
cur += op->size;
r_anal_op_free (op);
op = NULL;
}
endOfFunction:
r_anal_op_free (op);
bbAdd (db, bb_begin, bb_end, UT64_MAX, UT64_MAX);
return oaddr;
}
static int analyzeFunction (RCore *core, ut64 addr) {
Sdb *db = sdb_new0 ();
if (!db) {
eprintf ("Cannot create db\n");
return R_FALSE;
}
addr = analyzeIterative (core, db, addr);
if (addr == UT64_MAX) {
eprintf ("Initial analysis failed\n");
return R_FALSE;
}
sdb_num_set (db, "addr", addr, 0);
/* those loops can split basic blocks */
/* iterate over all conditional jumps */
{
char *c, *cjmps = sdb_get (db, "cjmps", NULL);
sdb_aforeach (c, cjmps) {
ut64 addr = sdb_atoi (c);
analyzeIterative (core, db, addr);
sdb_aforeach_next (c);
}
free (cjmps);
}
{
char *c, *cjmps = sdb_get (db, "calls", NULL);
sdb_aforeach (c, cjmps) {
ut64 addr = sdb_atoi (c);
// check if call destination is inside the function boundaries
eprintf ("CALL 0x%08"PFMT64x"\n", addr);
sdb_aforeach_next (c);
}
free (cjmps);
}
{
char *c, *cjmps = sdb_get (db, "jmps", NULL);
sdb_aforeach (c, cjmps) {
ut64 addr = sdb_atoi (c);
// check if call destination is inside the function boundaries
eprintf ("JMP 0x%08"PFMT64x"\n", addr);
sdb_aforeach_next (c);
}
free (cjmps);
}
// Parse SDB and dump results of the analysis
eprintf ("addr: %s\n", sdb_const_get (db, "addr", NULL));
eprintf ("calls: %s\n", sdb_const_get (db, "calls", NULL));
eprintf ("ucalls: %s\n", sdb_const_get (db, "ucalls", NULL));
eprintf ("cjmps: %s\n", sdb_const_get (db, "cjmps", NULL));
eprintf ("ujmps: %s\n", sdb_const_get (db, "ujmps", NULL));
eprintf ("rets: %s\n", sdb_const_get (db, "rets", NULL));
eprintf ("bbs: %s\n", sdb_const_get (db, "bbs", NULL));
{
ut64 min, max;
char *c, *bbs = sdb_get (db, "bbs", NULL);
int first = 1;
sdb_aforeach (c, bbs) {
ut64 addr = sdb_atoi (c);
ut64 addr_end = sdb_num_get (db, sdb_fmt(0, "bb.%"PFMT64x, addr), NULL);
if (first) {
min = addr;
max = addr_end;
first = 0;
} else {
if (addr<min)
min = addr;
if (addr_end>max)
max = addr_end;
}
// check if call destination is inside the function boundaries
eprintf ("BB 0x%08"PFMT64x" - 0x%08"PFMT64x" %d\n",
addr, addr_end, addr_end-addr);
eprintf (" -> %s\n", sdb_const_get (db, FbbTo (addr), 0));
sdb_aforeach_next (c);
}
free (bbs);
sdb_num_set (db, "size", max-min, 0);
}
r_cons_printf ("af+ 0x%08"PFMT64x" %d fcn2.0x%08"PFMT64x,
sdb_num_get (db, "addr", NULL),
sdb_num_get (db, "size", NULL),
sdb_num_get (db, "addr", NULL)
);
eprintf ("size: %s\n", sdb_const_get (db, "size", NULL));
sdb_free (db);
return R_TRUE;
}
static int r_cmd_anal_call(void *user, const char *input) {
RCore *core = (RCore *) user;
if (!strncmp (input, "a2", 2)) {
switch (input[2]) {
case 'f':
if (!analyzeFunction (core, core->offset)) {
eprintf ("a2f: Failed to analyze function.\n");
}
break;
default:
eprintf ("Usage: a2f\n");
break;
}
return R_TRUE;
}
return R_FALSE;
}
// PLUGIN Definition Info
RCorePlugin r_core_plugin_anal = {
.name = "anal",
.desc = "The reworked analysis from scratch thing",
.license = "LGPL3",
.call = r_cmd_anal_call,
.deinit = NULL,
.init = NULL,
};
#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
.type = R_LIB_TYPE_CORE,
.data = &r_core_plugin_anal
};
#endif

View File

@ -2027,7 +2027,7 @@ RCorePlugin r_core_plugin_java = {
#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
.type = R_LIB_TYPE_CMD,
.type = R_LIB_TYPE_CORE,
.data = &r_core_plugin_java
};
#endif

View File

@ -280,6 +280,7 @@ R_API void r_cons_canvas_fill(RConsCanvas *c, int x, int y, int w, int h, char c
R_API RCons *r_cons_new ();
R_API RCons *r_cons_singleton ();
R_API RCons *r_cons_free ();
R_API char *r_cons_lastline ();
typedef void (*RConsBreak)(void *);
R_API void r_cons_break(RConsBreak cb, void *user);

View File

@ -483,6 +483,7 @@ R_API void r_core_task_join (RCore *core, RCoreTask *task);
/* PLUGINS */
extern RCorePlugin r_core_plugin_java;
extern RCorePlugin r_core_plugin_anal;
extern RCorePlugin r_core_plugin_yara;
#endif

View File

@ -111,6 +111,7 @@ bp.bf
bp.x86
bp.mips
bp.ppc
core.anal
core.java
core.yara
crypto.aes