radare2/libr/anal/esil2reil.c
2017-11-28 22:43:17 +01:00

1203 lines
33 KiB
C

/*
* Convert from ESIL to REIL (Reverse Engineering Intermediate Language)
* Contributor: sushant94
*/
#include <r_anal.h>
#define REIL_TEMP_PREFIX "V"
#define REIL_REG_PREFIX "R_"
#define REGBUFSZ 32
void reil_flag_spew_inst(RAnalEsil *esil, const char *flag);
static const char *ops[] = { FOREACHOP(REIL_OP_STRING) };
// Get size of a register.
static ut8 esil_internal_sizeof_reg(RAnalEsil *esil, const char *r) {
if (!esil || !esil->anal || !esil->anal->reg || !r) {
return false;
}
RRegItem *i = r_reg_get(esil->anal->reg, r, -1);
return i ? (ut8)i->size : 0;
}
RAnalReilArgType reil_get_arg_type(RAnalEsil *esil, char *s) {
if (!strncmp (s, REIL_TEMP_PREFIX, strlen (REIL_TEMP_PREFIX))) {
return ARG_TEMP;
}
int type = r_anal_esil_get_parm_type(esil, s);
switch (type) {
case R_ANAL_ESIL_PARM_REG:
return ARG_REG;
case R_ANAL_ESIL_PARM_NUM:
return ARG_CONST;
case R_ANAL_ESIL_PARM_INTERNAL:
return ARG_ESIL_INTERNAL;
default:
return ARG_NONE;
}
}
// Marshall the struct into a string
void reil_push_arg(RAnalEsil *esil, RAnalReilArg *op) {
char *s = r_str_newf ("%s:%d", op->name, op->size);
r_anal_esil_push (esil, s);
free (s);
}
// Unmarshall the string in stack to the struct.
RAnalReilArg *reil_pop_arg(RAnalEsil *esil) {
RAnalReilArg *op;
int i, j = 0, flag = 0, len;
char tmp_buf[REGBUFSZ];
char *buf = r_anal_esil_pop(esil);
if (!buf) {
return NULL;
}
len = strlen (buf);
op = R_NEW0(RAnalReilArg);
for (i = 0; i < len; i++) {
if (buf[i] == ':') {
tmp_buf[j] = '\0';
strncpy(op->name, tmp_buf, sizeof(op->name) - 1);
memset(tmp_buf, 0, sizeof(tmp_buf));
j = 0;
flag = 1;
continue;
}
// Strip all spaces
if (buf[i] == ' ') continue;
tmp_buf[j] = buf[i];
j++;
}
tmp_buf[j] = '\0';
// If we have not encountered a ':' we don't know the size yet.
if (!flag) {
strncpy(op->name, tmp_buf, sizeof(op->name) - 1);
op->type = reil_get_arg_type(esil, op->name);
if (op->type == ARG_REG) {
op->size = esil_internal_sizeof_reg(esil, op->name);
} else if (op->type == ARG_CONST) {
op->size = esil->anal->bits;
}
free(buf);
return op;
}
op->size = strtoll(tmp_buf, NULL, 10);
op->type = reil_get_arg_type(esil, op->name);
free(buf);
return op;
}
// Get the next available temp register.
void get_next_temp_reg(RAnalEsil *esil, char *buf) {
r_snprintf (buf, REGBUFSZ, REIL_TEMP_PREFIX"_%02"PFMT64u,
esil->Reil->reilNextTemp);
esil->Reil->reilNextTemp++;
}
void reil_make_arg(RAnalEsil *esil, RAnalReilArg *arg, char *name) {
if (!arg) return;
RAnalReilArgType type;
type = reil_get_arg_type(esil, name);
arg->size = 0;
arg->type = type;
memset(arg->name, 0, sizeof(arg->name));
strncpy(arg->name, name, sizeof(arg->name) - 1);
}
// Free ins and all its arguments
void reil_free_inst(RAnalReilInst *ins) {
if (!ins) return;
if (ins->arg[0]) R_FREE(ins->arg[0]);
if (ins->arg[1]) R_FREE(ins->arg[1]);
if (ins->arg[2]) R_FREE(ins->arg[2]);
R_FREE(ins);
}
// Automatically increments the seq_num of the instruction.
void reil_print_inst(RAnalEsil *esil, RAnalReilInst *ins) {
char tmp_buf[REGBUFSZ];
int i;
if ((!ins) || (!esil)) {
return;
}
esil->anal->cb_printf("%04"PFMT64x".%02"PFMT64x": %8s",
esil->Reil->addr, esil->Reil->seq_num++, ops[ins->opcode]);
for (i = 0; i < 3; i++) {
if (i > 0) {
esil->anal->cb_printf (" ,");
}
if (!ins->arg[i]) {
continue;
}
if (ins->arg[i]->type == ARG_NONE) {
esil->anal->cb_printf ("%10s ", ins->arg[i]->name);
continue;
}
if (ins->arg[i]->type == ARG_REG) {
strncpy (tmp_buf, REIL_REG_PREFIX, sizeof (tmp_buf) - 1);
strncat (tmp_buf, ins->arg[i]->name, sizeof (tmp_buf) - strlen (tmp_buf) - 1);
esil->anal->cb_printf ("%10s:%02d", tmp_buf, ins->arg[i]->size);
continue;
}
esil->anal->cb_printf ("%10s:%02d", ins->arg[i]->name, ins->arg[i]->size);
}
esil->anal->cb_printf("\n");
}
// Used to cast sizes during assignment. OR is used for casting.
// Pushes the new *casted* src onto stack. Warning: Frees the original src!
void reil_cast_size(RAnalEsil *esil, RAnalReilArg *src, RAnalReilArg *dst) {
char tmp_buf[REGBUFSZ];
RAnalReilInst *ins;
if (!src || !dst) {
return;
}
// No need to case sizes if dst and src are of same size.
if (src->size == dst->size) {
reil_push_arg(esil, src);
return;
}
snprintf (tmp_buf, REGBUFSZ-1, "0:%d", dst->size);
r_anal_esil_push (esil, tmp_buf);
ins = R_NEW0 (RAnalReilInst);
if (!ins) return;
ins->opcode = REIL_OR;
ins->arg[0] = src;
ins->arg[1] = reil_pop_arg (esil);
ins->arg[2] = R_NEW0(RAnalReilArg);
get_next_temp_reg (esil, tmp_buf);
reil_make_arg (esil, ins->arg[2], tmp_buf);
if (ins->arg[2])
ins->arg[2]->size = dst->size;
reil_print_inst (esil, ins);
if (ins->arg[2])
reil_push_arg (esil, ins->arg[2]);
reil_free_inst (ins);
}
// Here start translation functions!
static int reil_eq(RAnalEsil *esil) {
RAnalReilInst *ins;
char tmp_buf[REGBUFSZ];
RAnalReilArgType src_type, dst_type;
RAnalReilArg *dst, *src;
dst = reil_pop_arg (esil);
if (!dst) return false;
src = reil_pop_arg (esil);
if (!src) {
R_FREE (dst);
return false;
}
src_type = src->type;
// Check if the src is an internal var. If it is, we need to resolve it.
if (src_type == ARG_ESIL_INTERNAL) {
reil_flag_spew_inst (esil, src->name + 1);
R_FREE (src);
src = reil_pop_arg (esil);
} else if (src_type == ARG_REG) {
// No direct register to register transfer.
ins = R_NEW0 (RAnalReilInst);
if (!ins) return false;
ins->opcode = REIL_STR;
ins->arg[0] = src;
ins->arg[1] = R_NEW0 (RAnalReilArg);
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
ins->arg[2] = R_NEW0(RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
return false;
}
reil_make_arg (esil, ins->arg[1], " ");
get_next_temp_reg (esil, tmp_buf);
reil_make_arg (esil, ins->arg[2], tmp_buf);
ins->arg[2]->size = ins->arg[0]->size;
reil_print_inst (esil, ins);
reil_push_arg( esil, ins->arg[2]);
reil_free_inst (ins);
src = reil_pop_arg (esil);
}
// First, make a copy of the dst. We will need this to set the flags later on.
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (dst);
R_FREE (src);
return false;
}
dst_type = dst->type;
if (src_type != ARG_ESIL_INTERNAL && dst_type == ARG_REG) {
ins->opcode = REIL_STR;
ins->arg[0] = dst;
ins->arg[1] = R_NEW0 (RAnalReilArg);
if (!ins->arg[1]) {
reil_free_inst (ins);
R_FREE (src);
return false;
}
ins->arg[2] = R_NEW0 (RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
R_FREE (src);
return false;
}
reil_make_arg (esil, ins->arg[1], " ");
get_next_temp_reg (esil, tmp_buf);
reil_make_arg (esil, ins->arg[2], tmp_buf);
ins->arg[2]->size = ins->arg[0]->size;
reil_print_inst (esil, ins);
// Used for setting the flags
r_snprintf (esil->Reil->old, sizeof (esil->Reil->old) - 1, "%s:%d",
ins->arg[2]->name, ins->arg[2]->size);
r_snprintf (esil->Reil->cur, sizeof (esil->Reil->cur) - 1, "%s:%d", dst->name,
dst->size);
esil->Reil->lastsz = dst->size;
R_FREE (ins->arg[1]);
R_FREE (ins->arg[2]);
}
// If we are modifying the Instruction Pointer, then we need to emit JCC instead.
if (!strcmp(esil->Reil->pc, dst->name)) {
ins->opcode = REIL_JCC;
r_anal_esil_push (esil, "1:1");
ins->arg[0] = reil_pop_arg (esil);
ins->arg[1] = R_NEW0 (RAnalReilArg);
reil_make_arg (esil, ins->arg[1], " ");
ins->arg[2] = src;
reil_print_inst (esil, ins);
reil_free_inst (ins);
R_FREE (dst);
return true;
}
reil_cast_size (esil, src, dst);
ins->opcode = REIL_STR;
ins->arg[0] = reil_pop_arg (esil);
if (!ins->arg[0]) {
R_FREE (dst);
reil_free_inst (ins);
return false;
}
ins->arg[2] = dst;
ins->arg[1] = R_NEW0 (RAnalReilArg);
reil_make_arg (esil, ins->arg[1], " ");
reil_print_inst (esil, ins);
reil_free_inst (ins);
return true;
}
// General function for operations that take 2 operands
static int reil_binop(RAnalEsil *esil, RAnalReilOpcode opcode) {
RAnalReilInst *ins;
char tmp_buf[REGBUFSZ];
ut8 dst_size;
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg(esil);
if (!op2) return false;
op1 = reil_pop_arg(esil);
if (!op1) {
R_FREE (op2);
return false;
}
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op1);
R_FREE (op2);
return false;
}
ins->opcode = opcode;
ins->arg[0] = op2;
ins->arg[1] = op1;
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
ins->arg[2] = R_NEW0(RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
return false;
}
get_next_temp_reg(esil, tmp_buf);
reil_make_arg(esil, ins->arg[2], tmp_buf);
// Choose the larger of the two sizes as the size of dst
dst_size = ins->arg[0]->size;
if (dst_size < ins->arg[1]->size)
dst_size = ins->arg[1]->size;
// REIL_LT has a dst_size of 1.
if (opcode == REIL_LT)
dst_size = 1;
ins->arg[2]->size = dst_size;
reil_print_inst(esil, ins);
reil_push_arg(esil, ins->arg[2]);
reil_free_inst(ins);
return true;
}
// General function for operations which re-assign to dst. Example, addeq.
static int reil_bineqop(RAnalEsil *esil, RAnalReilOpcode opcode) {
int ret = 1;
RAnalReilArg *op = reil_pop_arg(esil);
if (!op) return false;
reil_push_arg(esil, op);
ret &= reil_binop(esil, opcode);
reil_push_arg(esil, op);
ret &= reil_eq(esil);
R_FREE(op);
return ret;
}
static int reil_add(RAnalEsil *esil) { return reil_binop (esil, REIL_ADD); }
static int reil_addeq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_ADD); }
static int reil_mul(RAnalEsil *esil) { return reil_binop (esil, REIL_MUL); }
static int reil_muleq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_MUL); }
static int reil_sub(RAnalEsil *esil) { return reil_binop (esil, REIL_SUB); }
static int reil_subeq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_SUB); }
static int reil_div(RAnalEsil *esil) { return reil_binop (esil, REIL_DIV); }
static int reil_diveq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_DIV); }
static int reil_xor(RAnalEsil *esil) { return reil_binop (esil, REIL_XOR); }
static int reil_xoreq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_XOR); }
static int reil_and(RAnalEsil *esil) { return reil_binop (esil, REIL_AND); }
static int reil_andeq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_AND); }
static int reil_or(RAnalEsil *esil) { return reil_binop (esil, REIL_OR); }
static int reil_oreq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_OR); }
static int reil_lsl(RAnalEsil *esil) { return reil_binop (esil, REIL_SHL); }
static int reil_lsleq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_SHL); }
static int reil_lsr(RAnalEsil *esil) { return reil_binop (esil, REIL_SHR); }
static int reil_lsreq(RAnalEsil *esil) { return reil_bineqop (esil, REIL_SHR); }
static int reil_smaller(RAnalEsil *esil) { return reil_binop (esil, REIL_LT); }
static int reil_cmp(RAnalEsil *esil) {
RAnalReilInst *ins;
char tmp_buf[REGBUFSZ];
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg (esil);
if (!op2) return false;
op1 = reil_pop_arg (esil);
if (!op1) {
R_FREE (op2);
return false;
}
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op1);
R_FREE (op2);
return false;
}
ins->opcode = REIL_EQ;
ins->arg[0] = op2;
ins->arg[1] = op1;
ins->arg[2] = R_NEW0 (RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
return false;
}
get_next_temp_reg (esil, tmp_buf);
reil_make_arg (esil, ins->arg[2], tmp_buf);
ins->arg[2]->size = 1;
reil_print_inst (esil, ins);
// Set vars needed to determine flags.
r_snprintf (esil->Reil->cur, sizeof (esil->Reil->old) - 1, "%s:%d",
ins->arg[2]->name, ins->arg[2]->size);
r_snprintf (esil->Reil->old, sizeof (esil->Reil->cur) - 1, "%s:%d",
op2->name, op2->size);
if (r_reg_get (esil->anal->reg, op2->name, -1)) {
esil->Reil->lastsz = op2->size;
} else if (r_reg_get (esil->anal->reg, op1->name, -1)) {
esil->Reil->lastsz = op1->size;
}
reil_push_arg (esil, ins->arg[2]);
reil_free_inst (ins);
return true;
}
static int reil_smaller_equal(RAnalEsil *esil) {
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg(esil);
if (!op2) return false;
op1 = reil_pop_arg(esil);
if (!op1) {
R_FREE (op2);
return false;
}
reil_push_arg(esil, op1);
reil_push_arg(esil, op2);
reil_smaller(esil);
reil_push_arg(esil, op1);
reil_push_arg(esil, op2);
reil_cmp(esil);
reil_or(esil);
R_FREE(op1);
R_FREE(op2);
return true;
}
static int reil_larger(RAnalEsil *esil) {
RAnalReilArg *op2 = reil_pop_arg(esil);
if (!op2) {
return false;
}
RAnalReilArg *op1 = reil_pop_arg(esil);
if (!op1) {
R_FREE (op2);
return false;
}
reil_push_arg (esil, op2);
reil_push_arg (esil, op1);
reil_smaller (esil);
R_FREE (op1);
R_FREE (op2);
return true;
}
static int reil_larger_equal(RAnalEsil *esil) {
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg(esil);
if (!op2) return false;
op1 = reil_pop_arg(esil);
if (!op1) {
R_FREE (op2);
return false;
}
reil_push_arg (esil, op2);
reil_push_arg (esil, op1);
reil_smaller_equal (esil);
R_FREE (op1);
R_FREE (op2);
return true;
}
static int reil_dec(RAnalEsil *esil) {
RAnalReilArg *op = reil_pop_arg(esil);
if (!op) {
return false;
}
r_anal_esil_pushnum (esil, 1);
reil_push_arg (esil, op);
reil_sub (esil);
R_FREE (op);
return true;
}
static int reil_deceq(RAnalEsil *esil) {
RAnalReilArg *op1 = reil_pop_arg(esil);
if (!op1) {
return false;
}
reil_push_arg (esil, op1);
reil_dec (esil);
reil_push_arg (esil, op1);
reil_eq (esil);
R_FREE (op1);
return true;
}
static int reil_inc(RAnalEsil *esil) {
RAnalReilArg *op = reil_pop_arg(esil);
if (!op) return false;
r_anal_esil_pushnum(esil, 1);
reil_push_arg(esil, op);
reil_add(esil);
R_FREE(op);
return true;
}
static int reil_inceq(RAnalEsil *esil) {
RAnalReilArg *op = reil_pop_arg(esil);
if (!op) {
return false;
}
reil_push_arg (esil, op);
reil_inc (esil);
reil_push_arg (esil, op);
reil_eq (esil);
R_FREE (op);
return true;
}
static int reil_neg(RAnalEsil *esil) {
char tmp_buf[REGBUFSZ];
RAnalReilInst *ins;
RAnalReilArg *op = reil_pop_arg (esil);
if (!op) {
return false;
}
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op);
return false;
}
ins->opcode = REIL_EQ;
ins->arg[0] = op;
r_anal_esil_pushnum (esil, 0);
ins->arg[1] = reil_pop_arg(esil);
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
ins->arg[2] = R_NEW0 (RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
return false;
}
get_next_temp_reg (esil, tmp_buf);
reil_make_arg(esil, ins->arg[2], tmp_buf);
if (ins->arg[0]->size < ins->arg[1]->size)
ins->arg[1]->size = ins->arg[0]->size;
ins->arg[2]->size = 1;
reil_print_inst (esil, ins);
reil_push_arg (esil, ins->arg[2]);
reil_free_inst (ins);
return true;
}
static int reil_negeq(RAnalEsil *esil) {
RAnalReilArg *op = reil_pop_arg(esil);
if (!op) return false;
reil_push_arg (esil, op);
reil_neg (esil);
reil_push_arg (esil, op);
reil_eq (esil);
free (op);
return true;
}
static int reil_not(RAnalEsil *esil) {
char tmp_buf[REGBUFSZ];
RAnalReilInst *ins;
RAnalReilArg *op = reil_pop_arg (esil);
if (!op) return false;
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op);
return false;
}
ins->opcode = REIL_NOT;
ins->arg[0] = op;
ins->arg[1] = R_NEW0 (RAnalReilArg);
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
ins->arg[2] = R_NEW0 (RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
return false;
}
reil_make_arg (esil, ins->arg[1], " ");
get_next_temp_reg (esil, tmp_buf);
reil_make_arg (esil, ins->arg[2], tmp_buf);
ins->arg[2]->size = ins->arg[0]->size;
reil_print_inst (esil, ins);
reil_push_arg (esil, ins->arg[2]);
reil_free_inst (ins);
return true;
}
static int reil_if(RAnalEsil *esil) {
RAnalReilInst *ins;
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg (esil);
if (!op2) return false;
op1 = reil_pop_arg (esil);
if (!op1) {
R_FREE (op2);
return false;
}
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op2);
R_FREE (op1);
return false;
}
ins->opcode = REIL_JCC;
ins->arg[0] = op1;
ins->arg[2] = op2;
ins->arg[1] = R_NEW0 (RAnalReilArg);
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
reil_make_arg (esil, ins->arg[1], " ");
reil_print_inst (esil, ins);
reil_free_inst (ins);
return true;
}
static int reil_if_end(RAnalEsil *esil) { return true; }
static int reil_peek(RAnalEsil *esil) {
RAnalReilInst *ins;
char tmp_buf[REGBUFSZ];
RAnalReilArg *op1 = reil_pop_arg(esil);
if (!op1) return false;
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op1);
return false;
}
ins->opcode = REIL_LDM;
ins->arg[0] = op1;
ins->arg[1] = R_NEW0(RAnalReilArg);
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
ins->arg[2] = R_NEW0(RAnalReilArg);
if (!ins->arg[2]) {
reil_free_inst (ins);
return false;
}
reil_make_arg(esil, ins->arg[1], " ");
get_next_temp_reg(esil, tmp_buf);
reil_make_arg(esil, ins->arg[2], tmp_buf);
ins->arg[2]->size = ins->arg[0]->size;
reil_print_inst(esil, ins);
reil_push_arg(esil, ins->arg[2]);
reil_free_inst(ins);
return true;
}
// n = 8, 4, 2, 1
static int reil_peekn(RAnalEsil *esil, ut8 n) {
RAnalReilArg *op2;
RAnalReilArg *op1 = reil_pop_arg (esil);
if (!op1) return false;
reil_push_arg (esil, op1);
reil_peek (esil);
// No need to cast if n = 0
if (n == 0) {
R_FREE (op1);
return true;
}
R_FREE (op1);
op1 = reil_pop_arg (esil);
if (!op1) return false;
op2 = R_NEW0 (RAnalReilArg);
if (!op2) {
R_FREE (op1);
return false;
}
op2->size = n * 8;
op2->type = ARG_TEMP;
get_next_temp_reg (esil, op2->name);
reil_cast_size (esil, op1, op2);
esil->Reil->lastsz = 8 * n;
R_FREE (op2);
return true;
}
static int reil_peek1(RAnalEsil *esil) { return reil_peekn(esil, 1); }
static int reil_peek2(RAnalEsil *esil) { return reil_peekn(esil, 2); }
static int reil_peek4(RAnalEsil *esil) { return reil_peekn(esil, 4); }
static int reil_peek8(RAnalEsil *esil) { return reil_peekn(esil, 8); }
// n = 8, 4, 2, 1
static int reil_poken(RAnalEsil *esil, ut8 n) {
char tmp_buf[REGBUFSZ];
RAnalReilInst *ins;
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg (esil);
if (!op2) return false;
op1 = reil_pop_arg (esil);
if (!op1) {
R_FREE (op2);
return false;
}
if (op1->type != ARG_ESIL_INTERNAL) {
ins = R_NEW0 (RAnalReilInst);
if (!ins) {
R_FREE (op2);
R_FREE (op1);
return false;
}
ins->opcode = REIL_LDM;
ins->arg[0] = op2;
ins->arg[1] = R_NEW0(RAnalReilArg);
if (!ins->arg[1]) {
R_FREE (op1);
reil_free_inst (ins);
return false;
}
ins->arg[2] = R_NEW0(RAnalReilArg);
if (!ins->arg[2]) {
R_FREE (op1);
reil_free_inst (ins);
return false;
}
reil_make_arg (esil, ins->arg[1], " ");
get_next_temp_reg (esil, tmp_buf);
reil_make_arg (esil, ins->arg[2], tmp_buf);
ins->arg[2]->size = ins->arg[0]->size;
reil_print_inst (esil, ins);
r_snprintf (esil->Reil->old, sizeof (esil->Reil->old) - 1, "%s:%d",
ins->arg[2]->name, ins->arg[2]->size);
r_snprintf (esil->Reil->cur, sizeof (esil->Reil->cur) - 1, "%s:%d",
op2->name, op2->size);
esil->lastsz = n * 8;
reil_push_arg (esil, op1);
reil_push_arg (esil, op2);
R_FREE (op1);
reil_free_inst (ins);
} else {
reil_flag_spew_inst (esil, op1->name + 1);
R_FREE (op1);
op1 = reil_pop_arg (esil);
reil_push_arg (esil, op2);
reil_push_arg (esil, op1);
R_FREE (op2);
R_FREE (op1);
}
ins = R_NEW0 (RAnalReilInst);
if (!ins) return false;
ins->opcode = REIL_STM;
ins->arg[2] = reil_pop_arg (esil);
ins->arg[0] = reil_pop_arg (esil);
ins->arg[1] = R_NEW0 (RAnalReilArg);
if (!ins->arg[1]) {
reil_free_inst (ins);
return false;
}
reil_make_arg(esil, ins->arg[1], " ");
reil_print_inst(esil, ins);
reil_free_inst(ins);
return true;
}
static int reil_poke(RAnalEsil *esil) {
return reil_poken (esil, esil->anal->bits / 8);
}
static int reil_poke1(RAnalEsil *esil) { return reil_poken(esil, 1); }
static int reil_poke2(RAnalEsil *esil) { return reil_poken(esil, 2); }
static int reil_poke4(RAnalEsil *esil) { return reil_poken(esil, 4); }
static int reil_poke8(RAnalEsil *esil) { return reil_poken(esil, 8); }
// Generic function to handle all mem_*eq_n functions. Example, mem_oreq_n
static int reil_mem_bineq_n(RAnalEsil *esil, RAnalReilOpcode opcode, ut8 size) {
int ret = 1;
RAnalReilArg *op2, *op1;
op2 = reil_pop_arg (esil);
if (!op2) return false;
op1 = reil_pop_arg (esil);
if (!op1) {
R_FREE (op2);
return false;
}
reil_push_arg(esil, op2);
ret &= reil_peekn(esil, size);
reil_push_arg(esil, op1);
ret &= reil_binop(esil, opcode);
reil_push_arg(esil, op2);
ret &= reil_poken(esil, size);
free (op2);
free (op1);
return ret;
}
static int reil_mem_oreq(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_OR, esil->anal->bits / 8); }
static int reil_mem_oreq1(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_OR, 1); }
static int reil_mem_oreq2(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_OR, 2); }
static int reil_mem_oreq4(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_OR, 4); }
static int reil_mem_oreq8(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_OR, 8); }
static int reil_mem_andeq(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_AND, esil->anal->bits / 8); }
static int reil_mem_andeq1(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_AND, 1); }
static int reil_mem_andeq2(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_AND, 2); }
static int reil_mem_andeq4(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_AND, 4); }
static int reil_mem_andeq8(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_AND, 8); }
static int reil_mem_xoreq(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_XOR, esil->anal->bits / 8); }
static int reil_mem_xoreq1(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_XOR, 1); }
static int reil_mem_xoreq2(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_XOR, 2); }
static int reil_mem_xoreq4(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_XOR, 4); }
static int reil_mem_xoreq8(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_XOR, 8); }
static int reil_mem_addeq(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_ADD, esil->anal->bits / 8); }
static int reil_mem_addeq1(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_ADD, 1); }
static int reil_mem_addeq2(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_ADD, 2); }
static int reil_mem_addeq4(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_ADD, 4); }
static int reil_mem_addeq8(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_ADD, 8); }
static int reil_mem_subeq(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_SUB, esil->anal->bits / 8); }
static int reil_mem_subeq1(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_SUB, 1); }
static int reil_mem_subeq2(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_SUB, 2); }
static int reil_mem_subeq4(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_SUB, 4); }
static int reil_mem_subeq8(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_SUB, 8); }
static int reil_mem_muleq(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_MUL, esil->anal->bits / 8); }
static int reil_mem_muleq1(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_MUL, 1); }
static int reil_mem_muleq2(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_MUL, 2); }
static int reil_mem_muleq4(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_MUL, 4); }
static int reil_mem_muleq8(RAnalEsil *esil) { return reil_mem_bineq_n(esil, REIL_MUL, 8); }
static int reil_mem_inceq_n(RAnalEsil *esil, ut8 size) {
int ret = 1;
RAnalReilArg *op1 = reil_pop_arg(esil);
if (!op1) return false;
r_anal_esil_pushnum(esil, 1);
reil_push_arg(esil, op1);
ret &= reil_mem_bineq_n(esil, REIL_ADD, size);
free (op1);
return ret;
}
static int reil_mem_inceq(RAnalEsil *esil) {
return reil_mem_inceq_n(esil, esil->anal->bits / 8);
}
static int reil_mem_inceq1(RAnalEsil *esil) { return reil_mem_inceq_n(esil, 1); }
static int reil_mem_inceq2(RAnalEsil *esil) { return reil_mem_inceq_n(esil, 2); }
static int reil_mem_inceq4(RAnalEsil *esil) { return reil_mem_inceq_n(esil, 4); }
static int reil_mem_inceq8(RAnalEsil *esil) { return reil_mem_inceq_n(esil, 8); }
static int reil_mem_deceq_n(RAnalEsil *esil, ut8 size) {
int ret = 1;
RAnalReilArg *op1 = reil_pop_arg(esil);
if (!op1) return false;
r_anal_esil_pushnum(esil, 1);
reil_push_arg(esil, op1);
ret &= reil_mem_bineq_n(esil, REIL_SUB, size);
free (op1);
return ret;
}
static int reil_mem_deceq(RAnalEsil *esil) {
return reil_mem_deceq_n(esil, esil->anal->bits / 8);
}
static int reil_mem_deceq1(RAnalEsil *esil) { return reil_mem_deceq_n(esil, 1); }
static int reil_mem_deceq2(RAnalEsil *esil) { return reil_mem_deceq_n(esil, 2); }
static int reil_mem_deceq4(RAnalEsil *esil) { return reil_mem_deceq_n(esil, 4); }
static int reil_mem_deceq8(RAnalEsil *esil) { return reil_mem_deceq_n(esil, 8); }
// Functions to resolve internal vars.
// performs (2 << op) - 1
void reil_generate_mask(RAnalEsil *esil) {
r_anal_esil_pushnum(esil, 2);
reil_lsl(esil);
reil_dec(esil);
}
void reil_generate_borrow_flag(RAnalEsil *esil, ut8 bit) {
RAnalReilArg *op1;
r_anal_esil_pushnum(esil, bit);
r_anal_esil_pushnum(esil, 0x3f);
reil_and(esil);
r_anal_esil_pushnum(esil, 0x3f);
reil_add(esil);
r_anal_esil_pushnum(esil, 0x3f);
reil_and(esil);
// Generate the mask. 2 << bits - 1
reil_generate_mask(esil);
op1 = reil_pop_arg(esil);
// old & mask
r_anal_esil_push(esil, esil->Reil->old);
reil_push_arg(esil, op1);
reil_and(esil);
// cur & mask
r_anal_esil_push(esil, esil->Reil->cur);
reil_push_arg(esil, op1);
reil_and(esil);
// Check
reil_larger(esil);
free (op1);
}
void reil_generate_carry_flag(RAnalEsil *esil, ut8 bit) {
RAnalReilArg *op1;
r_anal_esil_pushnum(esil, bit);
r_anal_esil_pushnum(esil, 0x3f);
reil_and(esil);
// Generate the mask. 2 << bits - 1
reil_generate_mask(esil);
op1 = reil_pop_arg(esil);
// old & mask
r_anal_esil_push(esil, esil->Reil->old);
reil_push_arg(esil, op1);
reil_and(esil);
// cur & mask
r_anal_esil_push(esil, esil->Reil->cur);
reil_push_arg(esil, op1);
reil_and(esil);
// Check
reil_smaller(esil);
free (op1);
}
void reil_generate_partity_flag(RAnalEsil *esil) {
// Generation of parity flag taken from openreil README example.
RAnalReilArg *op;
r_anal_esil_push(esil, esil->Reil->cur);
r_anal_esil_pushnum(esil, 0xff);
reil_and(esil);
op = reil_pop_arg(esil);
if (!op) return;
r_anal_esil_pushnum(esil, 7);
reil_push_arg(esil, op);
reil_lsr(esil);
r_anal_esil_pushnum(esil, 6);
reil_push_arg(esil, op);
reil_lsr(esil);
reil_xor(esil);
r_anal_esil_pushnum(esil, 5);
reil_push_arg(esil, op);
reil_lsr(esil);
r_anal_esil_pushnum(esil, 4);
reil_push_arg(esil, op);
reil_lsr(esil);
reil_xor(esil);
reil_xor(esil);
r_anal_esil_pushnum(esil, 3);
reil_push_arg(esil, op);
reil_lsr(esil);
r_anal_esil_pushnum(esil, 2);
reil_push_arg(esil, op);
reil_lsr(esil);
reil_xor(esil);
r_anal_esil_pushnum(esil, 1);
reil_push_arg(esil, op);
reil_lsr(esil);
reil_push_arg(esil, op);
reil_xor(esil);
reil_xor(esil);
reil_xor(esil);
r_anal_esil_pushnum(esil, 1);
reil_and(esil);
reil_not(esil);
free (op);
}
void reil_generate_signature(RAnalEsil *esil) {
if (!esil->Reil->lastsz || esil->Reil->lastsz == 0) {
r_anal_esil_pushnum(esil, 0);
return;
}
RAnalReilArg *op;
r_anal_esil_pushnum(esil, esil->Reil->lastsz - 1);
r_anal_esil_pushnum(esil, 1);
reil_lsl(esil);
r_anal_esil_push(esil, esil->Reil->cur);
reil_and(esil);
op = reil_pop_arg(esil);
if (!op) return;
r_anal_esil_pushnum(esil, esil->Reil->lastsz - 1);
reil_push_arg(esil, op);
reil_lsr(esil);
free (op);
}
void reil_generate_overflow_flag(RAnalEsil *esil) {
if (esil->Reil->lastsz < 2)
r_anal_esil_pushnum(esil, 0);
reil_generate_borrow_flag(esil, esil->Reil->lastsz);
reil_generate_carry_flag(esil, esil->Reil->lastsz - 2);
reil_xor(esil);
}
void reil_flag_spew_inst(RAnalEsil *esil, const char *flag) {
ut8 bit;
switch (flag[0]) {
case 'z': // zero-flag
r_anal_esil_push(esil, esil->Reil->cur);
break;
case 'b':
bit = (ut8)r_num_get(NULL, &flag[1]);
reil_generate_borrow_flag(esil, bit);
break;
case 'c':
bit = (ut8)r_num_get(NULL, &flag[1]);
reil_generate_carry_flag(esil, bit);
break;
case 'o':
reil_generate_overflow_flag(esil);
break;
case 'p':
reil_generate_partity_flag(esil);
break;
case 'r':
r_anal_esil_pushnum(esil, esil->anal->bits / 8);
break;
case 's':
reil_generate_signature(esil);
break;
default:
return;
}
return;
}
/* Callback hook for command_hook */
static int setup_reil_ins(RAnalEsil *esil, const char *op) {
esil->Reil->addr++; // Increment the address location.
esil->Reil->seq_num = 0; // Reset the sequencing.
return 0;
}
R_API int r_anal_esil_to_reil_setup(RAnalEsil *esil, RAnal *anal, int romem,
int stats) {
if (!esil) {
return false;
}
esil->verbose = 2;
esil->anal = anal;
esil->trap = 0;
esil->trap_code = 0;
/* Set up a callback for hook_command */
esil->cb.hook_command = setup_reil_ins;
esil->Reil = R_NEW0(RAnalReil);
if (!esil->Reil) {
return false;
}
esil->Reil->reilNextTemp = 0;
esil->Reil->addr = -1;
esil->Reil->seq_num = 0;
esil->Reil->skip = 0;
// Store the pc
const char *name = r_reg_get_name (esil->anal->reg, r_reg_get_name_idx ("PC"));
strncpy (esil->Reil->pc, name, sizeof (esil->Reil->pc) - 1);
r_anal_esil_mem_ro(esil, romem);
r_anal_esil_set_op(esil, "=", reil_eq);
r_anal_esil_set_op(esil, "+", reil_add);
r_anal_esil_set_op(esil, "+=", reil_addeq);
r_anal_esil_set_op(esil, "-", reil_sub);
r_anal_esil_set_op(esil, "-=", reil_subeq);
r_anal_esil_set_op(esil, "*", reil_mul);
r_anal_esil_set_op(esil, "*=", reil_muleq);
r_anal_esil_set_op(esil, "/", reil_div);
r_anal_esil_set_op(esil, "/=", reil_diveq);
r_anal_esil_set_op(esil, "^", reil_xor);
r_anal_esil_set_op(esil, "^=", reil_xoreq);
r_anal_esil_set_op(esil, "|", reil_or);
r_anal_esil_set_op(esil, "|=", reil_oreq);
r_anal_esil_set_op(esil, "&", reil_and);
r_anal_esil_set_op(esil, "&=", reil_andeq);
r_anal_esil_set_op(esil, "<<", reil_lsl);
r_anal_esil_set_op(esil, "<<=", reil_lsleq);
r_anal_esil_set_op(esil, ">>", reil_lsr);
r_anal_esil_set_op(esil, ">>=", reil_lsreq);
r_anal_esil_set_op(esil, "++=", reil_inceq);
r_anal_esil_set_op(esil, "++", reil_inc);
r_anal_esil_set_op(esil, "--=", reil_deceq);
r_anal_esil_set_op(esil, "--", reil_dec);
r_anal_esil_set_op(esil, "!", reil_neg);
r_anal_esil_set_op(esil, "!=", reil_negeq);
r_anal_esil_set_op(esil, "==", reil_cmp);
r_anal_esil_set_op(esil, "<", reil_smaller);
r_anal_esil_set_op(esil, ">", reil_larger);
r_anal_esil_set_op(esil, "<=", reil_smaller_equal);
r_anal_esil_set_op(esil, ">=", reil_larger_equal);
r_anal_esil_set_op(esil, "[]", reil_peek);
r_anal_esil_set_op(esil, "=[]", reil_poke);
r_anal_esil_set_op(esil, "|=[]", reil_mem_oreq);
r_anal_esil_set_op(esil, "^=[]", reil_mem_xoreq);
r_anal_esil_set_op(esil, "&=[]", reil_mem_andeq);
r_anal_esil_set_op(esil, "+=[]", reil_mem_addeq);
r_anal_esil_set_op(esil, "-=[]", reil_mem_subeq);
r_anal_esil_set_op(esil, "*=[]", reil_mem_muleq);
r_anal_esil_set_op(esil, "++=[]", reil_mem_inceq);
r_anal_esil_set_op(esil, "--=[]", reil_mem_deceq);
r_anal_esil_set_op(esil, "=[1]", reil_poke1);
r_anal_esil_set_op(esil, "=[2]", reil_poke2);
r_anal_esil_set_op(esil, "=[4]", reil_poke4);
r_anal_esil_set_op(esil, "=[8]", reil_poke8);
r_anal_esil_set_op(esil, "[1]", reil_peek1);
r_anal_esil_set_op(esil, "[2]", reil_peek2);
r_anal_esil_set_op(esil, "[4]", reil_peek4);
r_anal_esil_set_op(esil, "[8]", reil_peek8);
r_anal_esil_set_op(esil, "|=[1]", reil_mem_oreq1);
r_anal_esil_set_op(esil, "|=[2]", reil_mem_oreq2);
r_anal_esil_set_op(esil, "|=[4]", reil_mem_oreq4);
r_anal_esil_set_op(esil, "|=[8]", reil_mem_oreq8);
r_anal_esil_set_op(esil, "^=[1]", reil_mem_xoreq1);
r_anal_esil_set_op(esil, "^=[2]", reil_mem_xoreq2);
r_anal_esil_set_op(esil, "^=[4]", reil_mem_xoreq4);
r_anal_esil_set_op(esil, "^=[8]", reil_mem_xoreq8);
r_anal_esil_set_op(esil, "&=[1]", reil_mem_andeq1);
r_anal_esil_set_op(esil, "&=[2]", reil_mem_andeq2);
r_anal_esil_set_op(esil, "&=[4]", reil_mem_andeq4);
r_anal_esil_set_op(esil, "&=[8]", reil_mem_andeq8);
r_anal_esil_set_op(esil, "+=[1]", reil_mem_addeq1);
r_anal_esil_set_op(esil, "+=[2]", reil_mem_addeq2);
r_anal_esil_set_op(esil, "+=[4]", reil_mem_addeq4);
r_anal_esil_set_op(esil, "+=[8]", reil_mem_addeq8);
r_anal_esil_set_op(esil, "-=[1]", reil_mem_subeq1);
r_anal_esil_set_op(esil, "-=[2]", reil_mem_subeq2);
r_anal_esil_set_op(esil, "-=[4]", reil_mem_subeq4);
r_anal_esil_set_op(esil, "-=[8]", reil_mem_subeq8);
r_anal_esil_set_op(esil, "*=[1]", reil_mem_muleq1);
r_anal_esil_set_op(esil, "*=[2]", reil_mem_muleq2);
r_anal_esil_set_op(esil, "*=[4]", reil_mem_muleq4);
r_anal_esil_set_op(esil, "*=[8]", reil_mem_muleq8);
r_anal_esil_set_op(esil, "++=[1]", reil_mem_inceq1);
r_anal_esil_set_op(esil, "++=[2]", reil_mem_inceq2);
r_anal_esil_set_op(esil, "++=[4]", reil_mem_inceq4);
r_anal_esil_set_op(esil, "++=[8]", reil_mem_inceq8);
r_anal_esil_set_op(esil, "--=[1]", reil_mem_deceq1);
r_anal_esil_set_op(esil, "--=[2]", reil_mem_deceq2);
r_anal_esil_set_op(esil, "--=[4]", reil_mem_deceq4);
r_anal_esil_set_op(esil, "--=[8]", reil_mem_deceq8);
r_anal_esil_set_op(esil, "?{", reil_if);
r_anal_esil_set_op(esil, "}", reil_if_end);
return true;
}