|
|
| version 1.5, 2004/02/19 03:04:01 | version 1.13, 2012/02/07 09:11:10 |
|---|---|
| Line 1 | Line 1 |
| /* $Id$ */ | |
| /* | /* |
| * Copyright (c) 2004 NONAKA Kimihiro | * Copyright (c) 2004 NONAKA Kimihiro |
| * All rights reserved. | * All rights reserved. |
| Line 12 | Line 10 |
| * 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. | * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products | |
| * derived from this software without specific prior written permission. | |
| * | * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| Line 33 | Line 29 |
| /* | /* |
| * register strings | |
| */ | |
| const char *reg8_str[8] = { | |
| "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" | |
| }; | |
| const char *reg16_str[8] = { | |
| "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" | |
| }; | |
| const char *reg32_str[8] = { | |
| "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" | |
| }; | |
| const char *sreg_str[6] = { | |
| "es", "cs", "ss", "ds", "fs", "gs" | |
| }; | |
| /* | |
| * opcode strings | * opcode strings |
| */ | */ |
| static const char *opcode_1byte[2][256] = { | static const char *opcode_1byte[2][256] = { |
| Line 82 static const char *opcode_1byte[2][256] | Line 59 static const char *opcode_1byte[2][256] |
| /*b0*/ "movb", "movb", "movb", "movb", "movb", "movb", "movb", "movb", | /*b0*/ "movb", "movb", "movb", "movb", "movb", "movb", "movb", "movb", |
| "movw", "movw", "movw", "movw", "movw", "movw", "movw", "movw", | "movw", "movw", "movw", "movw", "movw", "movw", "movw", "movw", |
| /*c0*/ NULL, NULL, "ret", "ret", "les", "lds", "movb", "movw", | /*c0*/ NULL, NULL, "ret", "ret", "les", "lds", "movb", "movw", |
| "enter", "leave", "ret", "ret", "int3", "int", "into", "iret", | "enter", "leave", "retf", "retf", "int3", "int", "into", "iret", |
| /*d0*/ NULL, NULL, NULL, NULL, "aam", "aad", "salc", "xlat", | /*d0*/ NULL, NULL, NULL, NULL, "aam", "aad", "salc", "xlat", |
| "esc0", "esc1", "esc2", "esc3", "esc4", "esc5", "esc6", "esc7", | "esc0", "esc1", "esc2", "esc3", "esc4", "esc5", "esc6", "esc7", |
| /*e0*/ "loopne","loope", "loop", "jcxz", "inb", "inw", "outb", "outw", | /*e0*/ "loopne","loope", "loop", "jcxz", "inb", "inw", "outb", "outw", |
| Line 117 static const char *opcode_1byte[2][256] | Line 94 static const char *opcode_1byte[2][256] |
| /*b0*/ "movb", "movb", "movb", "movb", "movb", "movb", "movb", "movb", | /*b0*/ "movb", "movb", "movb", "movb", "movb", "movb", "movb", "movb", |
| "movl", "movl", "movl", "movl", "movl", "movl", "movl", "movl", | "movl", "movl", "movl", "movl", "movl", "movl", "movl", "movl", |
| /*c0*/ NULL, NULL, "ret", "ret", "les", "lds", "movb", "movl", | /*c0*/ NULL, NULL, "ret", "ret", "les", "lds", "movb", "movl", |
| "enter", "leave", "ret", "ret", "int3", "int", "into", "iretd", | "enter", "leave", "retf", "retf", "int3", "int", "into", "iretd", |
| /*d0*/ NULL, NULL, NULL, NULL, "aam", "aad", "salc", "xlat", | /*d0*/ NULL, NULL, NULL, NULL, "aam", "aad", "salc", "xlat", |
| "esc0", "esc1", "esc2", "esc3", "esc4", "esc5", "esc6", "esc7", | "esc0", "esc1", "esc2", "esc3", "esc4", "esc5", "esc6", "esc7", |
| /*e0*/ "loopne","loope", "loop", "jecxz", "inb", "inl", "outb", "outl", | /*e0*/ "loopne","loope", "loop", "jecxz", "inb", "inl", "outb", "outl", |
| Line 332 static const char *opcode2_g9[8] = { | Line 309 static const char *opcode2_g9[8] = { |
| NULL, "cmpxchg8b", NULL, NULL, NULL, NULL, NULL, NULL | NULL, "cmpxchg8b", NULL, NULL, NULL, NULL, NULL, NULL |
| }; | }; |
| #if 0 | |
| static const char *sep[2] = { " ", ", " }; | static const char *sep[2] = { " ", ", " }; |
| #endif | |
| /* | |
| * context | |
| */ | |
| typedef struct { | |
| DWORD val; | |
| DWORD eip; | |
| BOOL op32; | |
| BOOL as32; | |
| DWORD baseaddr; | |
| DWORD opcode[3]; | |
| DWORD modrm; | |
| DWORD sib; | |
| BOOL useseg; | |
| int seg; | |
| BYTE opbyte[32]; | |
| int nopbyte; | |
| char str[256]; | |
| size_t remain; | |
| char *next; | |
| char *prefix; | |
| char *op; | |
| char *arg[3]; | |
| int narg; | |
| char pad; | |
| } disasm_context_t; | |
| /* | /* |
| Line 375 typedef struct { | Line 320 typedef struct { |
| static int | static int |
| convert_address(disasm_context_t *ctx) | convert_address(disasm_context_t *ctx) |
| { | { |
| DWORD pde_addr; /* page directory entry address */ | UINT32 pde_addr; /* page directory entry address */ |
| DWORD pde; /* page directory entry */ | UINT32 pde; /* page directory entry */ |
| DWORD pte_addr; /* page table entry address */ | UINT32 pte_addr; /* page table entry address */ |
| DWORD pte; /* page table entry */ | UINT32 pte; /* page table entry */ |
| DWORD addr; | UINT32 addr; |
| if (CPU_STAT_SREG(CPU_CS_INDEX).valid) { | if (CPU_STAT_SREG(CPU_CS_INDEX).valid) { |
| addr = CPU_STAT_SREGBASE(CPU_CS_INDEX) + ctx->eip; | addr = CPU_STAT_SREGBASE(CPU_CS_INDEX) + ctx->eip; |
| if (CPU_STAT_PAGING) { | if (CPU_STAT_PAGING) { |
| pde_addr = CPU_STAT_PDE_BASE + ((addr >> 20) & 0xffc); | pde_addr = CPU_STAT_PDE_BASE + ((addr >> 20) & 0xffc); |
| pde = cpu_memoryread_d(pde_addr); | pde = cpu_memoryread_d(pde_addr); |
| /* XXX: check */ | |
| pte_addr = (pde & CPU_PDE_BASEADDR_MASK) + ((addr >> 10) & 0xffc); | pte_addr = (pde & CPU_PDE_BASEADDR_MASK) + ((addr >> 10) & 0xffc); |
| pte = cpu_memoryread_d(pte_addr); | pte = cpu_memoryread_d(pte_addr); |
| /* XXX: check */ | |
| addr = (pte & CPU_PTE_BASEADDR_MASK) + (addr & 0x00000fff); | addr = (pte & CPU_PTE_BASEADDR_MASK) + (addr & 0x00000fff); |
| } | } |
| ctx->val = addr; | ctx->val = addr; |
| Line 399 convert_address(disasm_context_t *ctx) | Line 346 convert_address(disasm_context_t *ctx) |
| static int | static int |
| disasm_codefetch_1(disasm_context_t *ctx) | disasm_codefetch_1(disasm_context_t *ctx) |
| { | { |
| BYTE val; | UINT8 val; |
| int rv; | int rv; |
| rv = convert_address(ctx); | rv = convert_address(ctx); |
| Line 409 disasm_codefetch_1(disasm_context_t *ctx | Line 356 disasm_codefetch_1(disasm_context_t *ctx |
| val = cpu_memoryread(ctx->val); | val = cpu_memoryread(ctx->val); |
| ctx->val = val; | ctx->val = val; |
| ctx->opbyte[ctx->nopbyte++] = (BYTE)ctx->val; | ctx->opbyte[ctx->nopbytes++] = (UINT8)ctx->val; |
| ctx->eip++; | ctx->eip++; |
| return 0; | return 0; |
| } | } |
| #if 0 | |
| static int | static int |
| disasm_codefetch_2(disasm_context_t *ctx) | disasm_codefetch_2(disasm_context_t *ctx) |
| { | { |
| WORD val; | UINT16 val; |
| int rv; | int rv; |
| rv = disasm_codefetch_1(ctx); | rv = disasm_codefetch_1(ctx); |
| if (rv) | if (rv) |
| return rv; | return rv; |
| val = (WORD)(ctx->val & 0xff); | val = (UINT16)(ctx->val & 0xff); |
| rv = disasm_codefetch_1(ctx); | rv = disasm_codefetch_1(ctx); |
| if (rv) | if (rv) |
| return rv; | return rv; |
| val |= (WORD)(ctx->val & 0xff) << 8; | val |= (UINT16)(ctx->val & 0xff) << 8; |
| ctx->val = val; | ctx->val = val; |
| return 0; | return 0; |
| Line 437 disasm_codefetch_2(disasm_context_t *ctx | Line 385 disasm_codefetch_2(disasm_context_t *ctx |
| static int | static int |
| disasm_codefetch_4(disasm_context_t *ctx) | disasm_codefetch_4(disasm_context_t *ctx) |
| { | { |
| DWORD val; | UINT32 val; |
| int rv; | int rv; |
| rv = disasm_codefetch_1(ctx); | rv = disasm_codefetch_1(ctx); |
| Line 447 disasm_codefetch_4(disasm_context_t *ctx | Line 395 disasm_codefetch_4(disasm_context_t *ctx |
| rv = disasm_codefetch_1(ctx); | rv = disasm_codefetch_1(ctx); |
| if (rv) | if (rv) |
| return rv; | return rv; |
| val |= (DWORD)(ctx->val & 0xff) << 8; | val |= (UINT32)(ctx->val & 0xff) << 8; |
| rv = disasm_codefetch_1(ctx); | rv = disasm_codefetch_1(ctx); |
| if (rv) | if (rv) |
| return rv; | return rv; |
| val |= (DWORD)(ctx->val & 0xff) << 16; | val |= (UINT32)(ctx->val & 0xff) << 16; |
| rv = disasm_codefetch_1(ctx); | rv = disasm_codefetch_1(ctx); |
| if (rv) | if (rv) |
| return rv; | return rv; |
| val |= (DWORD)(ctx->val & 0xff) << 24; | val |= (UINT32)(ctx->val & 0xff) << 24; |
| ctx->val = val; | ctx->val = val; |
| return 0; | return 0; |
| Line 472 ea16(disasm_context_t *ctx, char *buf, s | Line 420 ea16(disasm_context_t *ctx, char *buf, s |
| "bx + si", "bx + di", "bp + si", "bp + di", | "bx + si", "bx + di", "bp + si", "bp + di", |
| "si", "di", "bp", "bx" | "si", "di", "bp", "bx" |
| }; | }; |
| // char tmp[32]; | UINT32 val; |
| DWORD mod, rm; | UINT mod, rm; |
| DWORD val; | |
| int rv; | int rv; |
| mod = (ctx->modrm >> 6) & 3; | mod = (ctx->modrm >> 6) & 3; |
| Line 487 ea16(disasm_context_t *ctx, char *buf, s | Line 434 ea16(disasm_context_t *ctx, char *buf, s |
| if (rv) | if (rv) |
| return rv; | return rv; |
| snprintf(buf, size, "[0x%04lx]", ctx->val); | snprintf(buf, size, "[0x%04x]", ctx->val); |
| } else { | } else { |
| snprintf(buf, size, "[%s]", ea16_str[rm]); | snprintf(buf, size, "[%s]", ea16_str[rm]); |
| } | } |
| Line 510 ea16(disasm_context_t *ctx, char *buf, s | Line 457 ea16(disasm_context_t *ctx, char *buf, s |
| val = ctx->val; | val = ctx->val; |
| } | } |
| snprintf(buf, size, "[%s + 0x%04lx]", ea16_str[rm], val); | snprintf(buf, size, "[%s + 0x%04x]", ea16_str[rm], val); |
| } | } |
| return 0; | return 0; |
| Line 520 static int | Line 467 static int |
| ea32(disasm_context_t *ctx, char *buf, size_t size) | ea32(disasm_context_t *ctx, char *buf, size_t size) |
| { | { |
| char tmp[32]; | char tmp[32]; |
| DWORD count[9]; | UINT count[9]; |
| DWORD mod, rm; | UINT32 val; |
| DWORD sib; | UINT mod, rm; |
| DWORD scale; | UINT sib; |
| DWORD idx; | UINT scale; |
| DWORD base; | UINT idx; |
| DWORD val; | UINT base; |
| int rv; | int rv; |
| int i, n; | int i, n; |
| Line 604 ea32(disasm_context_t *ctx, char *buf, s | Line 551 ea32(disasm_context_t *ctx, char *buf, s |
| milstr_ncat(buf, " + ", size); | milstr_ncat(buf, " + ", size); |
| } | } |
| if (count[i] > 1) { | if (count[i] > 1) { |
| snprintf(tmp, size, "%s * %ld", | snprintf(tmp, size, "%s * %d", |
| reg32_str[i], count[i]); | reg32_str[i], count[i]); |
| } else { | } else { |
| milstr_ncpy(tmp, reg32_str[i], sizeof(tmp)); | milstr_ncpy(tmp, reg32_str[i], sizeof(tmp)); |
| Line 617 ea32(disasm_context_t *ctx, char *buf, s | Line 564 ea32(disasm_context_t *ctx, char *buf, s |
| if (n > 0) { | if (n > 0) { |
| milstr_ncat(buf, " + ", size); | milstr_ncat(buf, " + ", size); |
| } | } |
| snprintf(tmp, sizeof(tmp), "0x%08lx", count[8]); | snprintf(tmp, sizeof(tmp), "0x%08x", count[8]); |
| milstr_ncat(buf, tmp, size); | milstr_ncat(buf, tmp, size); |
| } | } |
| milstr_ncat(buf, "]", size); | milstr_ncat(buf, "]", size); |
| Line 665 ea(disasm_context_t *ctx) | Line 612 ea(disasm_context_t *ctx) |
| return 0; | return 0; |
| } | } |
| #endif | |
| /* | /* |
| * get opcode | * get opcode |
| */ | */ |
| static int | static int |
| op(disasm_context_t *ctx) | get_opcode(disasm_context_t *ctx) |
| { | { |
| const char *opcode; | const char *opcode; |
| // DWORD type; | UINT8 op[3]; |
| BYTE op[3]; | |
| int prefix; | int prefix; |
| int len; | size_t len; |
| int rv; | int rv; |
| int i; | int i; |
| Line 685 op(disasm_context_t *ctx) | Line 632 op(disasm_context_t *ctx) |
| if (rv) | if (rv) |
| return rv; | return rv; |
| op[0] = (BYTE)(ctx->val & 0xff); | op[0] = (UINT8)(ctx->val & 0xff); |
| if (insttable_info[op[0]] & INST_PREFIX) { | if (!(insttable_info[op[0]] & INST_PREFIX)) |
| if (ctx->prefix == 0) | break; |
| ctx->prefix = ctx->next; | |
| if (ctx->prefix == 0) | |
| switch (op[0]) { | ctx->prefix = ctx->next; |
| case 0x26: /* ES: */ | |
| case 0x2e: /* CS: */ | switch (op[0]) { |
| case 0x36: /* SS: */ | case 0x26: /* ES: */ |
| case 0x3e: /* DS: */ | case 0x2e: /* CS: */ |
| ctx->useseg = TRUE; | case 0x36: /* SS: */ |
| ctx->seg = (op[0] >> 3) & 3; | case 0x3e: /* DS: */ |
| break; | ctx->useseg = TRUE; |
| ctx->seg = (op[0] >> 3) & 3; | |
| case 0x64: /* FS: */ | break; |
| case 0x65: /* GS: */ | |
| ctx->useseg = TRUE; | case 0x64: /* FS: */ |
| ctx->seg = (op[0] - 0x64) + 4; | case 0x65: /* GS: */ |
| break; | ctx->useseg = TRUE; |
| ctx->seg = (op[0] - 0x64) + 4; | |
| case 0x66: /* OPSize: */ | break; |
| ctx->op32 = !CPU_INST_OP32; | |
| break; | case 0x66: /* OPSize: */ |
| ctx->op32 = !CPU_STATSAVE.cpu_inst_default.op_32; | |
| case 0x67: /* AddrSize: */ | break; |
| ctx->as32 = !CPU_INST_AS32; | |
| break; | case 0x67: /* AddrSize: */ |
| } | ctx->as32 = !CPU_STATSAVE.cpu_inst_default.as_32; |
| continue; | break; |
| } | } |
| break; | |
| } | } |
| if (prefix == MAX_PREFIX) | if (prefix == MAX_PREFIX) |
| return 1; | return 1; |
| Line 729 op(disasm_context_t *ctx) | Line 675 op(disasm_context_t *ctx) |
| } | } |
| } | } |
| len = strlen(ctx->next); | len = strlen(ctx->next); |
| len = (len < (int)ctx->remain) ? len : ctx->remain; | len = (len < ctx->remain) ? len : ctx->remain; |
| ctx->next += len; | ctx->next += len; |
| ctx->remain -= len; | ctx->remain -= len; |
| } | } |
| Line 741 op(disasm_context_t *ctx) | Line 687 op(disasm_context_t *ctx) |
| if (rv) | if (rv) |
| return rv; | return rv; |
| op[1] = (BYTE)(ctx->val & 0xff); | op[1] = (UINT8)(ctx->val & 0xff); |
| ctx->opcode[1] = op[1]; | ctx->opcode[1] = op[1]; |
| switch (op[0]) { | switch (op[0]) { |
| Line 752 op(disasm_context_t *ctx) | Line 698 op(disasm_context_t *ctx) |
| if (rv) | if (rv) |
| return rv; | return rv; |
| op[2] = (BYTE)(ctx->val & 0xff); | op[2] = (UINT8)(ctx->val & 0xff); |
| ctx->opcode[2] = op[2]; | ctx->opcode[2] = op[2]; |
| switch (op[1]) { | switch (op[1]) { |
| Line 813 op(disasm_context_t *ctx) | Line 759 op(disasm_context_t *ctx) |
| * interface | * interface |
| */ | */ |
| int | int |
| disasm(DWORD *eip, char *buf, size_t size) | disasm(UINT32 *eip, disasm_context_t *ctx) |
| { | { |
| disasm_context_t ctx; | |
| int rv; | int rv; |
| memset(&ctx, 0, sizeof(ctx)); | memset(ctx, 0, sizeof(disasm_context_t)); |
| ctx.remain = sizeof(ctx.str) - 1; | ctx->remain = sizeof(ctx->str) - 1; |
| ctx.next = ctx.str; | ctx->next = ctx->str; |
| ctx.prefix = 0; | ctx->prefix = 0; |
| ctx.op = 0; | ctx->op = 0; |
| ctx.arg[0] = 0; | ctx->arg[0] = 0; |
| ctx.arg[1] = 0; | ctx->arg[1] = 0; |
| ctx.arg[2] = 0; | ctx->arg[2] = 0; |
| ctx.eip = *eip; | ctx->eip = *eip; |
| ctx.op32 = CPU_INST_OP32; | ctx->op32 = CPU_STATSAVE.cpu_inst_default.op_32; |
| ctx.as32 = CPU_INST_AS32; | ctx->as32 = CPU_STATSAVE.cpu_inst_default.as_32; |
| ctx.seg = -1; | ctx->seg = -1; |
| ctx.baseaddr = ctx.eip; | ctx->baseaddr = ctx->eip; |
| ctx.pad = ' '; | ctx->pad = ' '; |
| rv = op(&ctx); | rv = get_opcode(ctx); |
| if (rv) { | if (rv) { |
| memset(&ctx, 0, sizeof(ctx)); | memset(ctx, 0, sizeof(disasm_context_t)); |
| return rv; | return rv; |
| } | } |
| *eip = ctx->eip; | |
| *eip = ctx.eip; | |
| milstr_ncpy(buf, ctx.str, size); | |
| return 0; | return 0; |
| } | } |
| char * | |
| cpu_disasm2str(UINT32 eip) | |
| { | |
| static char output[2048]; | |
| disasm_context_t d; | |
| UINT32 eip2 = eip; | |
| int rv; | |
| output[0] = '\0'; | |
| rv = disasm(&eip2, &d); | |
| if (rv == 0) { | |
| char buf[256]; | |
| char tmp[32]; | |
| int len = d.nopbytes > 8 ? 8 : d.nopbytes; | |
| int i; | |
| buf[0] = '\0'; | |
| for (i = 0; i < len; i++) { | |
| snprintf(tmp, sizeof(tmp), "%02x ", d.opbyte[i]); | |
| milstr_ncat(buf, tmp, sizeof(buf)); | |
| } | |
| for (; i < 8; i++) { | |
| milstr_ncat(buf, " ", sizeof(buf)); | |
| } | |
| snprintf(output, sizeof(output), "%04x:%08x: %s%s", | |
| CPU_CS, eip, buf, d.str); | |
| if (i < d.nopbytes) { | |
| char t[256]; | |
| buf[0] = '\0'; | |
| for (; i < d.nopbytes; i++) { | |
| snprintf(tmp, sizeof(tmp), "%02x ", | |
| d.opbyte[i]); | |
| milstr_ncat(buf, tmp, sizeof(buf)); | |
| if ((i % 8) == 7) { | |
| snprintf(t, sizeof(t), | |
| "\n : %s", buf); | |
| milstr_ncat(output, t, sizeof(output)); | |
| buf[0] = '\0'; | |
| } | |
| } | |
| if ((i % 8) != 0) { | |
| snprintf(t, sizeof(t), | |
| "\n : %s", buf); | |
| milstr_ncat(output, t, sizeof(output)); | |
| } | |
| } | |
| } | |
| return output; | |
| } |