341 lines
12 KiB
C++
341 lines
12 KiB
C++
#include <string.h>
|
|
#include <vendor/hde.hpp>
|
|
|
|
static unsigned char hde32_table[] = {
|
|
0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xac, 0xaa, 0xb2, 0xaa, 0x9f, 0x9f, 0x9f, 0x9f, 0xb5, 0xa3, 0xa3, 0xa4, 0xaa, 0xaa, 0xba, 0xaa, 0x96, 0xaa, 0xa8, 0xaa,
|
|
0xc3, 0xc3, 0x96, 0x96, 0xb7, 0xae, 0xd6, 0xbd, 0xa3, 0xc5, 0xa3, 0xa3, 0x9f, 0xc3, 0x9c, 0xaa, 0xaa, 0xac, 0xaa, 0xbf, 0x03, 0x7f,
|
|
0x11, 0x7f, 0x01, 0x7f, 0x01, 0x3f, 0x01, 0x01, 0x90, 0x82, 0x7d, 0x97, 0x59, 0x59, 0x59, 0x59, 0x59, 0x7f, 0x59, 0x59, 0x60, 0x7d,
|
|
0x7f, 0x7f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x9a, 0x88, 0x7d, 0x59, 0x50, 0x50, 0x50, 0x50,
|
|
0x59, 0x59, 0x59, 0x59, 0x61, 0x94, 0x61, 0x9e, 0x59, 0x59, 0x85, 0x59, 0x92, 0xa3, 0x60, 0x60, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
|
|
0x59, 0x59, 0x59, 0x59, 0x59, 0x9f, 0x01, 0x03, 0x01, 0x04, 0x03, 0xd5, 0x03, 0xcc, 0x01, 0xbc, 0x03, 0xf0, 0x10, 0x10, 0x10, 0x10,
|
|
0x50, 0x50, 0x50, 0x50, 0x14, 0x20, 0x20, 0x20, 0x20, 0x01, 0x01, 0x01, 0x01, 0xc4, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
|
0xc0, 0xc2, 0x10, 0x11, 0x02, 0x03, 0x11, 0x03, 0x03, 0x04, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x00, 0xc6, 0xc8, 0x02, 0x02, 0x02,
|
|
0x02, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xca, 0x01, 0x01, 0x01, 0x00, 0x06, 0x00, 0x04, 0x00, 0xc0, 0xc2,
|
|
0x01, 0x01, 0x03, 0x01, 0xff, 0xff, 0x01, 0x00, 0x03, 0xc4, 0xc4, 0xc6, 0x03, 0x01, 0x01, 0x01, 0xff, 0x03, 0x03, 0x03, 0xc8, 0x40,
|
|
0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xff, 0xff,
|
|
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xff, 0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x4a, 0x4a, 0x4a, 0x4a,
|
|
0x4b, 0x52, 0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4c, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x55, 0x45, 0x40, 0x4a, 0x4a, 0x4a,
|
|
0x45, 0x59, 0x4d, 0x46, 0x4a, 0x5d, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x61, 0x63,
|
|
0x67, 0x4e, 0x4a, 0x4a, 0x6b, 0x6d, 0x4a, 0x4a, 0x45, 0x6d, 0x4a, 0x4a, 0x44, 0x45, 0x4a, 0x4a, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x06,
|
|
0x06, 0x06, 0x06, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x02, 0x06, 0x00, 0x0a, 0x0a, 0x07, 0x07, 0x06,
|
|
0x02, 0x05, 0x05, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x06, 0x06, 0x06, 0x01, 0x06, 0x00,
|
|
0x00, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x28, 0x00, 0x30, 0x00, 0x80, 0x01, 0x82, 0x01, 0x86, 0x00, 0xf6, 0xcf, 0xfe,
|
|
0x3f, 0xab, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xba, 0xf8, 0xbb, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc7, 0xbf, 0x62, 0xff, 0x00,
|
|
0x8d, 0xff, 0x00, 0xc4, 0xff, 0x00, 0xc5, 0xff, 0x00, 0xff, 0xff, 0xeb, 0x01, 0xff, 0x0e, 0x12, 0x08, 0x00, 0x13, 0x09, 0x00, 0x16,
|
|
0x08, 0x00, 0x17, 0x09, 0x00, 0x2b, 0x09, 0x00, 0xae, 0xff, 0x07, 0xb2, 0xff, 0x00, 0xb4, 0xff, 0x00, 0xb5, 0xff, 0x00, 0xc3, 0x01,
|
|
0x00, 0xc7, 0xff, 0xbf, 0xe7, 0x08, 0x00, 0xf0, 0x02, 0x00 //
|
|
};
|
|
|
|
unsigned int hde32_disasm(const void *code, hde32s *hs) {
|
|
uint8_t x, c, *p = (uint8_t *) code, cflags, opcode, pref = 0;
|
|
uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
|
|
|
|
memset(hs, 0, sizeof(hde32s));
|
|
|
|
for (x = 16; x; x--)
|
|
switch (c = *p++) {
|
|
case 0xf3:
|
|
hs->p_rep = c;
|
|
pref |= PRE_F3;
|
|
break;
|
|
case 0xf2:
|
|
hs->p_rep = c;
|
|
pref |= PRE_F2;
|
|
break;
|
|
case 0xf0:
|
|
hs->p_lock = c;
|
|
pref |= PRE_LOCK;
|
|
break;
|
|
case 0x26:
|
|
case 0x2e:
|
|
case 0x36:
|
|
case 0x3e:
|
|
case 0x64:
|
|
case 0x65:
|
|
hs->p_seg = c;
|
|
pref |= PRE_SEG;
|
|
break;
|
|
case 0x66:
|
|
hs->p_66 = c;
|
|
pref |= PRE_66;
|
|
break;
|
|
case 0x67:
|
|
hs->p_67 = c;
|
|
pref |= PRE_67;
|
|
break;
|
|
default: goto pref_done;
|
|
}
|
|
pref_done:
|
|
|
|
hs->flags = (uint32_t) pref << 23;
|
|
|
|
if (!pref)
|
|
pref |= PRE_NONE;
|
|
|
|
if ((hs->opcode = c) == 0x0f) {
|
|
hs->opcode2 = c = *p++;
|
|
ht += DELTA_OPCODES;
|
|
} else if (c >= 0xa0 && c <= 0xa3) {
|
|
if (pref & PRE_67)
|
|
pref |= PRE_66;
|
|
else
|
|
pref &= ~PRE_66;
|
|
}
|
|
|
|
opcode = c;
|
|
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
|
|
|
if (cflags == C_ERROR) {
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
cflags = 0;
|
|
if ((opcode & -3) == 0x24)
|
|
cflags++;
|
|
}
|
|
|
|
x = 0;
|
|
if (cflags & C_GROUP) {
|
|
uint16_t t;
|
|
t = *(uint16_t *) (ht + (cflags & 0x7f));
|
|
cflags = (uint8_t) t;
|
|
x = (uint8_t) (t >> 8);
|
|
}
|
|
|
|
if (hs->opcode2) {
|
|
ht = hde32_table + DELTA_PREFIXES;
|
|
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
}
|
|
|
|
if (cflags & C_MODRM) {
|
|
hs->flags |= F_MODRM;
|
|
hs->modrm = c = *p++;
|
|
hs->modrm_mod = m_mod = c >> 6;
|
|
hs->modrm_rm = m_rm = c & 7;
|
|
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
|
|
|
if (x && ((x << m_reg) & 0x80))
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
|
|
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
|
uint8_t t = opcode - 0xd9;
|
|
if (m_mod == 3) {
|
|
ht = hde32_table + DELTA_FPU_MODRM + t * 8;
|
|
t = ht[m_reg] << m_rm;
|
|
} else {
|
|
ht = hde32_table + DELTA_FPU_REG;
|
|
t = ht[t] << m_reg;
|
|
}
|
|
if (t & 0x80)
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
}
|
|
|
|
if (pref & PRE_LOCK) {
|
|
if (m_mod == 3) {
|
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
} else {
|
|
uint8_t *table_end, op = opcode;
|
|
if (hs->opcode2) {
|
|
ht = hde32_table + DELTA_OP2_LOCK_OK;
|
|
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
|
} else {
|
|
ht = hde32_table + DELTA_OP_LOCK_OK;
|
|
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
|
op &= -2;
|
|
}
|
|
for (; ht != table_end; ht++)
|
|
if (*ht++ == op) {
|
|
if (!((*ht << m_reg) & 0x80))
|
|
goto no_lock_error;
|
|
else
|
|
break;
|
|
}
|
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
no_lock_error:;
|
|
}
|
|
}
|
|
|
|
if (hs->opcode2) {
|
|
switch (opcode) {
|
|
case 0x20:
|
|
case 0x22:
|
|
m_mod = 3;
|
|
if (m_reg > 4 || m_reg == 1)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
case 0x21:
|
|
case 0x23:
|
|
m_mod = 3;
|
|
if (m_reg == 4 || m_reg == 5)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
}
|
|
} else {
|
|
switch (opcode) {
|
|
case 0x8c:
|
|
if (m_reg > 5)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
case 0x8e:
|
|
if (m_reg == 1 || m_reg > 5)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
}
|
|
}
|
|
|
|
if (m_mod == 3) {
|
|
uint8_t *table_end;
|
|
if (hs->opcode2) {
|
|
ht = hde32_table + DELTA_OP2_ONLY_MEM;
|
|
table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
|
|
} else {
|
|
ht = hde32_table + DELTA_OP_ONLY_MEM;
|
|
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
|
}
|
|
for (; ht != table_end; ht += 2)
|
|
if (*ht++ == opcode) {
|
|
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
|
|
goto error_operand;
|
|
else
|
|
break;
|
|
}
|
|
goto no_error_operand;
|
|
} else if (hs->opcode2) {
|
|
switch (opcode) {
|
|
case 0x50:
|
|
case 0xd7:
|
|
case 0xf7:
|
|
if (pref & (PRE_NONE | PRE_66))
|
|
goto error_operand;
|
|
break;
|
|
case 0xd6:
|
|
if (pref & (PRE_F2 | PRE_F3))
|
|
goto error_operand;
|
|
break;
|
|
case 0xc5: goto error_operand;
|
|
}
|
|
goto no_error_operand;
|
|
} else
|
|
goto no_error_operand;
|
|
|
|
error_operand:
|
|
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
|
no_error_operand:
|
|
|
|
c = *p++;
|
|
if (m_reg <= 1) {
|
|
if (opcode == 0xf6)
|
|
cflags |= C_IMM8;
|
|
else if (opcode == 0xf7)
|
|
cflags |= C_IMM_P66;
|
|
}
|
|
|
|
switch (m_mod) {
|
|
case 0:
|
|
if (pref & PRE_67) {
|
|
if (m_rm == 6)
|
|
disp_size = 2;
|
|
} else if (m_rm == 5)
|
|
disp_size = 4;
|
|
break;
|
|
case 1: disp_size = 1; break;
|
|
case 2:
|
|
disp_size = 2;
|
|
if (!(pref & PRE_67))
|
|
disp_size <<= 1;
|
|
break;
|
|
}
|
|
|
|
if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
|
|
hs->flags |= F_SIB;
|
|
p++;
|
|
hs->sib = c;
|
|
hs->sib_scale = c >> 6;
|
|
hs->sib_index = (c & 0x3f) >> 3;
|
|
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
|
disp_size = 4;
|
|
}
|
|
|
|
p--;
|
|
switch (disp_size) {
|
|
case 1:
|
|
hs->flags |= F_DISP8;
|
|
hs->disp.disp8 = *p;
|
|
break;
|
|
case 2:
|
|
hs->flags |= F_DISP16;
|
|
hs->disp.disp16 = *(uint16_t *) p;
|
|
break;
|
|
case 4:
|
|
hs->flags |= F_DISP32;
|
|
hs->disp.disp32 = *(uint32_t *) p;
|
|
break;
|
|
}
|
|
p += disp_size;
|
|
} else if (pref & PRE_LOCK)
|
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
|
|
if (cflags & C_IMM_P66) {
|
|
if (cflags & C_REL32) {
|
|
if (pref & PRE_66) {
|
|
hs->flags |= F_IMM16 | F_RELATIVE;
|
|
hs->imm.imm16 = *(uint16_t *) p;
|
|
p += 2;
|
|
goto disasm_done;
|
|
}
|
|
goto rel32_ok;
|
|
}
|
|
if (pref & PRE_66) {
|
|
hs->flags |= F_IMM16;
|
|
hs->imm.imm16 = *(uint16_t *) p;
|
|
p += 2;
|
|
} else {
|
|
hs->flags |= F_IMM32;
|
|
hs->imm.imm32 = *(uint32_t *) p;
|
|
p += 4;
|
|
}
|
|
}
|
|
|
|
if (cflags & C_IMM16) {
|
|
if (hs->flags & F_IMM32) {
|
|
hs->flags |= F_IMM16;
|
|
hs->disp.disp16 = *(uint16_t *) p;
|
|
} else if (hs->flags & F_IMM16) {
|
|
hs->flags |= F_2IMM16;
|
|
hs->disp.disp16 = *(uint16_t *) p;
|
|
} else {
|
|
hs->flags |= F_IMM16;
|
|
hs->imm.imm16 = *(uint16_t *) p;
|
|
}
|
|
p += 2;
|
|
}
|
|
if (cflags & C_IMM8) {
|
|
hs->flags |= F_IMM8;
|
|
hs->imm.imm8 = *p++;
|
|
}
|
|
|
|
if (cflags & C_REL32) {
|
|
rel32_ok:
|
|
hs->flags |= F_IMM32 | F_RELATIVE;
|
|
hs->imm.imm32 = *(uint32_t *) p;
|
|
p += 4;
|
|
} else if (cflags & C_REL8) {
|
|
hs->flags |= F_IMM8 | F_RELATIVE;
|
|
hs->imm.imm8 = *p++;
|
|
}
|
|
|
|
disasm_done:
|
|
|
|
if ((hs->len = (uint8_t) (p - (uint8_t *) code)) > 15) {
|
|
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
|
hs->len = 15;
|
|
}
|
|
|
|
return (unsigned int) hs->len;
|
|
}
|