Add and use the new Indirect Code XREF type to improve code coverage ##analysis

This commit is contained in:
pancake 2023-06-28 20:47:27 +02:00 committed by pancake
parent 114096b8c4
commit c8d18b8123
5 changed files with 80 additions and 39 deletions

View File

@ -354,6 +354,7 @@ static void check_purity(HtUP *ht, RAnalFunction *fcn) {
switch (rt) {
case R_ANAL_REF_TYPE_CALL:
case R_ANAL_REF_TYPE_CODE:
case R_ANAL_REF_TYPE_ICOD:
{
RAnalFunction *called_fcn = r_anal_get_fcn_in (fcn->anal, ref->addr, 0);
if (!called_fcn) {
@ -1059,25 +1060,31 @@ repeat:
}
break;
case R_ANAL_OP_TYPE_LOAD:
// R2R db/anal/arm db/esil/apple
if (anal->iob.is_valid_offset (anal->iob.io, op->ptr, 0)) {
// TODO: what about the qword loads!??!?
ut8 dd[4] = {0};
(void)anal->iob.read_at (anal->iob.io, op->ptr, (ut8 *) dd, sizeof (dd));
// if page have exec perms
ut64 da = (ut64)r_read_ble32 (dd, R_ARCH_CONFIG_IS_BIG_ENDIAN (anal->config));
if (da != UT32_MAX && anal->iob.is_valid_offset (anal->iob.io, da, 0)) {
if (da != UT32_MAX && da != UT64_MAX && anal->iob.is_valid_offset (anal->iob.io, da, 0)) {
/// R2_590 - this must be CODE | READ , not CODE|DATA, but raises 10 fails
r_anal_xrefs_set (anal, op->addr, da, R_ANAL_REF_TYPE_CODE | R_ANAL_REF_TYPE_DATA);
// r_anal_xrefs_set (anal, op->addr, da, R_ANAL_REF_TYPE_CODE | R_ANAL_REF_TYPE_DATA);
r_anal_xrefs_set (anal, op->addr, da, R_ANAL_REF_TYPE_ICOD | R_ANAL_REF_TYPE_EXEC);
} else {
R_LOG_DEBUG ("Invalid refs 0x%08"PFMT64x" .. 0x%08"PFMT64x" .. 0x%08"PFMT64x" not adding", op->addr, op->ptr, da);
/// XXX this breaks the db/esil/apple tests
// r_meta_set (anal, R_META_TYPE_DATA, op->ptr, 4, "");
}
r_anal_xrefs_set (anal, op->addr, op->ptr, R_ANAL_REF_TYPE_DATA);
// maybe optional or in the else
// r_anal_xrefs_set (anal, op->addr, op->ptr, R_ANAL_REF_TYPE_DATA);
if (anal->opt.loads) {
// set this address as data if destination is not code
if (anal->iob.is_valid_offset (anal->iob.io, op->ptr, 0)) {
r_meta_set (anal, R_META_TYPE_DATA, op->ptr, 4, "");
}
}
}
break;
break;
// Case of valid but unused "add [rax], al"
case R_ANAL_OP_TYPE_ADD:
if (is_arm && anal->config->bits == 32) {

View File

@ -364,8 +364,8 @@ R_API const char *r_anal_ref_type_tostring(RAnalRefType type) {
case ' ':
case R_ANAL_REF_TYPE_NULL:
return "NULL";
case R_ANAL_REF_TYPE_CODE | R_ANAL_REF_TYPE_DATA:
return "ICOD"; // indirect code reference
case R_ANAL_REF_TYPE_ICOD:
return "ICOD";
case R_ANAL_REF_TYPE_CODE:
return "CODE";
case R_ANAL_REF_TYPE_CALL:
@ -374,9 +374,10 @@ R_API const char *r_anal_ref_type_tostring(RAnalRefType type) {
return "JUMP";
case R_ANAL_REF_TYPE_DATA:
return "DATA";
case R_ANAL_REF_TYPE_STRING:
case R_ANAL_REF_TYPE_STRN:
return "STRN";
default:
// R_LOG_ERROR("Invalid unknown ref type %c", R_ANAL_REF_TYPE_MASK (type));
return "UNKN";
}
}
@ -414,12 +415,16 @@ R_API int r_anal_ref_typemask(int x) {
const int maskedType = x & 0xff;
switch (maskedType) {
case R_ANAL_REF_TYPE_NULL:
case R_ANAL_REF_TYPE_CODE | R_ANAL_REF_TYPE_DATA: // 'g' // XXX R2_590 - this is a conflictive type
case R_ANAL_REF_TYPE_CODE: // 'c' // code ref
case R_ANAL_REF_TYPE_CALL: // 'C' // code ref (call)
case R_ANAL_REF_TYPE_JUMP: // 'j' // code ref (call)
case R_ANAL_REF_TYPE_DATA: // 'd' // mem ref
case R_ANAL_REF_TYPE_STRN: // 's' // string ref
case R_ANAL_REF_TYPE_STRN: // 's' // string ref
case R_ANAL_REF_TYPE_ICOD: // 'i' // indirect cod reference
return maskedType;
case ' ':
return R_ANAL_REF_TYPE_NULL;
}
R_LOG_ERROR ("Invalid reftype mask '%c' (0x%02x)", x, x);
// SHOULD NEVER HAPPEN MAYBE WARN HERE
@ -433,6 +438,7 @@ R_API RAnalRefType r_anal_xrefs_type(char ch) {
case R_ANAL_REF_TYPE_CALL:
case R_ANAL_REF_TYPE_DATA:
case R_ANAL_REF_TYPE_STRN:
case R_ANAL_REF_TYPE_ICOD:
case R_ANAL_REF_TYPE_NULL:
return (RAnalRefType)ch;
default:

View File

@ -658,18 +658,35 @@ static void r_anal_analyze_fcn_refs(RCore *core, RAnalFunction *fcn, int depth)
continue;
}
int rt = R_ANAL_REF_TYPE_MASK (ref->type);
if (rt == R_ANAL_REF_TYPE_DATA) {
switch (rt) {
case R_ANAL_REF_TYPE_DATA:
if (core->anal->opt.followdatarefs) {
r_anal_try_get_fcn (core, ref, depth, 2);
}
} else if (rt == R_ANAL_REF_TYPE_CODE || rt == R_ANAL_REF_TYPE_CALL) {
break;
case R_ANAL_REF_TYPE_ICOD:
// check if its used as data or code.. or at least check what's in the destination
{
const int t = r_anal_data_type (core->anal, ref->addr);
switch (R_ANAL_REF_TYPE_MASK (t)) {
case R_ANAL_REF_TYPE_ICOD:
case R_ANAL_REF_TYPE_CODE:
r_core_anal_fcn (core, ref->addr, ref->at, ref->type, depth - 1);
break;
case R_ANAL_REF_TYPE_DATA:
// TODO: maybe check if the contents of dst is a pointer to code
default:
break;
}
}
break;
case R_ANAL_REF_TYPE_CODE:
case R_ANAL_REF_TYPE_CALL:
r_core_anal_fcn (core, ref->addr, ref->at, ref->type, depth - 1);
break;
}
// TODO: fix memleak here, fcn not freed even though it is
// added in core->anal->fcns which is freed in r_anal_free ()
}
r_list_free (refs);
return 1;
}
static void function_rename(RFlag *flags, RAnalFunction *fcn) {
@ -1995,9 +2012,8 @@ R_API bool r_core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int dep
// if the function was already analyzed as a "loc.",
// convert it to function and rename it to "fcn.",
// because we found a call to this address
int rt = R_ANAL_REF_TYPE_MASK (reftype);
int ft = R_ANAL_REF_TYPE_MASK (fcn->type);
if (rt == R_ANAL_REF_TYPE_CALL && ft == R_ANAL_FCN_TYPE_LOC) {
const int rt = R_ANAL_REF_TYPE_MASK (reftype);
if (rt == R_ANAL_REF_TYPE_CALL && fcn->type == R_ANAL_FCN_TYPE_LOC) {
function_rename (core->flags, fcn);
}
return 0; // already analyzed function
@ -2986,7 +3002,7 @@ static int fcn_print_json(RCore *core, RAnalFunction *fcn, bool dorefs, PJ *pj)
pj_a (pj);
r_list_foreach (xrefs, iter, refi) {
int rt = R_ANAL_REF_TYPE_MASK (refi->type);
if (rt == R_ANAL_REF_TYPE_CODE || rt == R_ANAL_REF_TYPE_CALL) {
if (rt == R_ANAL_REF_TYPE_CODE || rt == R_ANAL_REF_TYPE_CALL || rt == R_ANAL_REF_TYPE_ICOD) {
indegree++;
pj_o (pj);
pj_kn (pj, "addr", refi->addr);
@ -3147,6 +3163,8 @@ static int fcn_print_detail(RCore *core, RAnalFunction *fcn) {
r_cons_printf ("axC 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
} else if (t == R_ANAL_REF_TYPE_DATA) {
r_cons_printf ("axd 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
} else if (t == R_ANAL_REF_TYPE_ICOD) {
r_cons_printf ("axi 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
} else if (t == R_ANAL_REF_TYPE_CODE) {
r_cons_printf ("axc 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
} else if (t == R_ANAL_REF_TYPE_STRING) {
@ -3244,7 +3262,8 @@ static int fcn_print_legacy(RCore *core, RAnalFunction *fcn, bool dorefs) {
r_cons_printf ("\ncode-xrefs:");
r_list_foreach (xrefs, iter, refi) {
int rt = R_ANAL_REF_TYPE_MASK (refi->type);
if (rt == R_ANAL_REF_TYPE_CODE || rt == R_ANAL_REF_TYPE_CALL) {
// TODO: just check for the exec perm
if (rt == R_ANAL_REF_TYPE_CODE || rt == R_ANAL_REF_TYPE_CALL || rt == R_ANAL_REF_TYPE_ICOD) {
indegree++;
r_cons_printf (" 0x%08"PFMT64x" %c", refi->addr,
rt == R_ANAL_REF_TYPE_CALL? 'C': 'J');
@ -4227,6 +4246,7 @@ static bool found_xref(RCore *core, ut64 at, ut64 xref_to, RAnalRefType type, PJ
// Display in radare commands format
char *cmd;
switch (type) {
case R_ANAL_REF_TYPE_ICOD: cmd = "axi"; break;
case R_ANAL_REF_TYPE_CODE: cmd = "axc"; break;
case R_ANAL_REF_TYPE_CALL: cmd = "axC"; break;
case R_ANAL_REF_TYPE_DATA: cmd = "axd"; break;

View File

@ -1016,6 +1016,7 @@ static RCoreHelpMessage help_msg_ax = {
"axg", " [addr]", "show xrefs graph to reach current function",
"axg*", " [addr]", "show xrefs graph to given address, use .axg*;aggv",
"axgj", " [addr]", "show xrefs graph to reach current function in json format",
"axi", " addr [at]", "add indirect code reference (see ax?)",
"axj", "", "add jmp reference", // list refs in json format",
"axl", "[jcq]", "list xrefs (axlc = count, axlq = quiet, axlj = json)",
"axm", " addr [at]", "copy data/code references pointing to addr to also point to curseek (or at)",
@ -5284,6 +5285,7 @@ static int cmd_af(RCore *core, const char *input) {
r_cons_printf ("0x%08" PFMT64x " ", ref->addr);
break;
case R_ANAL_REF_TYPE_CODE:
case R_ANAL_REF_TYPE_ICOD:
case R_ANAL_REF_TYPE_JUMP:
case R_ANAL_REF_TYPE_CALL:
case R_ANAL_REF_TYPE_DATA:
@ -9672,31 +9674,36 @@ static bool cmd_anal_refs(RCore *core, const char *input) {
break;
case 'C': // "axC"
case 'c': // "axc"
case 'i': // "axi"
case 'r': // "axr"
case 'w': // "axw"
case 'j': // "axj"
case 'd': // "axd"
case 's': // "axs"
case ' ': // "ax "
{
char *ptr = strdup (r_str_trim_head_ro ((char *)input + 1));
int n = r_str_word_set0 (ptr);
ut64 at = core->offset;
ut64 addr = UT64_MAX;
RAnalRefType reftype = r_anal_xrefs_type (input[0]);
switch (n) {
case 2: // get at
at = r_num_math (core->num, r_str_word_get0 (ptr, 1));
/* fall through */
case 1: // get addr
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
break;
default:
if (input[1] == '?') {
char *s = r_str_newf ("ax%c", input[0]);
r_core_cmd_help_match (core, help_msg_ax, s, true);
free (s);
} else {
char *ptr = strdup (r_str_trim_head_ro ((char *)input + 1));
int n = r_str_word_set0 (ptr);
ut64 at = core->offset;
ut64 addr = UT64_MAX;
RAnalRefType reftype = r_anal_xrefs_type (input[0]);
switch (n) {
case 2: // get at
at = r_num_math (core->num, r_str_word_get0 (ptr, 1));
/* fall through */
case 1: // get addr
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
break;
default:
free (ptr);
return false;
}
r_anal_xrefs_set (core->anal, at, addr, reftype);
free (ptr);
return false;
}
r_anal_xrefs_set (core->anal, at, addr, reftype);
free (ptr);
}
break;
default:

View File

@ -659,8 +659,9 @@ typedef enum {
R_ANAL_REF_TYPE_CALL = 'C', // code ref (call) -- maybe use 'k' for kall?
R_ANAL_REF_TYPE_JUMP = 'j', // code ref (call)
R_ANAL_REF_TYPE_DATA = 'd', // mem ref
R_ANAL_REF_TYPE_STRING = 's', // string ref // R_DEPRECATE
R_ANAL_REF_TYPE_STRN = 's', // string ref
R_ANAL_REF_TYPE_ICOD = 'i', // indirect code reference
R_ANAL_REF_TYPE_STRING = 's', // string ref // R_DEPRECATE
R_ANAL_REF_TYPE_STRN = 's', // string ref
// perm / direction
R_ANAL_REF_TYPE_READ = 4 << 8,
R_ANAL_REF_TYPE_WRITE = 2 << 8,