From 6ff0ee19a2fa36897aa4e7b21f08bdb0672fd2cf Mon Sep 17 00:00:00 2001 From: vboxuser Date: Wed, 21 Jun 2023 10:46:07 +0200 Subject: [PATCH] Add evm disassembly support. --- librz/asm/arch/evm/evmasm.c | 638 ++++++++++++++++++++++++++++++++++++ librz/asm/arch/evm/evmdis.c | 411 +++++++++++++++++++++++ librz/asm/meson.build | 5 + librz/asm/p/asm_evm.c | 38 +++ librz/include/rz_asm.h | 1 + test/db/asm/evm | 135 ++++++++ test/db/cmd/cmd_list | 6 +- 7 files changed, 1232 insertions(+), 2 deletions(-) create mode 100644 librz/asm/arch/evm/evmasm.c create mode 100644 librz/asm/arch/evm/evmdis.c create mode 100644 librz/asm/p/asm_evm.c create mode 100644 test/db/asm/evm diff --git a/librz/asm/arch/evm/evmasm.c b/librz/asm/arch/evm/evmasm.c new file mode 100644 index 00000000000..99a5ec14359 --- /dev/null +++ b/librz/asm/arch/evm/evmasm.c @@ -0,0 +1,638 @@ +// SPDX-FileCopyrightText: 2023 gogo +// SPDX-FileCopyrightText: 2012-2020 pancake +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include +#include + +static void str_op(char *c) { + if ((c[0] <= 'Z') && (c[0] >= 'A')) { + c[0] += 0x20; + } +} + +static int gb_reg_idx(char r) { + const char *rstr = "bcdehl a"; + const char *ptr = strchr(rstr, r); + return ptr ? (int)(size_t)(ptr - rstr) : -1; +} + +static bool gb_parse_cb1(ut8 *buf, const int minlen, char *buf_asm, ut8 base) { + // minlen varries between 4 and 6 + int i; + size_t j; + if (strlen(buf_asm) < minlen || minlen < 1) { + return false; + } + buf[0] = base; + char *ptr_asm = buf_asm + minlen - 1; + j = strlen(ptr_asm); + rz_str_replace_in(ptr_asm, (ut32)j, "[ ", "[", true); + rz_str_replace_in(ptr_asm, (ut32)j, " ]", "]", true); + rz_str_do_until_token(str_op, buf_asm, ' '); + i = gb_reg_idx(buf_asm[minlen - 1]); + if (i != (-1)) { + buf[0] |= (ut8)i; + return true; + } + if (!strncmp(&buf_asm[minlen - 1], "[hl]", 4)) { + buf[0] |= 6; + return true; + } + return false; +} + +static bool gb_parse_cb2(ut8 *buf, const int minlen, char *buf_asm, ut8 base) { + ut64 num; + int i; + char *p, *q; + if ((i = strlen(buf_asm)) < minlen) { + return false; + } + rz_str_replace_in(buf_asm, (ut32)i, "[ ", "[", true); + rz_str_replace_in(buf_asm, (ut32)i, " ]", "]", true); + rz_str_replace_in(buf_asm, (ut32)i, ", ", ",", true); + p = strchr(buf_asm, (int)' '); + if (!p) { + return false; + } + q = strchr(p, (int)','); + if (!q) { + return false; + } + q[0] = '\0'; + if (p[1] == '\0' || q[1] == '\0') { + q[0] = ','; + return false; + } + num = rz_num_get(NULL, &p[1]); + q[0] = ','; + if (num > 7) { + return false; + } + buf[0] = base + (ut8)num * 8; + i = gb_reg_idx(q[1]); + if (i != -1) { + buf[0] |= (ut8)i; + return true; + } + if (strlen(q + 1) < 4) { + return false; + } + if (!strncmp(q + 1, "[hl]", 4)) { + buf[0] |= 6; + return true; + } + return false; +} + +static int gb_parse_arith1(ut8 *buf, const int minlen, char *buf_asm, ut8 base, ut8 alt) { + int i; + ut64 num; + if (strlen(buf_asm) < minlen) { + return 0; + } + buf[0] = base; + char *ptr_asm = buf_asm + minlen - 1; + i = strlen(ptr_asm); + rz_str_replace_in(ptr_asm, (ut32)i, "[ ", "[", true); + rz_str_replace_in(ptr_asm, (ut32)i, " ]", "]", true); + rz_str_do_until_token(str_op, buf_asm, ' '); + i = gb_reg_idx(buf_asm[minlen - 1]); + if (i != -1) { + buf[0] |= (ut8)i; + } else if (!strncmp(buf_asm + minlen - 1, "[hl]", 4)) { + buf[0] |= 6; + } else { + buf[0] = alt; + num = rz_num_get(NULL, buf_asm + minlen - 1); + buf[1] = (ut8)(num & 0xff); + return 2; + } + return 1; +} + +static bool gb_parse_ld1(ut8 *buf, const int minlen, char *buf_asm) { + int i; + rz_str_replace_in(buf_asm, strlen(buf_asm), ", ", ",", true); + if (strlen(buf_asm) < minlen) { + return false; + } + rz_str_do_until_token(str_op, buf_asm, '\0'); + if (buf_asm[4] == ',') { + i = gb_reg_idx(buf_asm[3]); + if (i == (-1)) { + return false; + } + buf[0] = (ut8)(0x40 + (i * 8)); + i = gb_reg_idx(buf_asm[5]); + if (i == -1) { + if (strncmp(buf_asm + 5, "[hl]", 4)) { + return false; + } + i = 6; + } + buf[0] |= (ut8)i; + return true; + } + if (!strncmp(buf_asm + 3, "[hl],", 5)) { + if ((i = gb_reg_idx(buf_asm[8])) == (-1)) { + //'ld [hl], [hl]' does not exist + return false; + } + buf[0] = 0x70 | (ut8)i; + return true; + } + return false; +} + +static bool gb_parse_ld2(ut8 *buf, char *buf_asm) { + int i; + ut64 num; + if (strlen(buf_asm) < 6) { + return false; + } + if (buf_asm[4] == ',') { + if ((i = gb_reg_idx(buf_asm[3])) == -1) { + return false; + } + buf[0] = 0x6 + (ut8)(i * 8); + num = rz_num_get(NULL, buf_asm + 5); + buf[1] = (ut8)(num & 0xff); + return true; + } else if (!strncmp(buf_asm + 3, "[hl],", 5)) { + buf[0] = 0x36; + num = rz_num_get(NULL, buf_asm + 8); + buf[1] = (ut8)(num & 0xff); + return true; + } + return false; +} + +static bool gb_parse_ld3(ut8 *buf, char *buf_asm) { + if (strlen(buf_asm) < 7) { + return false; + } + if (buf_asm[5] != ',') { + return false; + } + + const ut16 reg = (buf_asm[3] << 8) | buf_asm[4]; + switch (reg) { + case 0x6263: // bc + buf[0] = 0x01; + break; + case 0x6465: // de + buf[0] = 0x11; + break; + case 0x686c: // hl + buf[0] = 0x21; + break; + case 0x7370: // sp + buf[0] = 0x31; + break; + default: + return false; + } + + const ut64 num = rz_num_get(NULL, buf_asm + 6); + buf[1] = num & 0xff; + buf[2] = (num & 0xff00) >> 8; + return true; +} + +static int evmAsm(RzAsm *a, RzAsmOp *op, const char *buf) { + int mn_len, j, len = 1; + ut32 mn = 0; + ut64 num; + size_t i; + if (!a || !op || !buf) { + return 0; + } + ut8 opbuf[4] = { 0 }; + rz_strbuf_set(&op->buf_asm, buf); + char *buf_asm = rz_strbuf_get(&op->buf_asm); + ut32 buf_len = strlen(buf); + while (strstr(buf_asm, " ")) { + rz_str_replace_in(buf_asm, buf_len, " ", " ", true); + } + rz_str_replace_in(buf_asm, buf_len, " ,", ",", true); + mn_len = rz_str_do_until_token(str_op, buf_asm, ' '); + if (mn_len < 2 || mn_len > 4) { + return 0; + } + for (j = 0; j < mn_len; j++) { + mn = (mn << 8) | buf_asm[j]; + } + switch (mn) { + case 0x73746f70: // STOP + opbuf[0] = 0x00; + break; + case 0x616464: // ADD + opbuf[0] = 0x01; + break; + case 0x6e6f70: // nop + opbuf[0] = 0x00; + break; + case 0x696e63: // inc + if ((i = strlen(buf_asm)) < 5) { + return op->size = 0; + } + rz_str_replace_in(buf_asm, (ut32)i, "[ ", "[", true); + rz_str_replace_in(buf_asm, (ut32)i, " ]", "]", true); + rz_str_do_until_token(str_op, buf_asm + 4, '\0'); + if (buf_asm[4] == 'b') { + opbuf[0] = (buf_asm[5] == 'c') ? 3 : 4; + } else if (buf_asm[4] == 'c') { + opbuf[0] = 0x0c; + } else if (buf_asm[4] == 'd') { + opbuf[0] = (buf_asm[5] == 'e') ? 0x13 : 0x14; + } else if (buf_asm[4] == 'e') { + opbuf[0] = 0x1c; + } else if (buf_asm[4] == 'h') { + opbuf[0] = (buf_asm[5] == 'l') ? 0x23 : 0x24; + } else if (buf_asm[4] == 'l') { + opbuf[0] = 0x2c; + } else if (buf_asm[4] == 'a') { + opbuf[0] = 0x3c; + } else if (buf_asm[4] == 's' && buf_asm[5] == 'p') { + opbuf[0] = 0x33; + } else if (!strncmp(buf_asm + 4, "[hl]", 4)) { + opbuf[0] = 0x34; + } else { + len = 0; + } + break; + case 0x646563: // dec + if ((i = strlen(buf_asm)) < 5) { + return op->size = 0; + } + rz_str_replace_in(buf_asm, (ut32)i, "[ ", "[", true); + rz_str_replace_in(buf_asm, (ut32)i, " ]", "]", true); + rz_str_do_until_token(str_op, &buf_asm[4], '\0'); + switch (buf_asm[4]) { + case 'b': + opbuf[0] = (buf_asm[5] == 'c') ? 0x0b : 0x05; + break; + case 'c': + opbuf[0] = 0x0d; + break; + case 'd': + opbuf[0] = (buf_asm[5] == 'e') ? 0x1b : 0x15; + break; + case 'e': + opbuf[0] = 0x1d; + break; + case 'h': + opbuf[0] = (buf_asm[5] == 'l') ? 0x2b : 0x25; + break; + case 'l': + opbuf[0] = 0x2d; + break; + case 'a': + opbuf[0] = 0x3d; + break; + default: + if (!strncmp(buf_asm + 4, "sp", 2)) { + opbuf[0] = 0x3b; + } else if (!strncmp(buf_asm, "[hl]", 4)) { + opbuf[0] = 0x35; + } else { + len = 0; + } + break; + } + break; + case 0x726c6361: // rlca + opbuf[0] = 0x07; + break; + case 0x72726361: // rrca + opbuf[0] = 0xf0; + break; + case 0x726c61: // rla + opbuf[0] = 0x17; + break; + case 0x727261: // rra + opbuf[0] = 0x1f; + break; + case 0x646161: // daa + opbuf[0] = 0x27; + break; + case 0x63706c: // cpl + opbuf[0] = 0x2f; + break; + case 0x616463: // adc + len = gb_parse_arith1(opbuf, 5, buf_asm, 0x88, 0xce); + break; + case 0x737562: // sub + len = gb_parse_arith1(opbuf, 5, buf_asm, 0x90, 0xd6); + break; + case 0x736263: // sbc + len = gb_parse_arith1(opbuf, 5, buf_asm, 0x98, 0xde); + break; + case 0x616e64: // and + len = gb_parse_arith1(opbuf, 5, buf_asm, 0xa0, 0xe6); + break; + case 0x786f72: // xor + len = gb_parse_arith1(opbuf, 5, buf_asm, 0xa8, 0xee); + break; + case 0x6f72: // or + len = gb_parse_arith1(opbuf, 4, buf_asm, 0xb0, 0xf6); + break; + case 0x6370: // cp + len = gb_parse_arith1(opbuf, 4, buf_asm, 0xb8, 0xfe); + break; + case 0x736366: // scf + opbuf[0] = 0x37; + break; + case 0x636366: // ccf + opbuf[0] = 0x3f; + break; + case 0x68616c74: // halt + opbuf[0] = 0x76; + break; + case 0x726574: // ret + if (strlen(buf_asm) < 5) { + opbuf[0] = 0xc9; + } else if (strlen(buf_asm) < 6) { + // there is no way that there can be " " - we did rz_str_replace_in + str_op(buf_asm + 4); + if (buf_asm[4] == 'z') { // ret Z + opbuf[0] = 0xc8; + } else if (buf_asm[4] == 'c') { // ret C + opbuf[0] = 0xd8; + } else { + return op->size = 0; + } + } else { + str_op(&buf_asm[4]); + if (buf_asm[4] != 'n') { + return op->size = 0; + } + str_op(&buf_asm[5]); // if (!(strlen(buf_asm) < 6)) => must be 6 or greater + if (buf_asm[5] == 'z') { // ret nZ + opbuf[0] = 0xc0; + } else if (buf_asm[5] == 'c') { // ret nC + opbuf[0] = 0xd0; + } else { + return op->size = 0; + } + } + break; + case 0x72657469: // reti + opbuf[0] = 0xd9; + break; + case 0x6469: // di + opbuf[0] = 0xf3; + break; + case 0x6569: // ei + opbuf[0] = 0xfb; + break; + case 0x6c64: // ld + i = strlen(buf_asm); + rz_str_replace_in(buf_asm, (ut32)i, "[ ", "[", true); + rz_str_replace_in(buf_asm, (ut32)i, " ]", "]", true); + if (!gb_parse_ld1(opbuf, 6, buf_asm)) { + len++; + if (!gb_parse_ld2(opbuf, buf_asm)) { + len++; + if (!gb_parse_ld3(opbuf, buf_asm)) { + len = 0; + } + } + } + break; + case 0x727374: // rst + if (strlen(buf_asm) < 5) { + return op->size = 0; + } + num = rz_num_get(NULL, &buf_asm[4]); + if ((num & 7) || ((num / 8) > 7)) { + return op->size = 0; + } + opbuf[0] = (ut8)((num & 0xff) + 0xc7); + break; + case 0x70757368: // push + if (strlen(buf_asm) < 7) { + return op->size = 0; + } + str_op(buf_asm + 5); + str_op(buf_asm + 6); + if (buf_asm[5] == 'b' && buf_asm[6] == 'c') { + opbuf[0] = 0xc5; + } else if (buf_asm[5] == 'd' && buf_asm[6] == 'e') { + opbuf[0] = 0xd5; + } else if (buf_asm[5] == 'h' && buf_asm[6] == 'l') { + opbuf[0] = 0xe5; + } else if (buf_asm[5] == 'a' && buf_asm[6] == 'f') { + opbuf[0] = 0xf5; + } else { + len = 0; + } + break; + case 0x706f70: // pop + if (strlen(buf_asm) < 6) + return op->size = 0; + str_op(&buf_asm[4]); + str_op(&buf_asm[5]); + if (buf_asm[4] == 'b' && buf_asm[5] == 'c') { + opbuf[0] = 0xc1; + } else if (buf_asm[4] == 'd' && buf_asm[5] == 'e') { + opbuf[0] = 0xd1; + } else if (buf_asm[4] == 'h' && buf_asm[5] == 'l') { + opbuf[0] = 0xe1; + } else if (buf_asm[4] == 'a' && buf_asm[5] == 'f') { + opbuf[0] = 0xf1; + } else { + len = 0; + } + break; + case 0x6a70: // jp + if (strlen(buf_asm) < 4) { + return op->size = 0; + } + { + char *p = strchr(buf_asm, (int)','); + if (!p) { + str_op(&buf_asm[3]); + str_op(&buf_asm[4]); + if (buf_asm[3] == 'h' && buf_asm[4] == 'l') + opbuf[0] = 0xe9; + else { + num = rz_num_get(NULL, &buf_asm[3]); + len = 3; + opbuf[0] = 0xc3; + opbuf[1] = (ut8)(num & 0xff); + opbuf[2] = (ut8)((num & 0xff00) >> 8); + } + } else { + str_op(p - 2); + str_op(p - 1); + if (*(p - 2) == 'n') { + if (*(p - 1) == 'z') { + opbuf[0] = 0xc2; + } else if (*(p - 1) == 'c') { + opbuf[0] = 0xd2; + } else { + return op->size = 0; + } + } else if (*(p - 2) == ' ') { + if (*(p - 1) == 'z') { + opbuf[0] = 0xca; + } else if (*(p - 1) == 'c') { + opbuf[0] = 0xda; + } else { + return op->size = 0; + } + } else { + return op->size = 0; + } + rz_str_replace_in(p, strlen(p), ", ", ",", true); + if (!p[0] || !p[1]) { + return op->size = 0; + } + num = rz_num_get(NULL, p + 1); + opbuf[1] = (ut8)(num & 0xff); + opbuf[2] = (ut8)((num & 0xff00) >> 8); + len = 3; + } + } + break; + case 0x6a72: // jr + if (strlen(buf_asm) < 4) + return op->size = 0; + { + char *p = strchr(buf_asm, (int)','); + if (!p) { + num = rz_num_get(NULL, &buf_asm[3]); + len = 2; + opbuf[0] = 0x18; + opbuf[1] = (ut8)(num & 0xff); + } else { + str_op(p - 2); + str_op(p - 1); + if (*(p - 2) == 'n') { + if (*(p - 1) == 'z') + opbuf[0] = 0x20; + else if (*(p - 1) == 'c') + opbuf[0] = 0x30; + else + return op->size = 0; + } else if (*(p - 2) == ' ') { + if (*(p - 1) == 'z') + opbuf[0] = 0x28; + else if (*(p - 1) == 'c') + opbuf[0] = 0x38; + else + return op->size = 0; + } else { + return op->size = 0; + } + rz_str_replace_in(p, strlen(p), ", ", ",", true); + if (!p[1]) { + return op->size = 0; + } + num = rz_num_get(NULL, p + 1); + opbuf[1] = (ut8)(num & 0xff); + len = 2; + } + } + break; + case 0x63616c6c: // call + if (strlen(buf_asm) < 6) { + return op->size = 0; + } + { + char *p = strchr(buf_asm, (int)','); + if (!p) { + num = rz_num_get(NULL, buf_asm + 4); + len = 3; + opbuf[0] = 0xcd; + opbuf[1] = (ut8)(num & 0xff); + opbuf[2] = (ut8)((num & 0xff00) >> 8); + } else { + str_op(p - 2); + str_op(p - 1); + if (*(p - 2) == 'n') { + if (*(p - 1) == 'z') { + opbuf[0] = 0xc4; + } else if (*(p - 1) == 'c') { + opbuf[0] = 0xd4; + } else { + return op->size = 0; + } + } else if (*(p - 2) == ' ') { + if (*(p - 1) == 'z') { + opbuf[0] = 0xcc; + } else if (*(p - 1) == 'c') { + opbuf[0] = 0xdc; + } else { + return op->size = 0; + } + } else { + return op->size = 0; + } + rz_str_replace_in(p, strlen(p), ", ", ",", true); + if (!*p || !p[1]) { + return op->size = 0; + } + num = rz_num_get(NULL, p + 1); + opbuf[1] = (ut8)(num & 0xff); + opbuf[2] = (ut8)((num & 0xff00) >> 8); + len = 3; + } + } + break; + case 0x726c63: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 5, buf_asm, 0x00) ? 2 : 0; + break; + case 0x727263: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 5, buf_asm, 0x08) ? 2 : 0; + break; + case 0x726c: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 4, buf_asm, 0x10) ? 2 : 0; + break; + case 0x7272: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 4, buf_asm, 0x18) ? 2 : 0; + break; + case 0x736c61: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 5, buf_asm, 0x20) ? 2 : 0; + break; + case 0x737261: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 5, buf_asm, 0x28) ? 2 : 0; + break; + case 0x73776170: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 6, buf_asm, 0x30) ? 2 : 0; + break; + case 0x73726c: + opbuf[0] = 0xcb; + len = gb_parse_cb1(opbuf + 1, 6, buf_asm, 0x38) ? 2 : 0; + break; + case 0x626974: + opbuf[0] = 0xcb; + len = gb_parse_cb2(opbuf + 1, 6, buf_asm, 0x40) ? 2 : 0; + break; + case 0x726573: + opbuf[0] = 0xcb; + len = gb_parse_cb2(opbuf + 1, 6, buf_asm, 0x80) ? 2 : 0; + break; + case 0x736574: + opbuf[0] = 0xcb; + len = gb_parse_cb2(opbuf + 1, 6, buf_asm, 0xc0) ? 2 : 0; + break; + default: + len = 0; + break; + } + memcpy(rz_strbuf_get(&op->buf), opbuf, sizeof(ut8) * len); + return op->size = len; +} diff --git a/librz/asm/arch/evm/evmdis.c b/librz/asm/arch/evm/evmdis.c new file mode 100644 index 00000000000..c8145af2de0 --- /dev/null +++ b/librz/asm/arch/evm/evmdis.c @@ -0,0 +1,411 @@ +// SPDX-FileCopyrightText: 2023 gogo +// SPDX-FileCopyrightText: 2013-2018 pancake +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include +#include +#include +#include + +#ifndef GB_DIS_LEN_ONLY +static int evmDisass(RzAsmOp *op, const ut8 *buf, int len) { + int instruction_size = 1; + char buf_asm[2000]; + const unsigned char out[256]; + const unsigned char opcode[256]; + + switch (buf[0]) { + case 0x00: + rz_str_cpy(buf_asm, "STOP") break; + case 0x01: + rz_str_cpy(buf_asm, "ADD") break; + case 0x02: + rz_str_cpy(buf_asm, "MUL") break; + case 0x03: + rz_str_cpy(buf_asm, "SUB") break; + case 0x04: + rz_str_cpy(buf_asm, "DIV") break; + case 0x05: + rz_str_cpy(buf_asm, "SDIV") break; + case 0x06: + rz_str_cpy(buf_asm, "MOD") break; + case 0x07: + rz_str_cpy(buf_asm, "SMOD") break; + case 0x8: + rz_str_cpy(buf_asm, "ADDMOD") break; + case 0x9: + rz_str_cpy(buf_asm, "MULMOD") break; + case 0x0a: + rz_str_cpy(buf_asm, "EXP") break; + case 0x0b: + rz_str_cpy(buf_asm, "SIGNEXTEND") break; + case 0x11: + rz_str_cpy(buf_asm, "GT") break; + case 0x12: + rz_str_cpy(buf_asm, "SLT") break; + case 0x13: + rz_str_cpy(buf_asm, "SGT") break; + case 0x14: + rz_str_cpy(buf_asm, "EQ") break; + case 0x15: + rz_str_cpy(buf_asm, "ISZERO") break; + case 0x16: + rz_str_cpy(buf_asm, "AND") break; + case 0x17: + rz_str_cpy(buf_asm, "OR") break; + case 0x18: + rz_str_cpy(buf_asm, "XOR") break; + case 0x19: + rz_str_cpy(buf_asm, "NOT") break; + case 0x1a: + rz_str_cpy(buf_asm, "BYTE") break; + case 0x1b: + rz_str_cpy(buf_asm, "SHL") break; + case 0x1c: + rz_str_cpy(buf_asm, "SHR") break; + case 0x1d: + rz_str_cpy(buf_asm, "SAR") break; + case 0x20: + rz_str_cpy(buf_asm, "SHA3") break; + case 0x30: + rz_str_cpy(buf_asm, "ADDRESS") break; + case 0x31: + rz_str_cpy(buf_asm, "BALANCE") break; + case 0x32: + rz_str_cpy(buf_asm, "ORIGIN") break; + case 0x33: + rz_str_cpy(buf_asm, "CALLER") break; + case 0x34: + rz_str_cpy(buf_asm, "CALLVALUE") break; + case 0x35: + rz_str_cpy(buf_asm, "CALLDATALOAD") break; + case 0x36: + rz_str_cpy(buf_asm, "CALLDATASIZE") break; + case 0x37: + rz_str_cpy(buf_asm, "CALLDATACOPY") break; + case 0x38: + rz_str_cpy(buf_asm, "CODESIZE") break; + case 0x39: + rz_str_cpy(buf_asm, "CODECOPY") break; + case 0x3a: + rz_str_cpy(buf_asm, "GASPRICE") break; + case 0x3b: + rz_str_cpy(buf_asm, "EXTCODESIZE") break; + case 0x3c: + rz_str_cpy(buf_asm, "EXTCODECOPY") break; + case 0x3d: + rz_str_cpy(buf_asm, "RETURNDATASIZE") break; + case 0x3e: + rz_str_cpy(buf_asm, "RETURNDATACOPY") break; + case 0x3f: + rz_str_cpy(buf_asm, "EXTCODEHASH") break; + case 0x40: + rz_str_cpy(buf_asm, "BLOCKHASH") break; + case 0x41: + rz_str_cpy(buf_asm, "COINBASE") break; + case 0x42: + rz_str_cpy(buf_asm, "TIMESTAMP") break; + case 0x43: + rz_str_cpy(buf_asm, "NUMBER") break; + case 0x44: + rz_str_cpy(buf_asm, "DIFFICULTY") break; + case 0x45: + rz_str_cpy(buf_asm, "GASLIMIT") break; + case 0x46: + rz_str_cpy(buf_asm, "CHAINID") break; + case 0x47: + rz_str_cpy(buf_asm, "SELFBALANCE") break; + case 0x48: + rz_str_cpy(buf_asm, "BASEFEE") break; + case 0x50: + rz_str_cpy(buf_asm, "POP") break; + case 0x51: + rz_str_cpy(buf_asm, "MLOAD") break; + case 0x52: + rz_str_cpy(buf_asm, "MSTORE") break; + case 0x53: + rz_str_cpy(buf_asm, "MSTORE8") break; + case 0x54: + rz_str_cpy(buf_asm, "SLOAD") break; + case 0x55: + rz_str_cpy(buf_asm, "SSTORE") break; + case 0x56: + rz_str_cpy(buf_asm, "JUMP") break; + case 0x57: + rz_str_cpy(buf_asm, "JUMPI") break; + case 0x58: + rz_str_cpy(buf_asm, "PC") break; + case 0x59: + rz_str_cpy(buf_asm, "MSIZE") break; + case 0x5a: + rz_str_cpy(buf_asm, "GAS") break; + case 0x5b: + rz_str_cpy(buf_asm, "JUMPDEST") break; + case 0x60: + instruction_size = 2; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH1 0x%s", opcode); break; + case 0x61: + instruction_size = 3; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH2 0x%s", opcode); break; + case 0x62: + instruction_size = 4; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH3 0x%s", opcode); break; + case 0x63: + instruction_size = 5; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH4 0x%s", opcode); break; + case 0x64: + instruction_size = 6; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH5 0x%s", opcode); break; + case 0x65: + instruction_size = 7; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH6 0x%s", opcode); break; + case 0x66: + instruction_size = 8; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH7 0x%s", opcode); break; + case 0x67: + instruction_size = 9; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH8 0x%s", opcode); break; + case 0x68: + instruction_size = 10; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH9 0x%s", opcode); break; + case 0x69: + instruction_size = 11; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH10 0x%s", opcode); break; + case 0x6a: + instruction_size = 12; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH11 0x%s", opcode); break; + case 0x6b: + instruction_size = 13; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH12 0x%s", opcode); break; + case 0x6c: + instruction_size = 14; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH13 0x%s", opcode); break; + case 0x6d: + instruction_size = 15; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH14 0x%s", opcode); break; + case 0x6e: + instruction_size = 16; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH15 0x%s", opcode); break; + case 0x6f: + instruction_size = 17; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH16 0x%s", opcode); break; + case 0x70: + instruction_size = 18; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH17 0x%s", opcode); break; + case 0x71: + instruction_size = 19; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH18 0x%s", opcode); break; + case 0x72: + instruction_size = 20; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH19 0x%s", opcode); break; + case 0x73: + instruction_size = 21; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH20 0x%s", opcode); break; + case 0x74: + instruction_size = 22; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH21 0x%s", opcode); break; + case 0x75: + instruction_size = 23; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH22 0x%s", opcode); break; + case 0x76: + instruction_size = 24; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH23 0x%s", opcode); break; + case 0x77: + instruction_size = 25; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH24 0x%s", opcode); break; + case 0x78: + instruction_size = 26; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH25 0x%s", opcode); break; + case 0x79: + instruction_size = 27; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH26 0x%s", opcode); break; + case 0x7a: + instruction_size = 28; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH27 0x%s", opcode); break; + case 0x7b: + instruction_size = 29; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH28 0x%s", opcode); break; + case 0x7c: + instruction_size = 30; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH29 0x%s", opcode); break; + case 0x7d: + instruction_size = 31; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH30 0x%s", opcode); break; + case 0x7e: + instruction_size = 32; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH31 0x%s", opcode); break; + case 0x7f: + instruction_size = 33; + strncpy(out, buf+1, instruction_size-1); + rz_hex_bin2str(out, instruction_size-1, opcode); + snprintf(buf_asm, sizeof(buf_asm), "PUSH32 0x%s", opcode); break; + case 0x80: + rz_str_cpy(buf_asm, "DUP1") break; + case 0x81: + rz_str_cpy(buf_asm, "DUP2") break; + case 0x82: + rz_str_cpy(buf_asm, "DUP3") break; + case 0x83: + rz_str_cpy(buf_asm, "DUP4") break; + case 0x84: + rz_str_cpy(buf_asm, "DUP5") break; + case 0x85: + rz_str_cpy(buf_asm, "DUP6") break; + case 0x86: + rz_str_cpy(buf_asm, "DUP7") break; + case 0x87: + rz_str_cpy(buf_asm, "DUP8") break; + case 0x88: + rz_str_cpy(buf_asm, "DUP9") break; + case 0x89: + rz_str_cpy(buf_asm, "DUP10") break; + case 0x8a: + rz_str_cpy(buf_asm, "DUP11") break; + case 0x8b: + rz_str_cpy(buf_asm, "DUP12") break; + case 0x8c: + rz_str_cpy(buf_asm, "DUP13") break; + case 0x8d: + rz_str_cpy(buf_asm, "DUP14") break; + case 0x8e: + rz_str_cpy(buf_asm, "DUP15") break; + case 0x8f: + rz_str_cpy(buf_asm, "DUP16") break; + case 0x90: + rz_str_cpy(buf_asm, "SWAP1") break; + case 0x91: + rz_str_cpy(buf_asm, "SWAP2") break; + case 0x92: + rz_str_cpy(buf_asm, "SWAP3") break; + case 0x93: + rz_str_cpy(buf_asm, "SWAP4") break; + case 0x94: + rz_str_cpy(buf_asm, "SWAP5") break; + case 0x95: + rz_str_cpy(buf_asm, "SWAP6") break; + case 0x96: + rz_str_cpy(buf_asm, "SWAP7") break; + case 0x97: + rz_str_cpy(buf_asm, "SWAP8") break; + case 0x98: + rz_str_cpy(buf_asm, "SWAP9") break; + case 0x99: + rz_str_cpy(buf_asm, "SWAP10") break; + case 0x9a: + rz_str_cpy(buf_asm, "SWAP11") break; + case 0x9b: + rz_str_cpy(buf_asm, "SWAP12") break; + case 0x9c: + rz_str_cpy(buf_asm, "SWAP13") break; + case 0x9d: + rz_str_cpy(buf_asm, "SWAP14") break; + case 0x9e: + rz_str_cpy(buf_asm, "SWAP15") break; + case 0x9f: + rz_str_cpy(buf_asm, "SWAP16") break; + case 0xa0: + rz_str_cpy(buf_asm, "LOG0") break; + case 0xa1: + rz_str_cpy(buf_asm, "LOG1") break; + case 0xa2: + rz_str_cpy(buf_asm, "LOG2") break; + case 0xa3: + rz_str_cpy(buf_asm, "LOG3") break; + case 0xa4: + rz_str_cpy(buf_asm, "LOG4") break; + case 0xb0: + rz_str_cpy(buf_asm, "PUSH") break; //requires arguments? + case 0xb1: + rz_str_cpy(buf_asm, "DUP") break; //requires arguments? + case 0xb2: + rz_str_cpy(buf_asm, "SWAP") break; + case 0xf0: + rz_str_cpy(buf_asm, "CREATE") break; + case 0xf1: + rz_str_cpy(buf_asm, "CALL") break; //requires arguments? + case 0xf2: + rz_str_cpy(buf_asm, "CALLCODE") break; + case 0xf3: + rz_str_cpy(buf_asm, "RETURN") break; + case 0xf4: + rz_str_cpy(buf_asm, "DELEGATECALL") break; + case 0xf5: + rz_str_cpy(buf_asm, "CREATE2") break; + case 0xfa: + rz_str_cpy(buf_asm, "STATICCALL") break; + case 0xfd: + rz_str_cpy(buf_asm, "REVERT") break; + case 0xff: + rz_str_cpy(buf_asm, "SELFDESTRUCT") break; + default: + rz_str_cpy(buf_asm, "Invalid") break; + } + + rz_strbuf_set(&op->buf_asm, buf_asm); + return instruction_size; +} +#endif diff --git a/librz/asm/meson.build b/librz/asm/meson.build index 3c55a8f5ad3..0a72c66fc35 100644 --- a/librz/asm/meson.build +++ b/librz/asm/meson.build @@ -12,6 +12,7 @@ asm_plugins_list = [ 'dalvik', 'dcpu16', 'ebc', + 'evm', 'gb', 'h8300', 'hexagon', @@ -98,6 +99,7 @@ rz_asm_sources = [ 'p/asm_dalvik.c', 'p/asm_dcpu16.c', 'p/asm_ebc.c', + 'p/asm_evm.c', 'p/asm_gb.c', 'p/asm_h8300.c', 'p/asm_hexagon.c', @@ -154,6 +156,8 @@ rz_asm_sources = [ #'arch/dcpu16/dis.c', #'arch/dcpu16/main.c', 'arch/ebc/ebc_disas.c', + 'arch/evm/evmdis.c', + 'arch/evm/evmasm.c', #'arch/gb/gbasm.c', #'arch/gb/gbdis.c', 'arch/h8300/h8300_disas.c', @@ -299,6 +303,7 @@ rz_asm_inc = [ 'arch/v850', 'arch/propeller', 'arch/ebc', + 'arch/evm', 'arch/cr16', 'arch/8051', 'arch/v810', diff --git a/librz/asm/p/asm_evm.c b/librz/asm/p/asm_evm.c new file mode 100644 index 00000000000..1c1568c50c8 --- /dev/null +++ b/librz/asm/p/asm_evm.c @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2023 gogo +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include +#include +#include "../arch/evm/evmdis.c" +#include "../arch/evm/evmasm.c" + +static int disassemble(RzAsm *a, RzAsmOp *rz_op, const ut8 *buf, int len) { + int dlen = evmDisass(rz_op, buf, len); + return rz_op->size = RZ_MAX(0, dlen); +} + +static int assemble(RzAsm *a, RzAsmOp *rz_op, const char *buf) { + return evmAsm(a, rz_op, buf); +} + +RzAsmPlugin rz_asm_plugin_evm = { + .name = "evm", + .desc = "EVM solidity bytecode", + .arch = "evm", + .author = "gogo", + .license = "LGPL3", + .bits = 256, + .endian = RZ_SYS_ENDIAN_LITTLE, + .disassemble = &disassemble, + .assemble = &assemble, +}; + +#ifndef RZ_PLUGIN_INCORE +RZ_API RzLibStruct rizin_plugin = { + .type = RZ_LIB_TYPE_ASM, + .data = &rz_asm_plugin_evm, + .version = RZ_VERSION +}; +#endif diff --git a/librz/include/rz_asm.h b/librz/include/rz_asm.h index 783fb536173..615fd050f05 100644 --- a/librz/include/rz_asm.h +++ b/librz/include/rz_asm.h @@ -229,6 +229,7 @@ extern RzAsmPlugin rz_asm_plugin_cris_gnu; extern RzAsmPlugin rz_asm_plugin_dalvik; extern RzAsmPlugin rz_asm_plugin_dcpu16; extern RzAsmPlugin rz_asm_plugin_ebc; +extern RzAsmPlugin rz_asm_plugin_evm; extern RzAsmPlugin rz_asm_plugin_gb; extern RzAsmPlugin rz_asm_plugin_h8300; extern RzAsmPlugin rz_asm_plugin_hexagon; diff --git a/test/db/asm/evm b/test/db/asm/evm new file mode 100644 index 00000000000..2d5a26ff09b --- /dev/null +++ b/test/db/asm/evm @@ -0,0 +1,135 @@ +d "STOP" 00 +d "ADD" 01 +d "SUB" 03 +d "DIV" 04 +d "SDIV" 05 +d "MOD" 06 +d "SMOD" 07 +d "ADDMOD" 08 +d "MULMOD" 09 +d "EXP" 0a +d "SIGNEXTEND" 0b +d "GT" 11 +d "SLT" 12 +d "SGT" 13 +d "EQ" 14 +d "ISZERO" 15 +d "AND" 16 +d "OR" 17 +d "XOR" 18 +d "NOT" 19 +d "BYTE" 1a +d "SHL" 1b +d "SHR" 1c +d "SAR" 1d +d "SHA3" 20 +d "ADDRESS" 30 +d "BALANCE" 31 +d "ORIGIN" 32 +d "CALLER" 33 +d "CALLVALUE" 34 +d "CALLDATALOAD" 35 +d "CALLDATASIZE" 36 +d "CALLDATACOPY" 37 +d "CODESIZE" 38 +d "CODECOPY" 39 +d "GASPRICE" 3a +d "EXTCODESIZE" 3b +d "EXTCODECOPY" 3c +d "RETURNDATASIZE" 3d +d "RETURNDATACOPY" 3e +d "CODESIZE" 38 +d "CODECOPY" 39 +d "GASPRICE" 3a +d "EXTCODESIZE" 3b +d "EXTCODECOPY" 3c +d "RETURNDATASIZE" 3d +d "RETURNDATACOPY" 3e +d "EXTCODEHASH" 3f +d "BLOCKHASH" 40 +d "COINBASE" 41 +d "TIMESTAMP" 42 +d "NUMBER" 43 +d "DIFFICULTY" 44 +d "GASLIMIT" 45 +d "CHAINID" 46 +d "SELFBALANCE" 47 +d "POP" 50 +d "MLOAD" 51 +d "MSTORE" 52 +d "MSTORE8" 53 +d "SLOAD" 54 +d "SSTORE" 55 +d "JUMP" 56 +d "JUMPI" 57 +d "PC" 58 +d "MSIZE" 59 +d "GAS" 5a +d "JUMPDEST" 5b +d "PUSH1 0x01" 6001 +d "PUSH2 0x0102" 610102 +d "PUSH3 0x010203" 62010203 +d "PUSH4 0x01020304" 6301020304 +d "PUSH5 0x0102030405" 640102030405 +d "PUSH6 0x010203040506" 65010203040506 +d "PUSH7 0x01020304050607" 6601020304050607 +d "PUSH8 0x0102030405060708" 670102030405060708 +d "PUSH9 0x010203040506070809" 68010203040506070809 +d "PUSH10 0x01020304050607080901" 6901020304050607080901 +d "PUSH11 0x0102030405060708090102" 6a0102030405060708090102 +d "PUSH12 0x010203040506070809010203" 6b010203040506070809010203 +d "PUSH13 0x01020304050607080901020304" 6c01020304050607080901020304 +d "PUSH14 0x0102030405060708090102030405" 6d0102030405060708090102030405 +d "PUSH15 0x010203040506070809010203040506" 6e010203040506070809010203040506 +d "PUSH16 0x01020304050607080901020304050607" 6f01020304050607080901020304050607 +d "PUSH17 0x0102030405060708090102030405060708" 700102030405060708090102030405060708 +d "PUSH18 0x010203040506070809010203040506070809" 71010203040506070809010203040506070809 +d "PUSH19 0x01020304050607080901020304050607080901" 7201020304050607080901020304050607080901 +d "PUSH20 0x0102030405060708090102030405060708090102" 730102030405060708090102030405060708090102 +d "PUSH21 0x010203040506070809010203040506070809010203" 74010203040506070809010203040506070809010203 +d "PUSH22 0x01020304050607080901020304050607080901020304" 7501020304050607080901020304050607080901020304 +d "PUSH23 0x0102030405060708090102030405060708090102030405" 760102030405060708090102030405060708090102030405 +d "PUSH24 0x010203040506070809010203040506070809010203040506" 77010203040506070809010203040506070809010203040506 +d "PUSH25 0x01020304050607080901020304050607080901020304050607" 7801020304050607080901020304050607080901020304050607 +d "PUSH26 0x0102030405060708090102030405060708090102030405060708" 790102030405060708090102030405060708090102030405060708 +d "PUSH27 0x010203040506070809010203040506070809010203040506070809" 7a010203040506070809010203040506070809010203040506070809 +d "PUSH28 0x01020304050607080901020304050607080901020304050607080901" 7b01020304050607080901020304050607080901020304050607080901 +d "PUSH29 0x0102030405060708090102030405060708090102030405060708090102" 7c0102030405060708090102030405060708090102030405060708090102 +d "PUSH30 0x010203040506070809010203040506070809010203040506070809010203" 7d010203040506070809010203040506070809010203040506070809010203 +d "PUSH31 0x01020304050607080901020304050607080901020304050607080901020304" 7e01020304050607080901020304050607080901020304050607080901020304 +d "PUSH32 0x0102030405060708090102030405060708090102030405060708090102030405" 7f0102030405060708090102030405060708090102030405060708090102030405 +d "SWAP1" 90 +d "SWAP2" 91 +d "SWAP3" 92 +d "SWAP4" 93 +d "SWAP5" 94 +d "SWAP6" 95 +d "SWAP7" 96 +d "SWAP8" 97 +d "SWAP9" 98 +d "SWAP10" 99 +d "SWAP11" 9a +d "SWAP12" 9b +d "SWAP13" 9c +d "SWAP14" 9d +d "SWAP15" 9e +d "SWAP16" 9f +d "LOG0" a0 +d "LOG1" a1 +d "LOG2" a2 +d "LOG3" a3 +d "LOG4" a4 +d "CREATE" f0 +d "CALL" f1 +d "CALLCODE" f2 +d "RETURN" f3 +d "DELEGATECALL" f4 +d "CREATE2" f5 +d "STATICCALL" fa +d "REVERT" fd +d "SELFDESTRUCT" ff + + +a "STOP" 00 +a "ADD" 01 +d "PUSH" b0 diff --git a/test/db/cmd/cmd_list b/test/db/cmd/cmd_list index a62216870e2..30e781596ab 100644 --- a/test/db/cmd/cmd_list +++ b/test/db/cmd/cmd_list @@ -87,7 +87,7 @@ FILE== BROKEN=1 CMDS=Loj EXPECT=<