radare2/libr/anal/p/anal_evm_cs.c
2022-02-01 17:01:59 +01:00

311 lines
6.5 KiB
C

/* radare2 - LGPL - Copyright 2022 - pancake, Sylvain Pelissier */
#include <r_asm.h>
#include <r_lib.h>
#include <capstone.h>
#if CS_API_MAJOR >= 5
#include <evm.h>
static void set_opdir(RAnalOp *op) {
switch (op->type & R_ANAL_OP_TYPE_MASK) {
case R_ANAL_OP_TYPE_LOAD:
op->direction = R_ANAL_OP_DIR_READ;
break;
case R_ANAL_OP_TYPE_STORE:
op->direction = R_ANAL_OP_DIR_WRITE;
break;
case R_ANAL_OP_TYPE_LEA:
op->direction = R_ANAL_OP_DIR_REF;
break;
case R_ANAL_OP_TYPE_CALL:
case R_ANAL_OP_TYPE_JMP:
case R_ANAL_OP_TYPE_UJMP:
case R_ANAL_OP_TYPE_UCALL:
op->direction = R_ANAL_OP_DIR_EXEC;
break;
default:
break;
}
}
static int analop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
int n, ret, opsize = -1;
static csh hndl = 0;
static int omode = -1;
static int obits = 32;
cs_insn* insn;
char *str;
int mode = 0;
if (mode != omode || anal->bits != obits) {
cs_close (&hndl);
hndl = 0;
omode = mode;
obits = anal->bits;
}
op->addr = addr;
if (len < 1) {
return -1;
}
op->size = 4;
if (hndl == 0) {
ret = cs_open (CS_ARCH_EVM, mode, &hndl);
if (ret != CS_ERR_OK) {
goto fin;
}
cs_option (hndl, CS_OPT_DETAIL, CS_OPT_ON);
}
op->type = R_ANAL_OP_TYPE_UNK;
n = cs_disasm (hndl, (ut8*)buf, len, addr, 1, &insn);
opsize = 1;
if (n < 1 || insn->size < 1) {
if (mask & R_ANAL_OP_MASK_DISASM) {
op->mnemonic = strdup ("invalid");
}
goto beach;
}
if (mask & R_ANAL_OP_MASK_DISASM) {
if (!r_str_cmp(insn->op_str, "0x", 2)) {
str = r_str_newf ("%s%s%s", insn->mnemonic, insn->op_str[0]? " ": "", insn->op_str);
} else {
str = r_str_newf ("%s%s%s", insn->mnemonic, insn->op_str[0]? " 0x": "", insn->op_str);
}
op->mnemonic = str;
}
opsize = op->size = insn->size;
op->id = insn->id;
switch (insn->id) {
case EVM_INS_SUB:
op->type = R_ANAL_OP_TYPE_SUB;
break;
case EVM_INS_MOD:
case EVM_INS_SMOD:
op->type = R_ANAL_OP_TYPE_MOD;
break;
case EVM_INS_JUMP:
op->type = R_ANAL_OP_TYPE_JMP;
esilprintf (op, "32,sp,-=,sp,[1],pc,:=");
break;
case EVM_INS_JUMPI:
op->fail = op->addr + 1;
op->type = R_ANAL_OP_TYPE_CJMP;
break;
case EVM_INS_MLOAD:
case EVM_INS_SLOAD:
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case EVM_INS_MSTORE:
case EVM_INS_MSTORE8:
case EVM_INS_SSTORE:
op->type = R_ANAL_OP_TYPE_STORE;
break;
case EVM_INS_LT:
case EVM_INS_GT:
case EVM_INS_SLT:
case EVM_INS_SGT:
case EVM_INS_EQ:
case EVM_INS_ISZERO:
op->type = R_ANAL_OP_TYPE_CMP;
break;
case EVM_INS_COINBASE:
case EVM_INS_BLOCKHASH:
break;
case EVM_INS_CODECOPY:
case EVM_INS_SWAP1:
case EVM_INS_SWAP2:
case EVM_INS_SWAP12:
case EVM_INS_REVERT:
op->type = R_ANAL_OP_TYPE_MOV;
break;
case EVM_INS_GAS:
op->type = R_ANAL_OP_TYPE_MOV;
break;
case EVM_INS_MUL:
case EVM_INS_EXP:
case EVM_INS_MULMOD:
op->type = R_ANAL_OP_TYPE_MUL;
break;
case EVM_INS_STOP:
case EVM_INS_SUICIDE:
op->type = R_ANAL_OP_TYPE_TRAP;
break;
case EVM_INS_DELEGATECALL:
case EVM_INS_CALLDATACOPY:
case EVM_INS_CALLDATALOAD:
op->type = R_ANAL_OP_TYPE_CALL;
break;
case EVM_INS_DIV:
case EVM_INS_SDIV:
op->type = R_ANAL_OP_TYPE_DIV;
break;
case EVM_INS_RETURN:
op->type = R_ANAL_OP_TYPE_RET;
break;
case EVM_INS_DUP1:
case EVM_INS_DUP2:
case EVM_INS_DUP3:
case EVM_INS_DUP4:
case EVM_INS_DUP5:
case EVM_INS_DUP6:
case EVM_INS_DUP7:
case EVM_INS_DUP8:
case EVM_INS_DUP9:
case EVM_INS_DUP10:
case EVM_INS_DUP11:
case EVM_INS_DUP12:
case EVM_INS_DUP13:
case EVM_INS_DUP14:
case EVM_INS_DUP15:
case EVM_INS_DUP16:
op->type = R_ANAL_OP_TYPE_PUSH;
break;
case EVM_INS_PUSH1:
esilprintf (op, "0x%s,sp,=[1],32,sp,+=", insn->op_str);
op->type = R_ANAL_OP_TYPE_PUSH;
break;
case EVM_INS_PUSH2:
case EVM_INS_PUSH3:
case EVM_INS_PUSH4:
case EVM_INS_PUSH5:
case EVM_INS_PUSH6:
case EVM_INS_PUSH9:
case EVM_INS_PUSH10:
case EVM_INS_PUSH11:
case EVM_INS_PUSH12:
case EVM_INS_PUSH13:
case EVM_INS_PUSH14:
case EVM_INS_PUSH15:
case EVM_INS_PUSH16:
case EVM_INS_PUSH17:
case EVM_INS_PUSH18:
case EVM_INS_PUSH19:
case EVM_INS_PUSH20:
case EVM_INS_PUSH21:
case EVM_INS_PUSH22:
case EVM_INS_PUSH23:
op->type = R_ANAL_OP_TYPE_PUSH;
break;
// Handle https://github.com/capstone-engine/capstone/pull/1231. Can be removed when merged.
case EVM_INS_PUSH24:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 25;
break;
case EVM_INS_PUSH25:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 26;
break;
case EVM_INS_PUSH26:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 27;
break;
case EVM_INS_PUSH27:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 28;
break;
case EVM_INS_PUSH28:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 29;
break;
case EVM_INS_PUSH29:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 30;
break;
case EVM_INS_PUSH30:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 31;
break;
case EVM_INS_PUSH31:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 32;
break;
case EVM_INS_PUSH32:
op->type = R_ANAL_OP_TYPE_PUSH;
opsize = op->size = 33;
break;
case EVM_INS_ADD:
case EVM_INS_ADDMOD:
op->type = R_ANAL_OP_TYPE_ADD;
break;
case EVM_INS_POP:
op->type = R_ANAL_OP_TYPE_POP;
break;
}
beach:
set_opdir (op);
#if 0
if (insn && mask & R_ANAL_OP_MASK_OPEX) {
opex (&op->opex, hndl, insn);
}
if (mask & R_ANAL_OP_MASK_ESIL) {
if (analop_esil (anal, op, addr, buf, len, &hndl, insn) != 0) {
r_strbuf_fini (&op->esil);
}
}
if (mask & R_ANAL_OP_MASK_VAL) {
op_fillval (anal, op, &hndl, insn);
}
#endif
cs_free (insn, n);
//cs_close (&handle);
fin:
return opsize;
}
static char *get_reg_profile(RAnal *anal) {
const char *p = \
"=PC pc\n"
"=SP sp\n"
"=BP bp\n"
"=A0 r0\n"
"gpr pc .32 0 0\n"
"gpr sp .32 4 0\n"
"gpr bp .32 8 0\n"
"gpr r0 .32 12 0\n"
;
return (p && *p)? strdup (p): NULL;
}
static int archinfo(RAnal *anal, int q) {
switch (q) {
case R_ANAL_ARCHINFO_ALIGN:
return 0;
case R_ANAL_ARCHINFO_MAX_OP_SIZE:
return 33;
case R_ANAL_ARCHINFO_MIN_OP_SIZE:
return 1;
}
return 0;
}
RAnalPlugin r_anal_plugin_evm_cs = {
.name = "evm.cs",
.desc = "Capstone ETHEREUM VM arch plugin",
.license = "BSD",
.esil = true,
.arch = "evm",
.get_reg_profile = get_reg_profile,
.archinfo = archinfo,
.bits = 32,
.op = &analop,
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_ANAL,
.data = &r_anal_plugin_evm_cs,
.version = R2_VERSION
};
#endif
#else
RAnalPlugin r_anal_plugin_evm_cs = {0};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_ANAL,
.version = R2_VERSION
};
#endif
#endif