mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-11 15:04:23 +00:00
739 lines
20 KiB
C
739 lines
20 KiB
C
/* radare - LGPL - Copyright 2009-2016 - Alexandru Caciulescu */
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "r_core.h"
|
|
#include "r_io.h"
|
|
#include "r_list.h"
|
|
#include "r_types_base.h"
|
|
|
|
static RList* parse_list (const char *str) {
|
|
RList *list;
|
|
char *line, *data, *p, *str_n;
|
|
|
|
if (!str) {
|
|
return NULL;
|
|
}
|
|
|
|
str_n = strdup (str);
|
|
list = r_list_newf (free);
|
|
if (!list) {
|
|
free (str_n);
|
|
return NULL;
|
|
}
|
|
line = strtok (str_n, "\n");
|
|
data = strchr (line, '=');
|
|
p = strtok (data + 1, ",");
|
|
|
|
while (p) {
|
|
r_list_append (list, (void*)strdup (p));
|
|
p = strtok (NULL, ",");
|
|
}
|
|
|
|
free (str_n);
|
|
return list;
|
|
}
|
|
|
|
static RList* get_constants(const char *str) {
|
|
RList *list;
|
|
char *p, *data;
|
|
if (!str) {
|
|
return NULL;
|
|
}
|
|
|
|
data = strdup (str);
|
|
list = r_list_newf (free);
|
|
p = strtok (data, ",");
|
|
while (p) {
|
|
if (strtol (p, NULL, 0)) {
|
|
r_list_append (list, (void*)strdup (p));
|
|
}
|
|
p = strtok (NULL, ",");
|
|
}
|
|
return list;
|
|
}
|
|
|
|
static bool isFlag (RRegItem *reg) {
|
|
const char *type = r_reg_get_type (reg->type);
|
|
|
|
if (!strcmp (type, "flg"))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// binary op
|
|
static bool simulate_op (const char *op, ut64 src1, ut64 src2, ut64 old_src1, ut64 old_src2, ut64 *result, int size) {
|
|
ut64 limit;
|
|
|
|
if (size == 64) {
|
|
limit = UT64_MAX;
|
|
} else {
|
|
limit = 1ULL << size;
|
|
}
|
|
|
|
if (!strcmp (op, "^")) {
|
|
*result = src1 ^ src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "+")) {
|
|
*result = src1 + src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "-")) {
|
|
if (src2 > src1) {
|
|
*result = limit + (src1 - src2);
|
|
} else {
|
|
*result = src1 - src2;
|
|
}
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "*")) {
|
|
*result = src1 * src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "|")) {
|
|
*result = src1 | src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "/")) {
|
|
*result = src1 / src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "%")) {
|
|
*result = src1 % src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "<<")) {
|
|
*result = src1 << src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, ">>")) {
|
|
*result = src1 >> src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "&")) {
|
|
*result = src1 & src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "+=")) {
|
|
*result = old_src1 + src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "-=")) {
|
|
if (src2 > old_src1) {
|
|
*result = limit + (old_src1 - src2);
|
|
} else {
|
|
*result = old_src1 - src2;
|
|
}
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "*=")) {
|
|
*result = old_src1 * src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "/=")) {
|
|
*result = old_src1 / src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "%=")) {
|
|
*result = old_src1 % src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "<<")) {
|
|
*result = src1 << src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, ">>")) {
|
|
*result = src1 >> src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "&=")) {
|
|
*result = src1 & src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "^=")) {
|
|
*result = src1 ^ src2;
|
|
return true;
|
|
}
|
|
if (!strcmp (op, "|=")) {
|
|
*result = src1 | src2;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// fill REGs with known values
|
|
static void fillRegisterValues (RCore *core) {
|
|
RListIter *iter_reg;
|
|
RList *regs;
|
|
RRegItem *reg_item;
|
|
int nr = 10;
|
|
|
|
regs = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!regs) {
|
|
return;
|
|
}
|
|
r_list_foreach (regs, iter_reg, reg_item) {
|
|
r_reg_arena_pop (core->dbg->reg);
|
|
r_reg_set_value (core->dbg->reg, reg_item, nr);
|
|
r_reg_arena_push (core->dbg->reg);
|
|
nr += 3;
|
|
}
|
|
}
|
|
|
|
// split esil string in flags part and main instruction
|
|
// hacky, only tested for x86, TODO: portable version
|
|
// NOTE: esil_main and esil_flg are heap allocated and must be freed by the caller
|
|
static void esil_split_flg (char *esil_str, char **esil_main, char **esil_flg) {
|
|
char *split = strstr (esil_str, "f,=");
|
|
const int kCommaHits = 2;
|
|
int hits = 0;
|
|
|
|
if (split) {
|
|
while (hits != kCommaHits) {
|
|
--split;
|
|
if (*split == ',') {
|
|
hits++;
|
|
}
|
|
}
|
|
*esil_flg = strdup (++split);
|
|
*esil_main = r_str_ndup (esil_str, strlen (esil_str) - strlen (*esil_flg) - 1);
|
|
}
|
|
}
|
|
|
|
#define FREE_ROP { \
|
|
R_FREE (out); \
|
|
R_FREE (esil_flg); \
|
|
R_FREE (esil_main); \
|
|
r_list_free (ops_list); \
|
|
ops_list = NULL; \
|
|
r_list_free (flg_read); \
|
|
flg_read = NULL; \
|
|
r_list_free (flg_write); \
|
|
flg_write = NULL; \
|
|
r_list_free (reg_read); \
|
|
reg_read = NULL; \
|
|
r_list_free (reg_write); \
|
|
reg_write = NULL; \
|
|
r_list_free (mem_read); \
|
|
mem_read = NULL; \
|
|
r_list_free (mem_write); \
|
|
mem_write = NULL; \
|
|
}
|
|
|
|
static char* rop_classify_constant(RCore *core, RList *ropList) {
|
|
char *esil_str, *constant;
|
|
char *ct = NULL, *esil_main = NULL, *esil_flg = NULL, *out = NULL;
|
|
RListIter *iter_r, *iter_dst, *iter_const;
|
|
RRegItem *item_dst;
|
|
RList *head, *constants;
|
|
RList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL,
|
|
*reg_read = NULL, *reg_write = NULL, *mem_read = NULL,
|
|
*mem_write = NULL;
|
|
const bool romem = r_config_get_i (core->config, "esil.romem");
|
|
const bool stats = r_config_get_i (core->config, "esil.stats");
|
|
|
|
if (!romem || !stats) {
|
|
// eprintf ("Error: esil.romem and esil.stats must be set TRUE");
|
|
return NULL;
|
|
}
|
|
|
|
r_list_foreach (ropList, iter_r, esil_str) {
|
|
constants = get_constants (esil_str);
|
|
// if there are no constants in the instruction continue
|
|
if (r_list_empty (constants)) {
|
|
continue;
|
|
}
|
|
// init regs with known values
|
|
fillRegisterValues (core);
|
|
head = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!head) {
|
|
ct = NULL;
|
|
goto continue_error;
|
|
}
|
|
esil_split_flg (esil_str, &esil_main, &esil_flg);
|
|
cmd_anal_esil (core, esil_main? esil_main: esil_str);
|
|
out = sdb_querys (core->anal->esil->stats, NULL, 0, "*");
|
|
if (!out) {
|
|
goto continue_error;
|
|
}
|
|
ops_list = parse_list (strstr (out, "ops.list"));
|
|
flg_read = parse_list (strstr (out, "flg.read"));
|
|
flg_write = parse_list (strstr (out, "flg.write"));
|
|
reg_read = parse_list (strstr (out, "reg.read"));
|
|
reg_write = parse_list (strstr (out, "reg.write"));
|
|
mem_read = parse_list (strstr (out, "mem.read"));
|
|
mem_write = parse_list (strstr (out, "mem.write"));
|
|
if (!r_list_find (ops_list, "=", (RListComparator)strcmp)) {
|
|
goto continue_error;
|
|
}
|
|
head = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!head) {
|
|
goto out_error;
|
|
}
|
|
r_list_foreach (head, iter_dst, item_dst) {
|
|
ut64 diff_dst, value_dst;
|
|
if (!r_list_find (reg_write, item_dst->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
|
|
value_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
//restore initial value
|
|
r_reg_set_value (core->dbg->reg, item_dst, diff_dst);
|
|
|
|
if (value_dst != diff_dst) {
|
|
r_list_foreach (constants, iter_const, constant) {
|
|
if (value_dst == r_num_get (NULL, constant)) {
|
|
ct = r_str_concatf (ct, "%s <-- 0x%"PFMT64x";", item_dst->name, value_dst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continue_error:
|
|
// coverity may complain here but as long as the pointer is set back to
|
|
// NULL is safe that is why is used R_FREE
|
|
FREE_ROP;
|
|
r_list_free (constants);
|
|
}
|
|
return ct;
|
|
out_error:
|
|
FREE_ROP;
|
|
r_list_free (constants);
|
|
return NULL;
|
|
}
|
|
|
|
static char* rop_classify_mov(RCore *core, RList *ropList) {
|
|
char *esil_str;
|
|
char *mov = NULL, *esil_main = NULL, *esil_flg = NULL, *out = NULL;
|
|
RListIter *iter_src, *iter_r, *iter_dst;
|
|
RRegItem *item_src, *item_dst;
|
|
RList *head;
|
|
RList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL,
|
|
*reg_read = NULL, *reg_write = NULL, *mem_read = NULL,
|
|
*mem_write = NULL;
|
|
const bool romem = r_config_get_i (core->config, "esil.romem");
|
|
const bool stats = r_config_get_i (core->config, "esil.stats");
|
|
|
|
if (!romem || !stats) {
|
|
// eprintf ("Error: esil.romem and esil.stats must be set TRUE");
|
|
return NULL;
|
|
}
|
|
|
|
r_list_foreach (ropList, iter_r, esil_str) {
|
|
// init regs with known values
|
|
fillRegisterValues (core);
|
|
head = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!head) {
|
|
goto out_error;
|
|
}
|
|
esil_split_flg (esil_str, &esil_main, &esil_flg);
|
|
cmd_anal_esil (core, esil_main? esil_main: esil_str);
|
|
out = sdb_querys (core->anal->esil->stats, NULL, 0, "*");
|
|
if (out) {
|
|
ops_list = parse_list (strstr (out, "ops.list"));
|
|
flg_read = parse_list (strstr (out, "flg.read"));
|
|
flg_write = parse_list (strstr (out, "flg.write"));
|
|
reg_read = parse_list (strstr (out, "reg.read"));
|
|
reg_write = parse_list (strstr (out, "reg.write"));
|
|
mem_read = parse_list (strstr (out, "mem.read"));
|
|
mem_write = parse_list (strstr (out, "mem.write"));
|
|
} else {
|
|
goto continue_error;
|
|
}
|
|
|
|
if (!r_list_find (ops_list, "=", (RListComparator)strcmp)) {
|
|
goto continue_error;
|
|
}
|
|
|
|
head = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!head) {
|
|
goto out_error;
|
|
}
|
|
r_list_foreach (head, iter_dst, item_dst) {
|
|
ut64 diff_dst, value_dst;
|
|
if (!r_list_find (reg_write, item_dst->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
|
|
// you never mov into flags
|
|
if (isFlag (item_dst)) {
|
|
continue;
|
|
}
|
|
|
|
value_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
r_list_foreach (head, iter_src, item_src) {
|
|
ut64 diff_src, value_src;
|
|
if (!r_list_find (reg_read, item_src->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
// you never mov from flags
|
|
if (item_src == item_dst || isFlag (item_src)) {
|
|
continue;
|
|
}
|
|
value_src = r_reg_get_value (core->dbg->reg, item_src);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_src = r_reg_get_value (core->dbg->reg, item_src);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
//restore initial value
|
|
r_reg_set_value (core->dbg->reg, item_src, diff_src);
|
|
if (value_dst == value_src && value_dst != diff_dst) {
|
|
mov = r_str_concatf (mov, "%s <-- %s;",
|
|
item_dst->name, item_src->name);
|
|
}
|
|
}
|
|
}
|
|
continue_error:
|
|
FREE_ROP;
|
|
}
|
|
return mov;
|
|
out_error:
|
|
FREE_ROP;
|
|
return NULL;
|
|
}
|
|
|
|
static char* rop_classify_arithmetic(RCore *core, RList *ropList) {
|
|
char *esil_str, *op;
|
|
char *arithmetic = NULL, *esil_flg = NULL, *esil_main = NULL,
|
|
*out = NULL;
|
|
RListIter *iter_src1, *iter_src2, *iter_r, *iter_dst, *iter_ops;
|
|
RRegItem *item_src1, *item_src2, *item_dst;
|
|
RList *head;
|
|
RList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL,
|
|
*reg_read = NULL, *reg_write = NULL, *mem_read = NULL,
|
|
*mem_write = NULL;
|
|
const bool romem = r_config_get_i (core->config, "esil.romem");
|
|
const bool stats = r_config_get_i (core->config, "esil.stats");
|
|
ut64 *op_result = R_NEW0 (ut64);
|
|
ut64 *op_result_r = R_NEW0 (ut64);
|
|
|
|
if (!romem || !stats) {
|
|
// eprintf ("Error: esil.romem and esil.stats must be set TRUE");
|
|
free (op_result);
|
|
free (op_result_r);
|
|
return NULL;
|
|
}
|
|
|
|
r_list_foreach (ropList, iter_r, esil_str) {
|
|
// init regs with known values
|
|
fillRegisterValues (core);
|
|
head = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!head) {
|
|
goto out_error;
|
|
}
|
|
esil_split_flg (esil_str, &esil_main, &esil_flg);
|
|
if (esil_main) {
|
|
cmd_anal_esil (core, esil_main);
|
|
} else {
|
|
cmd_anal_esil (core, esil_str);
|
|
}
|
|
out = sdb_querys (core->anal->esil->stats, NULL, 0, "*");
|
|
// r_cons_println (out);
|
|
if (!out) {
|
|
goto continue_error;
|
|
}
|
|
ops_list = parse_list (strstr (out, "ops.list"));
|
|
flg_read = parse_list (strstr (out, "flg.read"));
|
|
flg_write = parse_list (strstr (out, "flg.write"));
|
|
reg_read = parse_list (strstr (out, "reg.read"));
|
|
reg_write = parse_list (strstr (out, "reg.write"));
|
|
mem_read = parse_list (strstr (out, "mem.read"));
|
|
mem_write = parse_list (strstr (out, "mem.write"));
|
|
|
|
r_list_foreach (ops_list, iter_ops, op) {
|
|
r_list_foreach (head, iter_src1, item_src1) {
|
|
ut64 value_src1, diff_src1;
|
|
|
|
value_src1 = r_reg_get_value (core->dbg->reg, item_src1);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_src1 = r_reg_get_value (core->dbg->reg, item_src1);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
if (!r_list_find (reg_read, item_src1->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
|
|
r_list_foreach (head, iter_src2, item_src2) {
|
|
ut64 value_src2, diff_src2;
|
|
value_src2 = r_reg_get_value (core->dbg->reg, item_src2);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_src2 = r_reg_get_value (core->dbg->reg, item_src2);
|
|
|
|
if (!r_list_find (reg_read, item_src2->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
// TODO check condition
|
|
if (iter_src1 == iter_src2) {
|
|
continue;
|
|
}
|
|
|
|
r_list_foreach (head, iter_dst, item_dst) {
|
|
ut64 value_dst;
|
|
bool redundant = false, simulate, simulate_r;
|
|
|
|
value_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
if (!r_list_find (reg_write, item_dst->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
// dont check flags for arithmetic
|
|
if (isFlag (item_dst)) {
|
|
continue;
|
|
}
|
|
simulate = simulate_op (op, value_src1, value_src2, diff_src1, diff_src2, op_result, item_dst->size);
|
|
simulate_r = simulate_op (op, value_src2, value_src1, diff_src2, diff_src1, op_result_r, item_dst->size);
|
|
if (/*value_src1 != 0 && value_src2 != 0 && */simulate && value_dst == *op_result) {
|
|
// r_cons_println ("Debug: FOUND ONE !");
|
|
char *tmp = r_str_newf ("%s <-- %s %s %s;", item_dst->name, item_src1->name, op, item_src2->name);
|
|
if (arithmetic && !strstr (arithmetic, tmp)) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
} else if (!arithmetic) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
}
|
|
free (tmp);
|
|
redundant = true;
|
|
} else if (!redundant /*&& value_src1 != 0 && value_src2 != 0*/ && simulate_r && value_dst == *op_result_r) {
|
|
// r_cons_println ("Debug: FOUND ONE reversed!");
|
|
char *tmp = r_str_newf ("%s <-- %s %s %s;", item_dst->name, item_src2->name, op, item_src1->name);
|
|
if (arithmetic && !strstr (arithmetic, tmp)) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
} else if (!arithmetic) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
}
|
|
free (tmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continue_error:
|
|
FREE_ROP;
|
|
}
|
|
free (op_result);
|
|
free (op_result_r);
|
|
return arithmetic;
|
|
out_error:
|
|
FREE_ROP;
|
|
free (op_result);
|
|
free (op_result_r);
|
|
return NULL;
|
|
}
|
|
|
|
static char* rop_classify_arithmetic_const(RCore *core, RList *ropList) {
|
|
char *esil_str, *op, *constant;
|
|
char *arithmetic = NULL, *esil_flg = NULL, *esil_main = NULL;
|
|
RListIter *iter_src1, *iter_r, *iter_dst, *iter_ops, *iter_const;
|
|
RRegItem *item_src1, *item_dst;
|
|
RList *head, *constants;
|
|
RList *ops_list = NULL, *flg_read = NULL, *flg_write = NULL, *reg_read = NULL,
|
|
*reg_write = NULL, *mem_read = NULL, *mem_write = NULL;
|
|
const bool romem = r_config_get_i (core->config, "esil.romem");
|
|
const bool stats = r_config_get_i (core->config, "esil.stats");
|
|
ut64 *op_result = R_NEW0 (ut64);
|
|
ut64 *op_result_r = R_NEW0 (ut64);
|
|
|
|
if (!romem || !stats) {
|
|
// eprintf ("Error: esil.romem and esil.stats must be set TRUE");
|
|
free (op_result);
|
|
free (op_result_r);
|
|
return NULL;
|
|
}
|
|
|
|
r_list_foreach (ropList, iter_r, esil_str) {
|
|
constants = get_constants (esil_str);
|
|
// if there are no constants in the instruction continue
|
|
if (r_list_empty (constants)) {
|
|
continue;
|
|
}
|
|
// init regs with known values
|
|
fillRegisterValues (core);
|
|
head = r_reg_get_list (core->dbg->reg, 0);
|
|
if (!head) {
|
|
arithmetic = NULL;
|
|
continue;
|
|
}
|
|
esil_split_flg (esil_str, &esil_main, &esil_flg);
|
|
if (esil_main) {
|
|
cmd_anal_esil (core, esil_main);
|
|
} else {
|
|
cmd_anal_esil (core, esil_str);
|
|
}
|
|
char *out = sdb_querys (core->anal->esil->stats, NULL, 0, "*");
|
|
// r_cons_println (out);
|
|
if (out) {
|
|
ops_list = parse_list (strstr (out, "ops.list"));
|
|
flg_read = parse_list (strstr (out, "flg.read"));
|
|
flg_write = parse_list (strstr (out, "flg.write"));
|
|
reg_read = parse_list (strstr (out, "reg.read"));
|
|
reg_write = parse_list (strstr (out, "reg.write"));
|
|
mem_read = parse_list (strstr (out, "mem.read"));
|
|
mem_write = parse_list (strstr (out, "mem.write"));
|
|
} else {
|
|
free (op_result);
|
|
free (op_result_r);
|
|
goto continue_error;
|
|
}
|
|
|
|
r_list_foreach (ops_list, iter_ops, op) {
|
|
r_list_foreach (head, iter_src1, item_src1) {
|
|
ut64 value_src1, diff_src1;
|
|
value_src1 = r_reg_get_value (core->dbg->reg, item_src1);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_src1 = r_reg_get_value (core->dbg->reg, item_src1);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
|
|
if (!r_list_find (reg_read, item_src1->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
r_list_foreach (head, iter_dst, item_dst) {
|
|
ut64 value_dst, diff_dst;
|
|
bool redundant = false, simulate, simulate_r;
|
|
value_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
diff_dst = r_reg_get_value (core->dbg->reg, item_dst);
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
|
if (!r_list_find (reg_write, item_dst->name,
|
|
(RListComparator)strcmp)) {
|
|
continue;
|
|
}
|
|
// dont check flags for arithmetic
|
|
if (isFlag (item_dst)) {
|
|
continue;
|
|
}
|
|
if (value_dst != diff_dst) {
|
|
r_list_foreach (constants, iter_const, constant) {
|
|
ut64 value_ct = r_num_get (NULL, constant);
|
|
simulate = simulate_op (op, value_src1, value_ct,
|
|
diff_src1, value_ct, op_result,
|
|
item_dst->size);
|
|
simulate_r = simulate_op (op, value_ct, value_src1,
|
|
value_ct, diff_src1, op_result_r,
|
|
item_dst->size);
|
|
if (simulate && value_dst == *op_result) {
|
|
char *tmp = r_str_newf ("%s <-- %s %s %s;", item_dst->name, item_src1->name, op, constant);
|
|
if (arithmetic && !strstr (arithmetic, tmp)) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
} else if (!arithmetic) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
}
|
|
free (tmp);
|
|
redundant = true;
|
|
} else if (!redundant && simulate_r && value_dst == *op_result_r) {
|
|
char *tmp = r_str_newf ("%s <-- %s %s %s;", item_dst->name, constant, op, item_src1->name);
|
|
if (arithmetic && !strstr (arithmetic, tmp)) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
} else if (!arithmetic) {
|
|
arithmetic = r_str_concat (arithmetic, tmp);
|
|
}
|
|
free (tmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continue_error:
|
|
FREE_ROP;
|
|
r_list_free (constants);
|
|
}
|
|
free (op_result);
|
|
free (op_result_r);
|
|
return arithmetic;
|
|
}
|
|
|
|
static int rop_classify_nops(RCore *core, RList *ropList) {
|
|
char *esil_str;
|
|
int changes = 1;
|
|
RListIter *iter_r;
|
|
const bool romem = r_config_get_i (core->config, "esil.romem");
|
|
const bool stats = r_config_get_i (core->config, "esil.stats");
|
|
|
|
if (!romem || !stats) {
|
|
// eprintf ("Error: esil.romem and esil.stats must be set TRUE");
|
|
return -2;
|
|
}
|
|
|
|
r_list_foreach (ropList, iter_r, esil_str) {
|
|
fillRegisterValues (core);
|
|
|
|
// r_cons_printf ("Emulating nop:%s\n", esil_str);
|
|
cmd_anal_esil (core, esil_str);
|
|
char *out = sdb_querys (core->anal->esil->stats, NULL, 0, "*");
|
|
// r_cons_println (out);
|
|
if (out) {
|
|
free (out);
|
|
return 0;
|
|
}
|
|
// directly say NOP
|
|
continue;
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
static void rop_classify (RCore *core, Sdb *db, RList *ropList, const char *key, unsigned int size) {
|
|
Sdb *db_nop = NULL, *db_mov = NULL, *db_ct = NULL, *db_aritm = NULL, *db_aritm_ct = NULL;
|
|
int nop = 0; rop_classify_nops (core, ropList);
|
|
char *mov, *ct, *arithm, *arithm_ct, *str;
|
|
db_nop = sdb_ns (db, "nop", true);
|
|
db_mov = sdb_ns (db, "mov", true);
|
|
db_ct = sdb_ns (db, "const", true);
|
|
db_aritm = sdb_ns (db, "arithm", true);
|
|
db_aritm_ct = sdb_ns (db, "arithm_ct", true);
|
|
|
|
if (!db_nop || !db_mov || !db_ct || !db_aritm || !db_aritm_ct) {
|
|
eprintf ("Error: Could not create SDB 'rop' sub-namespaces\n");
|
|
return;
|
|
}
|
|
nop = rop_classify_nops (core, ropList);
|
|
mov = rop_classify_mov (core, ropList);
|
|
ct = rop_classify_constant (core, ropList);
|
|
arithm = rop_classify_arithmetic (core, ropList);
|
|
arithm_ct = rop_classify_arithmetic_const (core, ropList);
|
|
str = r_str_newf ("0x%"PFMT64x, size);
|
|
|
|
if (nop == 1) {
|
|
char *str_nop = r_str_newf ("%s NOP", str);
|
|
sdb_set (db_nop, key, str_nop, 0);
|
|
free (str_nop);
|
|
} else {
|
|
if (mov) {
|
|
char *str_mov = r_str_newf ("%s MOV { %s }", str, mov);
|
|
sdb_set (db_mov, key, str_mov, 0);
|
|
free (str_mov);
|
|
free (mov);
|
|
}
|
|
if (ct) {
|
|
char *str_ct = r_str_newf ("%s LOAD_CONST { %s }", str, ct);
|
|
sdb_set (db_ct, key, str_ct, 0);
|
|
free (str_ct);
|
|
free (ct);
|
|
}
|
|
if (arithm) {
|
|
char *str_arithm = r_str_newf ("%s ARITHMETIC { %s }", str, arithm);
|
|
sdb_set (db_aritm, key, str_arithm, 0);
|
|
free (str_arithm);
|
|
free (arithm);
|
|
}
|
|
if (arithm_ct) {
|
|
char *str_arithm_ct = r_str_newf ("%s ARITHMETIC_CONST { %s }", str, arithm_ct);
|
|
sdb_set (db_aritm_ct, key, str_arithm_ct, 0);
|
|
free (str_arithm_ct);
|
|
free (arithm_ct);
|
|
}
|
|
}
|
|
|
|
free (str);
|
|
}
|