From 14f5abf8f7ec9ee71b7c07219bd79a860c9cd00c Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Mon, 29 Aug 2011 02:18:28 +0200 Subject: [PATCH] Initial commit dirty & untested --- .gitignore | 1 + Makefile | 7 + dis-ebc.c | 469 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 477 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 dis-ebc.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..618686e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dis-ebc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4172574 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +CFLAGS = -O2 -Wall -std=gnu99 + +all: dis-ebc + +.PHONY: clean +clean: + rm -f dis-ebc diff --git a/dis-ebc.c b/dis-ebc.c new file mode 100644 index 0000000..b96ec15 --- /dev/null +++ b/dis-ebc.c @@ -0,0 +1,469 @@ +/* todo: copyright/gpl stuff. */ + +#ifndef __i386__ +#error "use it on your own risk" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PS "%-10s: " + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +static int file_len; +static u8 *data, *data_start; +static u32 base_data, base_code, size_code; + +static char *imm_chw[] = { + "b", /* 08 bits */ "w", /* 16 bits */ + "d", /* 32 bits */ "q", /* 64 bits */ + "n" /* unsigned int. hax */ , + "sn" /* signed int. hax */ +}; + +static char *vm_reg[] = { + "FLAGS", "IP", "RESERVED", "RESERVED", + "RESERVED", "RESERVED", "RESERVED", "RESERVED" +}; + +static void print_debug(const char *s) +{ + fprintf(stderr, PS "0x%08x (0x%04x)\n", s, (u32) data, + data - data_start); +} + +static void pspace(void) { printf(" "); } + +static void pcomma(void) { printf(", "); } + +static void preg(u8 reg) +{ + if (reg > 7) { assert(0); } + printf("r%1d", reg); +} + +static void pvmreg(u8 reg) +{ + if (reg > 7) { assert(0); } + printf("%s", vm_reg[reg]); +} + +static void pdref(u8 x) +{ + printf("%s", x ? "@" : ""); +} + +#define PIMM_READ(size) \ + static void pimm##size(void) \ + { \ + printf(size != 64 ? "%x" : "%llx", *((u##size *) data)); \ + data += sizeof (u##size); \ + } + +PIMM_READ(8); +PIMM_READ(16); +PIMM_READ(32); +PIMM_READ(64); + +static void pimm(u8 mod) +{ + switch (mod) { + case 1: pimm16(); break; + case 2: pimm32(); break; + case 3: pimm64(); break; + case 0: default: assert(0); + } +} + +static void pimmc(u8 imm_type) +{ + if (imm_type > 5) { assert(0); } + printf("%s", imm_chw[imm_type]); +} + +static void pflags(u8 flag) +{ + switch (flag) { + case 0x0: printf("eq"); break; + case 0x1: printf("lte"); break; + case 0x2: printf("gte"); break; + case 0x3: printf("ulte"); break; + case 0x4: printf("ugte"); break; + } +} + +static const char *breakopts[] = { + "Runaway program break", + "Get virtual machine version", + "undefined. WTF?", // "Skip"? + "Debug breakpoint", + "System call", + "Create thunk", + "Set compiler version" +}; + +static void pbreak(void) +{ + u8 i = *data++; + pspace(); + if (i > 6) { printf("unknown break!"); assert(0); + } else printf("\"%s\"", breakopts[i]); +} + +static void pinsn(void) +{ + u8 insn = *data++; + u8 opc = insn & 0x3f; + + switch (opc) { + case 0x00: printf("BREAK"); pbreak(); break; + case 0x01: case 0x03:{ + u8 opindex = insn & 0x80; + u8 c3264 = insn & 0x40; + + u8 b1 = *data++; + u8 cond = b1 & 0x80; + u8 flag = b1 & 0x40; + u8 ebcnative = b1 & 0x20; + u8 relabs = b1 & 0x10; + u8 op1 = b1 & 0x7; + u8 dref1 = b1 & 0x8; + + if (opc == 0x01) { + printf("JMP%d%s", c3264 ? 64 : 32, + cond ? (flag ? "cs" : "cc") : ""); + } else if (opc == 0x03) { + printf("CALL%d%s", c3264 ? 64 : 32, + ebcnative ? "EX" : ""); + } + printf("%s", relabs ? "a" : ""); pspace(); + + if (!c3264) { // 32bit + pdref(dref1); + preg(op1); + if (opindex) { + pspace(); pimm32(); + } + } else { // 64bit + pimm64(); + } + } + break; + case 0x02:{ + u8 cond = insn & 0x80; + u8 flag = insn & 0x40; + printf("JMP8%s", cond ? (flag ? "cs" : "cc") : ""); + pspace(); pimm8(); + } + break; + case 0x04: printf("RET"); data++; break; + case 0x05 ... 0x09:{ + u8 opindex = insn & 0x80; + u8 c3264 = insn & 0x40; + + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 op2 = (b1 & 0x70) >> 4; + u8 dref2 = b1 & 0x80; + + printf("CMP%d", !c3264 ? 32 : 64); + pflags(opc - 0x05); pspace(); + preg(op1); pcomma(); + pdref(dref2); preg(op2); + if (opindex) { + pspace(); pimm16(); + } + } + break; + case 0x0a ... 0x19:{ + u8 opindex = insn & 0x80; + u8 c3264 = insn & 0x40; + + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref1 = b1 & 0x8; + u8 op2 = (b1 & 0x70) >> 4; + u8 dref2 = b1 & 0x80; + switch (opc) { + case 0x0a: printf("NOT"); break; + case 0x0b: printf("NEG"); break; + case 0x0c: printf("ADD"); break; + case 0x0d: printf("SUB"); break; + case 0x0e: printf("MUL"); break; + case 0x0f: printf("MULU"); break; + case 0x10: printf("DIV"); break; + case 0x11: printf("DIVU"); break; + case 0x12: printf("MOD"); break; + case 0x13: printf("MODU"); break; + case 0x14: printf("AND"); break; + case 0x15: printf("OR"); break; + case 0x16: printf("XOR"); break; + case 0x17: printf("SHL"); break; + case 0x18: printf("SHR"); break; + case 0x19: printf("ASHR"); break; + default: + printf("\nopcode: %x\n", opc); + assert(0); + } + printf("%d", c3264 ? 64 : 32); pspace(); + pdref(dref1); preg(op1); pcomma(); + pdref(dref2); preg(op2); + if (opindex) { + pspace(); pimm16(); + } + } + break; + case 0x1a ... 0x1c:{ + u8 opindex = insn & 0x80; + u8 c3264 = insn & 0x40; + u8 opmod = opc - 0x1a; // 0b, 1w, 2d + + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref1 = b1 & 0x8; + u8 op2 = (b1 & 0x70) >> 4; + u8 dref2 = b1 & 0x80; + + printf("EXTND"); pimmc(opmod); + printf("%d", c3264 ? 64 : 32); pspace(); + pdref(dref1); preg(op1); pcomma(); + pdref(dref2); preg(op2); + if (opindex) { + pspace(); pimm16(); + } + } + break; + case 0x2a:{ + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 op2 = (b1 & 0x70) >> 4; + + printf("STORESP"); pspace(); + preg(op1); pcomma(); pvmreg(op2); + } + break; + case 0x2d ... 0x31:{ + u8 c3264 = insn & 0x40; + u8 i1632 = !!(insn & 0x80); + + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref1 = b1 & 0x8; + u8 op1index = b1 & 0x10; + + printf("CMPI%d", !c3264 ? 32 : 64); + pimmc(i1632 + 1); + pflags(opc - 0x2d); pspace(); + pdref(dref1); preg(op1); + if (op1index) { + pspace(); pimm16(); + } + pcomma(); + if (i1632) pimm32(); + else pimm16(); + } + break; + case 0x1d ... 0x28: + case 0x32 ... 0x33:{ + u8 op1mod = 0; + u8 op2mod = 0; + switch (opc) { + case 0x1d: op1mod = 0; op2mod = 1; break; // MOVbw + case 0x1e: op1mod = 1; op2mod = 1; break; // MOVww + case 0x1f: op1mod = 2; op2mod = 1; break; // MOVdw + case 0x20: op1mod = 3; op2mod = 1; break; // MOVqw + case 0x21: op1mod = 0; op2mod = 2; break; // MOVbd + case 0x22: op1mod = 1; op2mod = 2; break; // MOVwd + case 0x23: op1mod = 2; op2mod = 2; break; // MOVdd + case 0x24: op1mod = 3; op2mod = 2; break; // MOVqd + + case 0x25: op1mod = 5; op2mod = 1; break; // MOVsnw + case 0x26: op1mod = 5; op2mod = 2; break; // MOVsnq + + case 0x28: op1mod = 3; op2mod = 3; break; // MOVqq + + case 0x32: op1mod = 4; op2mod = 1; break; // MOVnw + case 0x33: op1mod = 4; op2mod = 2; break; // MOVnd + default: + fprintf(stderr, "wtfopcode: %x\n", opc); + assert(0); + } + u8 mod = (insn & 0xc0) >> 6; + u8 op1index = mod & 0x2; + u8 op2index = mod & 0x1; + + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref1 = b1 & 0x8; + u8 op2 = (b1 & 0x70) >> 4; + u8 dref2 = b1 & 0x80; + + printf("MOV"); pimmc(op1mod); pimmc(op2mod); pspace(); + pdref(dref1); preg(op1); + // op2mod defines index width for *both* indexes + if (op1index) { + pspace(); pimm(op2mod); + } + pcomma(); pdref(dref2); preg(op2); + if (op2index) { + pspace(); pimm(op2mod); + } + } + break; + case 0x37:{ + u8 mod = (insn & 0xc0) >> 6; + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref = b1 & 0x8; + u8 width = (b1 & 0x30) >> 4; + u8 op1index = b1 & 0x40; + + printf("MOVI"); pimmc(width); pimmc(mod); pspace(); + pdref(dref); preg(op1); + if (op1index) { + pspace(); pimm16(); + } + pcomma(); pimm(mod); + } + break; + case 0x38:{ + u8 mod = (insn & 0xc0) >> 6; + + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref = b1 & 0x8; + u8 op1index = (b1 & 0x40) >> 6; + + printf("MOVIn"); pimmc(mod); pspace(); + pdref(dref); preg(op1); + if (op1index) { + pspace(); pimm16(); + } + pcomma(); pimm(mod); + } + break; + case 0x39:{ + u8 mod = (insn & 0xc0) >> 6; + u8 b1 = *data++; + u8 op1 = b1 & 0x7; + u8 dref = b1 & 0x8; + u8 op1index = b1 & 0x40; + + printf("MOVREL"); pimmc(mod); pspace(); + pdref(dref); preg(op1); + if (op1index) { + pspace(); pimm16(); + } + pcomma(); pimm(mod); + } + break; + default: + fprintf(stderr, "\nunknown opcode: 0x%02x\n", opc); + assert(0); + } +} + +static void pheader(void) +{ + printf("\n%08x: ", data - data_start); +} + +int main(int argc, const char **argv) +{ + if (argc != 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + + int fd = open(argv[1], O_RDONLY); + file_len = lseek(fd, 0, SEEK_END); + data_start = data = mmap(0, file_len, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + if (memcmp(data, "MZ", 2) != 0) { + fprintf(stderr, "wrong DOS header: %c%c\n", *data, *(data + 1)); + exit(2); + } else { + print_debug("data"); + } + + int found = 0; + while (!found && ++data < (data + file_len)) { + if (memcmp(data, "PE", 2) == 0) { + print_debug("PE"); + found = 1; + } + } + + if (!found) { + fprintf(stderr, "no PE header found\n"); + exit(3); + } + + data += 4; + if (memcmp(data, "\xbc\x0e", 2) != 0) { // read '0xebc' + fprintf(stderr, "not an EBC image: 0x%02x%02x\n", *data, + *(data + 1)); + exit(4); + } + + found = 0; + while (!found && ++data < (data + file_len)) { + if (memcmp(data, "\x0b\x01", 2) == 0) { // read '0x10b' + print_debug("PE-opt"); + found = 1; + } + } + + if (!found) { + fprintf(stderr, "no PE-opt header found\n"); + exit(3); + } + + fprintf(stderr, PS "0x%04x\n", "magic", *((u16 *) data)); + data += 2; //u16 + + fprintf(stderr, PS "0x%02x\n", "majorver", *((u8 *) data)); + data++; //u8 + fprintf(stderr, PS "0x%02x\n", "minorver", *((u8 *) data)); + data++; //u8 + + // TODO: not sure if this is correct :/ + size_code = *((u32 *) data); + print_debug("size_code"); + fprintf(stderr, PS "0x%08x\n", "size_code", size_code); + data += 4 + 4 + 4; //u32, u32, u32 + + fprintf(stderr, PS "0x%08x\n", "entry_point", *((u32 *) data)); + data += 4; //u32 + + base_code = *((u32 *) data); + print_debug("base_code"); + fprintf(stderr, PS "0x%08x\n", "base_code", base_code); + data += 4; + base_data = *((u32 *) data); + print_debug("base_data"); + fprintf(stderr, PS "0x%08x\n", "base_data", base_data); + + data += 4; //u32 + fprintf(stderr, PS "0x%08x\n", "???", *((u32 *) data)); + + data = data_start + base_code; + while (data <= (data_start + size_code)) { + pheader(); + pinsn(); + } + printf("\n"); + + return 0; +} -- 2.25.1