2016-08-13 10:09:14 +00:00
|
|
|
/* radare - LGPL - Copyright 2016 - oddcoder */
|
2016-08-16 11:38:40 +00:00
|
|
|
/* type matching - type propagation */
|
2016-08-16 01:26:26 +00:00
|
|
|
|
2016-08-13 10:09:14 +00:00
|
|
|
#include <r_anal.h>
|
|
|
|
#include <r_util.h>
|
|
|
|
#include <r_core.h>
|
|
|
|
|
|
|
|
static bool r_anal_emul_init (RCore *core) {
|
|
|
|
r_config_set (core->config, "esil.romem", "true");
|
|
|
|
r_config_set (core->config, "asm.trace", "true");
|
|
|
|
r_config_set (core->config, "anal.trace", "true");
|
|
|
|
r_config_set (core->config, "dbg.trace", "true");
|
|
|
|
r_config_set (core->config, "esil.nonull", "true");
|
2016-08-22 09:22:22 +00:00
|
|
|
const char *bp = r_reg_get_name (core->anal->reg, R_REG_NAME_BP);
|
|
|
|
const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
|
|
|
|
if ((bp && !r_reg_getv (core->anal->reg, bp)) || (sp && !r_reg_getv (core->anal->reg, sp))) {
|
|
|
|
eprintf ("Stack isn't initiatized.\n");
|
|
|
|
eprintf ("Try running aei and aeim commands before aftm for default stack initialization\n");
|
|
|
|
return false;
|
|
|
|
}
|
2016-08-17 23:27:11 +00:00
|
|
|
return (core->anal->esil != NULL);
|
2016-08-13 10:09:14 +00:00
|
|
|
}
|
2016-08-15 15:34:12 +00:00
|
|
|
|
2016-08-14 00:07:43 +00:00
|
|
|
static void type_match (RCore *core, ut64 addr, char *name) {
|
2016-08-13 10:09:14 +00:00
|
|
|
Sdb *trace = core->anal->esil->db_trace;
|
|
|
|
RAnal *anal = core->anal;
|
|
|
|
RAnalVar *v;
|
2016-08-14 00:07:43 +00:00
|
|
|
char *fcn_name;
|
|
|
|
if (r_anal_type_func_exist (anal, name)) {
|
|
|
|
fcn_name = strdup (name);
|
|
|
|
} else if (!(fcn_name = r_anal_type_func_guess (anal, name))) {
|
2016-08-15 15:34:12 +00:00
|
|
|
eprintf ("can't find function prototype for %s\n", name);
|
2016-08-13 10:09:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const char* cc = r_anal_type_func_cc (anal, fcn_name);
|
|
|
|
if (!cc || !r_anal_cc_exist (anal, cc)) {
|
2016-08-17 23:27:11 +00:00
|
|
|
eprintf("cant find %s calling convention %s\n", fcn_name, cc);
|
2016-08-13 10:09:14 +00:00
|
|
|
}
|
|
|
|
int i, j, max = r_anal_type_func_args_count (anal, fcn_name);
|
|
|
|
int size = 0, idx = sdb_num_get (trace, "idx", 0);
|
|
|
|
const char *sp_name = r_reg_get_name (anal->reg, R_REG_NAME_SP);
|
|
|
|
const char *bp_name = r_reg_get_name (anal->reg, R_REG_NAME_BP);
|
2016-08-22 09:22:22 +00:00
|
|
|
ut64 sp = r_reg_getv (anal->reg, sp_name);
|
|
|
|
ut64 bp = r_reg_getv (anal->reg, bp_name);
|
2016-08-13 10:09:14 +00:00
|
|
|
for (i = 0; i < max; i++) {
|
|
|
|
char *type = r_anal_type_func_args_type (anal, fcn_name, i);
|
|
|
|
const char *name =r_anal_type_func_args_name (anal, fcn_name, i);
|
|
|
|
const char *place = r_anal_cc_arg (anal, cc, i + 1);
|
|
|
|
if (!strcmp (place, "stack")) {
|
2016-08-23 01:02:23 +00:00
|
|
|
// type_match_stack ();
|
2016-08-13 10:09:14 +00:00
|
|
|
for (j = idx; j >= 0; j--) {
|
|
|
|
ut64 write_addr = sdb_num_get (trace, sdb_fmt (-1, "%d.mem.write", j), 0);
|
|
|
|
if (write_addr == sp + size) {
|
|
|
|
ut64 instr_addr = sdb_num_get (trace, sdb_fmt (-1, "%d.addr", j), 0);
|
|
|
|
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, instr_addr,
|
|
|
|
sdb_fmt (-1, "%s %s", type, name));
|
|
|
|
char *tmp = sdb_fmt (-1, "%d.mem.read", j);
|
|
|
|
int i2, array_size = sdb_array_size (trace, tmp);
|
|
|
|
for (i2 = 0; i2 < array_size; i2++) {
|
|
|
|
if (bp_name) {
|
|
|
|
int bp_idx = sdb_array_get_num (trace, tmp, i2, 0) - bp;
|
|
|
|
if ((v =r_anal_var_get (anal, addr, R_ANAL_VAR_KIND_BPV, 1, bp_idx))) {
|
|
|
|
r_anal_var_retype (anal, addr, 1, bp_idx, R_ANAL_VAR_KIND_BPV, type, -1, v->name);
|
|
|
|
r_anal_var_free (v);
|
|
|
|
}
|
|
|
|
}
|
2016-08-15 15:34:12 +00:00
|
|
|
int sp_idx = sdb_array_get_num (trace, tmp, i2, 0) - sp;
|
2016-08-23 01:02:23 +00:00
|
|
|
if ((v = r_anal_var_get (anal, addr, R_ANAL_VAR_KIND_SPV, 1, sp_idx))) {
|
2016-08-13 10:09:14 +00:00
|
|
|
r_anal_var_retype (anal, addr, 1, sp_idx, R_ANAL_VAR_KIND_SPV, type, -1, v->name);
|
|
|
|
r_anal_var_free (v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
size += r_anal_type_get_size (anal, type) / 8;
|
|
|
|
} else if (!strcmp (place , "stack_rev")) {
|
2016-08-23 01:02:23 +00:00
|
|
|
// type_match_stack_rev ();
|
2016-08-13 10:09:14 +00:00
|
|
|
free (type);
|
|
|
|
int k;
|
|
|
|
for ( k = max -1; k >=i; k--) {
|
|
|
|
type = r_anal_type_func_args_type (anal, fcn_name, k);
|
|
|
|
name =r_anal_type_func_args_name (anal, fcn_name, k);
|
|
|
|
place = r_anal_cc_arg (anal, cc, k + 1);
|
|
|
|
if (strcmp (place ,"stack_rev")) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (j = idx; j >= 0; j--) {
|
|
|
|
ut64 write_addr = sdb_num_get (trace, sdb_fmt (-1, "%d.mem.write", j), 0);
|
|
|
|
if (write_addr == sp + size) {
|
|
|
|
ut64 instr_addr = sdb_num_get (trace, sdb_fmt (-1, "%d.addr", j), 0);
|
|
|
|
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, instr_addr,
|
|
|
|
sdb_fmt (-1, "%s %s", type, name));
|
|
|
|
char *tmp = sdb_fmt (-1, "%d.mem.read", j);
|
|
|
|
int i2, array_size = sdb_array_size (trace, tmp);
|
|
|
|
for (i2 = 0; i2 < array_size; i2++) {
|
|
|
|
if (bp_name) {
|
|
|
|
int bp_idx = sdb_array_get_num (trace, tmp, i2, 0) - bp;
|
|
|
|
if ((v =r_anal_var_get (anal, addr, R_ANAL_VAR_KIND_BPV, 1, bp_idx))) {
|
|
|
|
r_anal_var_retype (anal, addr, 1, bp_idx, R_ANAL_VAR_KIND_BPV, type, -1, v->name);
|
|
|
|
r_anal_var_free (v);
|
|
|
|
}
|
|
|
|
}
|
2016-08-15 15:34:12 +00:00
|
|
|
int sp_idx = sdb_array_get_num (trace, tmp, i2, 0) - sp;
|
2016-08-13 10:09:14 +00:00
|
|
|
if ((v =r_anal_var_get (anal, addr, R_ANAL_VAR_KIND_SPV, 1, sp_idx))) {
|
|
|
|
r_anal_var_retype (anal, addr, 1, sp_idx, R_ANAL_VAR_KIND_SPV, type, -1, v->name);
|
|
|
|
r_anal_var_free (v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2016-08-23 01:02:23 +00:00
|
|
|
size += r_anal_type_get_size (anal, type) / 8;
|
2016-08-13 10:09:14 +00:00
|
|
|
}
|
2016-08-15 15:34:12 +00:00
|
|
|
break;
|
2016-08-13 10:09:14 +00:00
|
|
|
} else {
|
2016-08-23 01:02:23 +00:00
|
|
|
// type_match_reg ();
|
2016-08-13 10:09:14 +00:00
|
|
|
for (j = idx; j >= 0; j--) {
|
|
|
|
if (sdb_array_contains (trace, sdb_fmt (-1, "%d.reg.write", j), place, 0)) {
|
|
|
|
ut64 instr_addr = sdb_num_get (trace, sdb_fmt (-1, "%d.addr", j), 0);
|
|
|
|
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, instr_addr,
|
|
|
|
sdb_fmt (-1, "%s %s", type, name));
|
|
|
|
char *tmp = sdb_fmt (-1, "%d.mem.read", j);
|
|
|
|
int i2, array_size = sdb_array_size (trace, tmp);
|
|
|
|
for (i2 = 0; i2 < array_size; i2++) {
|
|
|
|
if (bp_name) {
|
|
|
|
int bp_idx = sdb_array_get_num (trace, tmp, i2, 0) - bp;
|
|
|
|
if ((v =r_anal_var_get (anal, addr, R_ANAL_VAR_KIND_BPV, 1, bp_idx))) {
|
|
|
|
r_anal_var_retype (anal, addr, 1, bp_idx, R_ANAL_VAR_KIND_BPV, type, -1, v->name);
|
|
|
|
r_anal_var_free (v);
|
|
|
|
}
|
|
|
|
}
|
2016-08-15 15:34:12 +00:00
|
|
|
int sp_idx = sdb_array_get_num (trace, tmp, i2, 0) - sp;
|
2016-08-13 10:09:14 +00:00
|
|
|
if ((v =r_anal_var_get (anal, addr, R_ANAL_VAR_KIND_SPV, 1, sp_idx))) {
|
|
|
|
r_anal_var_retype (anal, addr, 1, sp_idx, R_ANAL_VAR_KIND_SPV, type, -1, v->name);
|
|
|
|
r_anal_var_free (v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free (type);
|
|
|
|
}
|
2016-08-14 00:07:43 +00:00
|
|
|
free (fcn_name);
|
2016-08-13 10:09:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int stack_clean (RCore *core, ut64 addr, RAnalFunction *fcn) {
|
2016-08-16 11:38:40 +00:00
|
|
|
int offset, ret;
|
|
|
|
char *tmp, *str, *sig;
|
2016-08-13 10:09:14 +00:00
|
|
|
RAnalOp *op = r_core_anal_op (core, addr);
|
2016-08-16 11:38:40 +00:00
|
|
|
if (!op) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
str = strdup (r_strbuf_get (&op->esil));
|
|
|
|
if (!str) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
tmp = strchr (str, ',');
|
2016-08-13 10:09:14 +00:00
|
|
|
if (!tmp) {
|
2016-08-15 07:54:25 +00:00
|
|
|
free (str);
|
2016-08-13 10:09:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*tmp++ = 0;
|
2016-08-16 11:38:40 +00:00
|
|
|
|
|
|
|
offset = r_num_math (core->num, str);
|
2016-08-13 10:09:14 +00:00
|
|
|
const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
|
2016-08-16 11:38:40 +00:00
|
|
|
sig = sdb_fmt (-1, "%s,+=", sp);
|
|
|
|
ret = 0;
|
2016-08-13 10:09:14 +00:00
|
|
|
if (!strncmp (tmp, sig, strlen (sig))) {
|
2016-08-16 11:38:40 +00:00
|
|
|
const char *esil = sdb_fmt (-1, "%d,%s,-=", offset, sp);
|
2016-08-13 10:09:14 +00:00
|
|
|
r_anal_esil_parse (core->anal->esil, esil);
|
|
|
|
r_anal_esil_dumpstack (core->anal->esil);
|
|
|
|
r_anal_esil_stack_free (core->anal->esil);
|
|
|
|
r_core_esil_step (core, UT64_MAX, NULL);
|
|
|
|
ret = op->size;
|
|
|
|
}
|
|
|
|
r_anal_op_free (op);
|
|
|
|
free (str);
|
|
|
|
return ret;
|
|
|
|
}
|
2016-08-16 08:41:16 +00:00
|
|
|
|
2016-08-13 10:09:14 +00:00
|
|
|
R_API void r_anal_type_match(RCore *core, RAnalFunction *fcn) {
|
2016-08-15 07:54:25 +00:00
|
|
|
if (!core || !r_anal_emul_init (core) || !fcn ) {
|
2016-08-13 10:09:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-08-22 09:22:22 +00:00
|
|
|
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
|
|
|
ut64 addr = fcn->addr;
|
|
|
|
r_reg_setv (core->dbg->reg, pc, fcn->addr);
|
2016-08-13 10:09:14 +00:00
|
|
|
r_debug_reg_sync (core->dbg, -1, true);
|
2016-08-16 08:43:33 +00:00
|
|
|
r_cons_break (NULL, NULL);
|
|
|
|
while (!r_cons_is_breaked ()) {
|
2016-08-13 10:09:14 +00:00
|
|
|
RAnalOp *op = r_core_anal_op (core, addr);
|
2016-08-16 01:26:26 +00:00
|
|
|
if (!op || op->type == R_ANAL_OP_TYPE_RET) {
|
2016-08-13 10:09:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (op->type == R_ANAL_OP_TYPE_CALL) {
|
|
|
|
RAnalFunction *fcn_call = r_anal_get_fcn_in (core->anal, op->jump, -1);
|
|
|
|
//eprintf ("in the middle of %s\n", fcn_call->name);
|
2016-08-16 08:41:16 +00:00
|
|
|
if (fcn_call) {
|
|
|
|
type_match (core, addr, fcn_call->name);
|
|
|
|
addr += op->size;
|
|
|
|
r_anal_op_free (op);
|
2016-08-22 09:22:22 +00:00
|
|
|
r_reg_setv (core->dbg->reg, pc, addr);
|
2016-08-16 08:41:16 +00:00
|
|
|
r_debug_reg_sync (core->dbg, -1, true);
|
|
|
|
r_anal_esil_set_pc (core->anal->esil, addr);
|
|
|
|
addr += stack_clean (core, addr, fcn);
|
2016-08-22 09:22:22 +00:00
|
|
|
r_reg_setv (core->dbg->reg, pc, addr);
|
2016-08-16 08:41:16 +00:00
|
|
|
r_debug_reg_sync (core->dbg, -1, true);
|
|
|
|
r_anal_esil_set_pc (core->anal->esil, addr);
|
|
|
|
} else {
|
|
|
|
eprintf ("Cannot find function at 0x%08"PFMT64x"\n", op->jump);
|
|
|
|
break;
|
|
|
|
}
|
2016-08-13 10:09:14 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
r_core_esil_step (core, UT64_MAX, NULL);
|
|
|
|
r_anal_op_free (op);
|
|
|
|
}
|
2016-08-22 09:22:22 +00:00
|
|
|
r_core_cmd0 (core, ".ar*");
|
|
|
|
addr = r_reg_getv (core->anal->reg, pc);
|
2016-08-13 10:09:14 +00:00
|
|
|
}
|
2016-08-16 08:43:33 +00:00
|
|
|
r_cons_break_end ();
|
2016-08-13 10:09:14 +00:00
|
|
|
}
|