From 6d4529ffbfd8e90179bdd2e48de42d801a3bf7f8 Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 13 Nov 2014 03:36:48 +0100 Subject: [PATCH] Add core.anal plugin `a2f` command. Fix a bug in x86.cs, align comments at right --- libr/anal/p/anal_x86_cs.c | 14 +- libr/asm/asm.c | 2 + libr/cons/cons.c | 12 ++ libr/core/anal.c | 2 +- libr/core/config.c | 3 +- libr/core/disasm.c | 42 +++++- libr/core/p/Makefile | 2 +- libr/core/p/anal.mk | 12 ++ libr/core/p/core_anal.c | 277 ++++++++++++++++++++++++++++++++++++++ libr/core/p/core_java.c | 2 +- libr/include/r_cons.h | 1 + libr/include/r_core.h | 1 + plugins.def.cfg | 1 + 13 files changed, 356 insertions(+), 15 deletions(-) create mode 100644 libr/core/p/anal.mk create mode 100644 libr/core/p/core_anal.c diff --git a/libr/anal/p/anal_x86_cs.c b/libr/anal/p/anal_x86_cs.c index bba5cbca9b..9403eb5ca3 100644 --- a/libr/anal/p/anal_x86_cs.c +++ b/libr/anal/p/anal_x86_cs.c @@ -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: diff --git a/libr/asm/asm.c b/libr/asm/asm.c index 176facdf7c..dbfe17e650 100644 --- a/libr/asm/asm.c +++ b/libr/asm/asm.c @@ -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); diff --git a/libr/cons/cons.c b/libr/cons/cons.c index f8b7227743..b64afaca45 100644 --- a/libr/cons/cons.c +++ b/libr/cons/cons.c @@ -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; +} diff --git a/libr/core/anal.c b/libr/core/anal.c index 076224681f..c72183bc4a 100644 --- a/libr/core/anal.c +++ b/libr/core/anal.c @@ -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); } } diff --git a/libr/core/config.c b/libr/core/config.c index c12551f719..54853aa6ed 100644 --- a/libr/core/config.c +++ b/libr/core/config.c @@ -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"); diff --git a/libr/core/disasm.c b/libr/core/disasm.c index 2da237feab..b9eaae99da 100644 --- a/libr/core/disasm.c +++ b/libr/core/disasm.c @@ -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 (cocols) - 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); diff --git a/libr/core/p/Makefile b/libr/core/p/Makefile index 0b578398dd..83de0fddc0 100644 --- a/libr/core/p/Makefile +++ b/libr/core/p/Makefile @@ -20,7 +20,7 @@ LDFLAGS+=${LINK} foo: all ALL_TARGETS= -PLUGS=java.mk +PLUGS=java.mk anal.mk include $(PLUGS) diff --git a/libr/core/p/anal.mk b/libr/core/p/anal.mk new file mode 100644 index 0000000000..018ccc7010 --- /dev/null +++ b/libr/core/p/anal.mk @@ -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} diff --git a/libr/core/p/core_anal.c b/libr/core/p/core_anal.c new file mode 100644 index 0000000000..b8c565100c --- /dev/null +++ b/libr/core/p/core_anal.c @@ -0,0 +1,277 @@ +/* radare - Copyright 2014 pancake */ + +#include +#include + +#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 (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 (addrmax) + 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 diff --git a/libr/core/p/core_java.c b/libr/core/p/core_java.c index a6634cbd29..46b5b13bcf 100644 --- a/libr/core/p/core_java.c +++ b/libr/core/p/core_java.c @@ -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 diff --git a/libr/include/r_cons.h b/libr/include/r_cons.h index f7438af571..c05627d711 100644 --- a/libr/include/r_cons.h +++ b/libr/include/r_cons.h @@ -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); diff --git a/libr/include/r_core.h b/libr/include/r_core.h index 0dd785893e..79312a253b 100644 --- a/libr/include/r_core.h +++ b/libr/include/r_core.h @@ -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 diff --git a/plugins.def.cfg b/plugins.def.cfg index e713d2179b..3f475370b1 100644 --- a/plugins.def.cfg +++ b/plugins.def.cfg @@ -111,6 +111,7 @@ bp.bf bp.x86 bp.mips bp.ppc +core.anal core.java core.yara crypto.aes