Much work on better support for disassembling the Mod R/M byte

This commit is contained in:
Pierre Pronchery 2011-04-25 06:16:07 +00:00
parent 5361aa325a
commit 9176288890
3 changed files with 108 additions and 31 deletions

View File

@ -38,6 +38,8 @@ static int _decode_immediate(ArchPlugin * plugin, ArchInstructionCall * call,
size_t i);
static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call,
size_t * i);
static int _decode_modrm_do(ArchPlugin * plugin, ArchInstructionCall * call,
size_t i, uint8_t u8);
static int _decode_operand(ArchPlugin * plugin, ArchInstructionCall * call,
size_t * i);
static int _decode_register(ArchPlugin * plugin, ArchInstructionCall * call,
@ -176,29 +178,84 @@ static int _decode_immediate(ArchPlugin * plugin, ArchInstructionCall * call,
static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call,
size_t * i)
{
int ret = -1;
ArchPluginHelper * helper = plugin->helper;
ArchOperand * ao = &call->operands[*i];
ArchOperand * ao1 = &call->operands[*i];
ArchOperand * ao2 = NULL;
uint8_t u8;
uint32_t uW; /* XXX should be uintW_t */
ArchRegister * ar;
uint8_t mod;
uint8_t reg;
uint8_t rm;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", &%lu)\n", __func__, call->name, *i);
#endif
if(*i + 1 < 3 && (AO_GET_TYPE(call->operands[*i + 1].type)
== AOT_REGISTER
|| AO_GET_TYPE(call->operands[*i + 1].type)
== AOT_DREGISTER))
ao2 = &call->operands[*i + 1];
if(helper->read(helper->arch, &u8, sizeof(u8)) != sizeof(u8))
return -1;
if((u8 & 0xc0) == 0xc0)
mod = (u8 >> 6) & 0x3;
reg = (u8 >> 3) & 0x7;
rm = u8 & 0x7;
#ifdef DEBUG
fprintf(stderr, "DEBUG: u8=0x%02x (%u %u %u)\n", u8, mod, reg, rm);
#endif
if(AO_GET_TYPE(ao1->type) == AOT_DREGISTER && ao2 != NULL
&& AO_GET_TYPE(ao2->type) & AOT_REGISTER
&& AO_GET_FLAGS(ao2->type) & AOF_I386_MODRM)
{
if((ar = helper->get_register_by_id_size(helper->arch,
(u8 & 0x38) >> 3, W)) == NULL)
ret = _decode_modrm_do(plugin, call, (*i)++,
(mod << 6) | (rm << 3));
ret |= _decode_modrm_do(plugin, call, *i,
(0x3 << 6) | (reg << 3));
}
else if(AO_GET_TYPE(ao1->type) == AOT_REGISTER && ao2 != NULL
&& AO_GET_FLAGS(ao2->type) & AOF_I386_MODRM)
{
ret = _decode_modrm_do(plugin, call, (*i)++,
(0x3 << 6) | (reg << 3));
ret |= _decode_modrm_do(plugin, call, *i,
(mod << 6) | (rm << 3));
}
else
/* FIXME really implement */
ret = _decode_modrm_do(plugin, call, *i, u8);
return ret;
}
static int _decode_modrm_do(ArchPlugin * plugin, ArchInstructionCall * call,
size_t i, uint8_t u8)
{
ArchPluginHelper * helper = plugin->helper;
ArchOperand * ao = &call->operands[i];
uint8_t mod;
uint8_t reg;
uint8_t rm;
ArchRegister * ar;
uintW_t uW;
mod = (u8 >> 6) & 0x3;
reg = (u8 >> 3) & 0x7;
rm = u8 & 0x7;
#ifdef DEBUG
fprintf(stderr, "DEBUG: u8=0x%02x (%u %u %u) size=%u\n",
u8, mod, reg, rm, AO_GET_SIZE(ao->type));
#endif
if(mod == 3)
{
if((ar = helper->get_register_by_id_size(helper->arch, reg,
AO_GET_SIZE(ao->type))) == NULL)
return -1;
ao->type = AO_REGISTER(0, 32, 0);
ao->value._register.name = ar->name;
}
else if((u8 & 0xc0) == 0x80)
else if(mod == 2)
{
if((ar = helper->get_register_by_id_size(helper->arch,
(u8 & 0x38) >> 3, W)) == NULL)
if((ar = helper->get_register_by_id_size(helper->arch, reg, W))
== NULL)
return -1;
if(helper->read(helper->arch, &uW, sizeof(uW)) != sizeof(uW))
return -1;
@ -206,28 +263,34 @@ static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call,
ao->value.dregister.name = ar->name;
ao->value.dregister.offset = _htol32(uW); /* XXX _htolW() */
}
else if((u8 & 0xc0) == 0x40)
else if(mod == 1)
{
if((ar = helper->get_register_by_id_size(helper->arch,
(u8 & 0x38) >> 3, W)) == NULL)
if((ar = helper->get_register_by_id_size(helper->arch, reg, W))
== NULL)
return -1;
ao->type = AO_DREGISTER(0, 8, W, 0);
ao->value.dregister.name = ar->name;
}
else if((u8 & 0xc0) == 0x00)
else /* mod == 0 */
{
if((ar = helper->get_register_by_id_size(helper->arch,
(u8 & 0x38) >> 3, W)) == NULL)
if(rm == 5) /* dispW */
{
/* FIXME SIB byte? */
if(helper->read(helper->arch, &uW, sizeof(uW))
!= sizeof(uW))
return -1;
/* FIXME endian */
ao->type = AO_IMMEDIATE(0, 0, W);
ao->value.immediate.value = uW;
}
else if((ar = helper->get_register_by_id_size(helper->arch, reg,
W)) != NULL)
{
ao->type = AO_DREGISTER(0, 0, W, 0);
ao->value.dregister.name = ar->name;
}
else
return -1;
ao->type = AO_DREGISTER(0, 0, W, 0);
ao->value.dregister.name = ar->name;
}
if(AO_GET_TYPE(call->operands[*i + 1].type) != AOT_NONE
&& AO_GET_FLAGS(call->operands[*i + 1].type)
& AOF_I386_MODRM)
{
/* FIXME really implement */
(*i)++;
}
return 0;
}
@ -235,17 +298,21 @@ static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call,
static int _decode_operand(ArchPlugin * plugin, ArchInstructionCall * call,
size_t * i)
{
if(AO_GET_FLAGS(call->operands[*i].type) & AOF_I386_MODRM)
return _decode_modrm(plugin, call, i);
switch(AO_GET_TYPE(call->operands[*i].type))
ArchOperand * ao = &call->operands[*i];
switch(AO_GET_TYPE(ao->type))
{
case AOT_CONSTANT:
return _decode_constant(plugin, call, *i);
case AOT_DREGISTER:
if(AO_GET_FLAGS(ao->type) & AOF_I386_MODRM)
return _decode_modrm(plugin, call, i);
return _decode_dregister(plugin, call, *i);
case AOT_IMMEDIATE:
return _decode_immediate(plugin, call, *i);
case AOT_REGISTER:
if(AO_GET_FLAGS(ao->type) & AOF_I386_MODRM)
return _decode_modrm(plugin, call, i);
return _decode_register(plugin, call, *i);
}
return -error_set_code(1, "%s", strerror(ENOSYS));

View File

@ -18,6 +18,7 @@
/* platform-specific */
#if defined(ARCH_i386_real) /* i386 in real mode */
# define W 16
# define uintW_t uint16_t
# define REG_AX_id REG_ax_id
# define REG_CX_id REG_cx_id
# define REG_DX_id REG_dx_id
@ -28,6 +29,7 @@
# define REG_DI_id REG_di_id
#else /* i386 and compatible in 32-bit protected mode */
# define W 32
# define uintW_t uint32_t
# define REG_AX_id REG_eax_id
# define REG_CX_id REG_ecx_id
# define REG_DX_id REG_edx_id
@ -674,6 +676,8 @@
{ "iret", 0xcf, OP1F, AOT_NONE, AOT_NONE, AOT_NONE },
/* IRETD 0xcf 1 */
{ "iretd", 0xcf, OP1F, AOT_NONE, AOT_NONE, AOT_NONE },
/* JAE 0x73 1 rel8 */
{ "jae", 0x73, OP1F, OP_S8, AOT_NONE, AOT_NONE },
/* JMP 0xeb 1 imm8 */
{ "jmp", 0xeb, OP1F, OP_S8, AOT_NONE, AOT_NONE },
/* JMP 0xe9 1 immW */
@ -683,6 +687,10 @@
{ "jmp", 0xff, OP1F, OP_RMW_D8+4,AOT_NONE, AOT_NONE },
{ "jmp", 0xff, OP1F, OP_RMW_DW+4,AOT_NONE, AOT_NONE },
{ "jmp", 0xff, OP1F, OP_RMW_RW+4,AOT_NONE, AOT_NONE },
/* JNE 0x75 1 rel8 */
{ "jne", 0x75, OP1F, OP_S8, AOT_NONE, AOT_NONE },
/* JO 0x70 1 rel8 */
{ "jo", 0x70, OP1F, OP_S8, AOT_NONE, AOT_NONE },
/* LAHF 0x9f 1 */
{ "lahf", 0x9f, OP1F, AOT_NONE, AOT_NONE, AOT_NONE },
/* LEAVE 0xc9 1 */
@ -728,6 +736,8 @@
{ "mov", 0x8b, OP1F, OP_RW_R, OP_RMW_D8, AOT_NONE },
{ "mov", 0x8b, OP1F, OP_RW_R, OP_RMW_DW, AOT_NONE },
{ "mov", 0x8b, OP1F, OP_RW_R, OP_RMW_RW, AOT_NONE },
/* MOV 0xa3 1 AX moffsW */
{ "mov", 0xa3, OP1F, OP_AX, OP_SW, AOT_NONE },
/* MOV 0xb0 +rb 1 r8 imm8 */
{ "mov", 0xb0, OP1F, OP_al, OP_S8, AOT_NONE },
{ "mov", 0xb1, OP1F, OP_cl, OP_S8, AOT_NONE },

View File

@ -26,10 +26,10 @@ REG(eax,32, 0x00)
REG(ecx,32, 0x01)
REG(edx,32, 0x02)
REG(ebx,32, 0x03)
REG(esi,32, 0x04)
REG(edi,32, 0x05)
REG(esp,32, 0x06)
REG(ebp,32, 0x07)
REG(esp,32, 0x04)
REG(ebp,32, 0x05)
REG(esi,32, 0x06)
REG(edi,32, 0x07)
#endif /* !ARCH_i386_real */
REG(cr0,32, 0x00)
REG(cr1,32, 0x01)