Initial commit
authorBernhard Urban <lewurm@gmail.com>
Mon, 29 Aug 2011 00:18:28 +0000 (02:18 +0200)
committerBernhard Urban <lewurm@gmail.com>
Mon, 29 Aug 2011 00:18:28 +0000 (02:18 +0200)
dirty & untested

.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
dis-ebc.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..618686e
--- /dev/null
@@ -0,0 +1 @@
+dis-ebc
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <string.h>
+#include <assert.h>
+
+#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 <pe-ebc>\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;
+}