diff options
-rw-r--r-- | ChangeLog | 23 | ||||
-rw-r--r-- | src/arch/x86/Makefile.am | 1 | ||||
-rw-r--r-- | src/arch/x86/instruction.h | 6 | ||||
-rw-r--r-- | src/arch/x86/op_mov.c | 22 | ||||
-rw-r--r-- | src/arch/x86/opcodes.h | 12 | ||||
-rw-r--r-- | src/arch/x86/operand.c | 343 | ||||
-rw-r--r-- | src/arch/x86/operand.h | 16 | ||||
-rw-r--r-- | src/arch/x86/processor.c | 11 |
8 files changed, 418 insertions, 16 deletions
@@ -1,4 +1,25 @@ -2008-09-06 Cyrille Bagard <nocbos@gmail.com> +2008-09-09 Cyrille Bagard <nocbos@gmail.com> + + * src/arch/x86/instruction.h: + Handle four kinds of the 'test' opcode. + + * src/arch/x86/Makefile.am: + Add op_test.c to libarchx86_a_SOURCES. + + * src/arch/x86/opcodes.h: + Register the new decoding functions. + + * src/arch/x86/operand.c: + * src/arch/x86/operand.h: + Handle the r/m information in a clever way. + + * src/arch/x86/op_mov.c: + Reorganize the code ; this must be improved. + + * src/arch/x86/processor.c: + Register the new decoding functions. + +2008-09-07 Cyrille Bagard <nocbos@gmail.com> * src/arch/x86/op_lea.c: * src/arch/x86/op_mov.c: diff --git a/src/arch/x86/Makefile.am b/src/arch/x86/Makefile.am index 238cf61..b074f69 100644 --- a/src/arch/x86/Makefile.am +++ b/src/arch/x86/Makefile.am @@ -21,6 +21,7 @@ libarchx86_a_SOURCES = \ op_ret.c \ op_sbb.c \ op_sub.c \ + op_test.c \ op_xor.c \ opcodes.h \ operand.h operand.c \ diff --git a/src/arch/x86/instruction.h b/src/arch/x86/instruction.h index 1a9b6d4..38315d9 100644 --- a/src/arch/x86/instruction.h +++ b/src/arch/x86/instruction.h @@ -88,12 +88,18 @@ typedef enum _X86Opcodes X86_OP_SUB8_REG1632, /* sub ([0x66] 0x83) */ X86_OP_XOR8_REG1632, /* xor ([0x66] 0x83) */ + X86_OP_TEST_RM8, /* test ([0x66] 0x84) */ + X86_OP_TEST_RM1632, /* test ([0x66] 0x85) */ + X86_OP_MOV_FROM_CONTENT1632, /* mov ([0x66] 0x8b) */ X86_OP_LEA, /* lea ([0x66] 0x8d) */ /* 66 ? */ X86_OP_NOP, /* nop (0x90) */ + X86_OP_TEST_AL, /* test ([0x66] 0xa8) */ + X86_OP_TEST_E_AX, /* test ([0x66] 0xa9) */ + X86_OP_MOV_E_AX, /* mov ([0x66] 0xb8) */ X86_OP_MOV_E_CX, /* mov ([0x66] 0xb9) */ X86_OP_MOV_E_DX, /* mov ([0x66] 0xba) */ diff --git a/src/arch/x86/op_mov.c b/src/arch/x86/op_mov.c index db731bb..d0a1bfc 100644 --- a/src/arch/x86/op_mov.c +++ b/src/arch/x86/op_mov.c @@ -65,27 +65,27 @@ asm_x86_instr *read_instr_mov_with_reg1632(const uint8_t *data, off_t *pos, off_ ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; - /* TODO ! */ - if ((data[*pos] & 0xc0) != 0xc0) - return NULL; - - reg1 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, true); - if (reg1 == NULL) + reg2 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, false); + if (reg2 == NULL) { free(result); return NULL; } - reg2 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, false); - if (reg2 == NULL) + if ((data[*pos] & 0xc0) == 0xc0) + { + reg1 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, true); + (*pos)++; + } + else reg1 = x86_create_content1632_operand(data, pos, len, oprsize == AOS_32_BITS, true); + + if (reg1 == NULL) { free(result); - free(reg1); + free(reg2); return NULL; } - (*pos)++; - ASM_INSTRUCTION(result)->operands = (asm_operand **)calloc(2, sizeof(asm_operand *)); ASM_INSTRUCTION(result)->operands_count = 2; diff --git a/src/arch/x86/opcodes.h b/src/arch/x86/opcodes.h index 1d3611f..64614dc 100644 --- a/src/arch/x86/opcodes.h +++ b/src/arch/x86/opcodes.h @@ -103,6 +103,18 @@ asm_x86_instr *read_instr_sbb8_with_reg1632(const uint8_t *, off_t *, off_t, uin /* Décode une instruction de type 'sub'. */ asm_x86_instr *read_instr_sub8_with_reg1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); +/* Décode une instruction de type 'test al, ...' (8 bits). */ +asm_x86_instr *read_instr_test_al(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + +/* Décode une instruction de type 'test [e]ax, ...' (16/32b). */ +asm_x86_instr *read_instr_test_e_ax(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + +/* Décode une instruction de type 'test' (8 bits). */ +asm_x86_instr *read_instr_test_rm8(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + +/* Décode une instruction de type 'test' (16 ou 32 bits). */ +asm_x86_instr *read_instr_test_rm1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); + /* Décode une instruction de type 'xor' (16 ou 32 bits). */ asm_x86_instr *read_instr_xor_with_reg1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *); diff --git a/src/arch/x86/operand.c b/src/arch/x86/operand.c index ada66f0..a232211 100644 --- a/src/arch/x86/operand.c +++ b/src/arch/x86/operand.c @@ -178,7 +178,15 @@ bool get_x86_register(x86_register *reg, AsmOperandSize size, uint8_t value) switch (size) { case AOS_8_BITS: - return false; + switch (value) + { + case 0 ... 7: + reg->reg8 = (X868bRegister)value; + break; + default: + return false; + break; + } break; case AOS_16_BITS: @@ -418,6 +426,339 @@ asm_x86_operand *x86_create_content1632_operand(const uint8_t *data, off_t *pos, } + + + +/****************************************************************************** +* * +* Paramètres : data = donnée à analyser. * +* first = indique la partie du ModR/M à traiter. * +* * +* Description : Crée une opérande renvoyant vers un registre 8 bits. * +* * +* Retour : Opérande mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_operand *x86_create_r8_operand(uint8_t data, bool first) +{ + asm_x86_operand *result; /* Registre à retourner */ + uint8_t reg; /* Transcription du registre */ + + if (first) reg = data & 0x07; + else reg = (data & 0x38) >> 3; + + result = create_new_x86_operand(); + + ASM_OPERAND(result)->type = AOT_REG; + ASM_OPERAND(result)->size = AOS_8_BITS; + + if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, reg)) + { + free(result); + return NULL; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* first = indique la partie du ModR/M à traiter. * +* * +* Description : Crée une opérande à partir d'un registre/une mémoire 8 bits. * +* * +* Retour : Opérande mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_operand *x86_create_rm8_operand(const uint8_t *data, off_t *pos, off_t len, bool first) +{ + asm_x86_operand *result; /* Registre à retourner */ + uint8_t mod; /* Modificateur présent */ + + /* Registre simple... */ + + result = x86_create_r8_operand(data[*pos], first); + if (result == NULL) return NULL; + + mod = (data[*pos] & 0xc0); + + (*pos)++; + + if (mod == 0xc0) return result; + + result->content = true; + + /* Vieille astuce de l'emplacement mémoire fixe ? */ + if (result->rindex.reg8 == X86_REG8_CH && mod == 0x00) + { + free(result); + + result = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result), AOS_8_BITS, data, pos, len)) + { + free(result); + return NULL; + } + + return result; + + } + + /* A la recherche d'un SIB */ + if (result->rindex.reg8 == X86_REG8_AH) + { + if (!get_x86_register(&result->rbase, ASM_OPERAND(result)->size, data[*pos] & 0x07)) + { + free(result); + return NULL; + } + + if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, (data[*pos] & 0x38) >> 3)) + { + free(result); + return NULL; + } + + result->scale = ((data[*pos] & 0xc0) >> 6); + + if (result->rindex.reg8 == X86_REG8_AH) + { + result->rindex.reg8 = result->rbase.reg8; + result->rbase.reg8 = X86_REG8_NONE; + } + + (*pos)++; + + } + + /* Décallage supplémentaire ? */ + switch (mod) + { + case 0x00: + if (result->rbase.reg8 == X86_REG8_CH) + { + result->rbase.reg8 = X86_REG8_NONE; + + result->displacement = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result->displacement), ASM_OPERAND(result)->size, data, pos, len)) + { + free(result->displacement); + free(result); + return NULL; + } + + } + break; + + case 0x40: + result->displacement = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len)) + { + free(result->displacement); + free(result); + return NULL; + } + break; + + case 0x80: + result->displacement = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len)) + { + free(result->displacement); + free(result); + return NULL; + } + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : data = donnée à analyser. * +* is_reg32 = indique si le registre est un registre 32 bits. * +* first = indique la partie du ModR/M à traiter. * +* * +* Description : Crée une opérande renvoyant vers un registre 16 ou 32 bits. * +* * +* Retour : Opérande mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_operand *x86_create_r1632_operand(uint8_t data, bool is_reg32, bool first) +{ + asm_x86_operand *result; /* Registre à retourner */ + uint8_t reg; /* Transcription du registre */ + + if (first) reg = data & 0x07; + else reg = (data & 0x38) >> 3; + + result = create_new_x86_operand(); + + ASM_OPERAND(result)->type = AOT_REG; + ASM_OPERAND(result)->size = (is_reg32 ? AOS_32_BITS : AOS_16_BITS); + + if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, reg)) + { + free(result); + return NULL; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* is_reg32 = indique si le registre est un registre 32 bits. * +* first = indique la partie du ModR/M à traiter. * +* * +* Description : Crée une opérande à partir d'un registre/une mémoire 16/32b. * +* * +* Retour : Opérande mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_operand *x86_create_rm1632_operand(const uint8_t *data, off_t *pos, off_t len, bool is_reg32, bool first) +{ + asm_x86_operand *result; /* Registre à retourner */ + uint8_t mod; /* Modificateur présent */ + + /* Registre simple... */ + + result = x86_create_r1632_operand(data[*pos], is_reg32, first); + if (result == NULL) return NULL; + + mod = (data[*pos] & 0xc0); + + (*pos)++; + + if (mod == 0xc0) return result; + + result->content = true; + + /* Vieille astuce de l'emplacement mémoire fixe ? */ + if (result->rindex.reg32 == X86_REG32_EBP && mod == 0x00) + { + free(result); + + result = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result), AOS_32_BITS/* FIXME ? */, data, pos, len)) + { + free(result); + return NULL; + } + + return result; + + } + + /* A la recherche d'un SIB */ + if (result->rindex.reg32 == X86_REG32_ESP) + { + if (!get_x86_register(&result->rbase, ASM_OPERAND(result)->size, data[*pos] & 0x07)) + { + free(result); + return NULL; + } + + if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, (data[*pos] & 0x38) >> 3)) + { + free(result); + return NULL; + } + + result->scale = ((data[*pos] & 0xc0) >> 6); + + if (result->rindex.reg32 == X86_REG32_ESP) + { + result->rindex.reg32 = result->rbase.reg32; + result->rbase.reg32 = X86_REG32_NONE; + } + + (*pos)++; + + } + + /* Décallage supplémentaire ? */ + switch (mod) + { + case 0x00: + if (result->rbase.reg32 == X86_REG32_EBP) + { + result->rbase.reg32 = X86_REG32_NONE; + + result->displacement = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result->displacement), ASM_OPERAND(result)->size, data, pos, len)) + { + free(result->displacement); + free(result); + return NULL; + } + + } + break; + + case 0x40: + result->displacement = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len)) + { + free(result->displacement); + free(result); + return NULL; + } + break; + + case 0x80: + result->displacement = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_32_BITS, data, pos, len)) + { + free(result->displacement); + free(result); + return NULL; + } + break; + + } + + return result; + +} + + + + + + + + + + + + /****************************************************************************** * * * Paramètres : reg = registre à imprimer. * diff --git a/src/arch/x86/operand.h b/src/arch/x86/operand.h index fbaba57..c330b8e 100644 --- a/src/arch/x86/operand.h +++ b/src/arch/x86/operand.h @@ -51,6 +51,22 @@ asm_x86_operand *x86_create_reg1632_operand_from_modrm(uint8_t, bool, bool); /* Crée une opérande renvoyant vers un contenu 16 ou 32 bits. */ asm_x86_operand *x86_create_content1632_operand(const uint8_t *, off_t *, off_t, bool, bool); + + +/* Crée une opérande renvoyant vers un registre 8 bits. */ +asm_x86_operand *x86_create_r8_operand(uint8_t, bool); + +/* Crée une opérande à partir d'un registre/une mémoire 8 bits. */ +asm_x86_operand *x86_create_rm8_operand(const uint8_t *, off_t *, off_t, bool); + +/* Crée une opérande renvoyant vers un registre 16 ou 32 bits. */ +asm_x86_operand *x86_create_r1632_operand(uint8_t, bool, bool); + +/* Crée une opérande à partir d'un registre/une mémoire 16/32b. */ +asm_x86_operand *x86_create_rm1632_operand(const uint8_t *, off_t *, off_t, bool, bool); + + + /* Traduit une opérande de registre en texte. */ void x86_print_reg_operand(const asm_x86_operand *, char *, size_t, AsmSyntax); diff --git a/src/arch/x86/processor.c b/src/arch/x86/processor.c index 118dbd6..3ca14b9 100644 --- a/src/arch/x86/processor.c +++ b/src/arch/x86/processor.c @@ -234,9 +234,6 @@ void x86_register_instructions(asm_x86_processor *proc) register_opcode(proc->opcodes[X86_OP_PUSH_IMM1632], 0x66, 0x68, "push", read_instr_push_imm1632); - - register_opcode(proc->opcodes[X86_OP_MOV_REG1632], 0x66, 0x89, "mov", read_instr_mov_with_reg1632); - register_opcode_with_ext(proc->opcodes[X86_OP_ADD8_REG1632], 0x66, 0x83, 0, "add", read_instr_add8_with_reg1632); register_opcode_with_ext(proc->opcodes[X86_OP_OR8_REG1632], 0x66, 0x83, 1, "or", read_instr_or8_with_reg1632); register_opcode_with_ext(proc->opcodes[X86_OP_ADC8_REG1632], 0x66, 0x83, 2, "adc", read_instr_adc8_with_reg1632); @@ -245,12 +242,20 @@ void x86_register_instructions(asm_x86_processor *proc) register_opcode_with_ext(proc->opcodes[X86_OP_SUB8_REG1632], 0x66, 0x83, 5, "sub", read_instr_sub8_with_reg1632); register_opcode_with_ext(proc->opcodes[X86_OP_XOR8_REG1632], 0x66, 0x83, 6, "xor", read_instr_xor8_with_reg1632); + register_opcode(proc->opcodes[X86_OP_TEST_RM8], 0x00, 0x84, "test", read_instr_test_rm8); + register_opcode(proc->opcodes[X86_OP_TEST_RM1632], 0x66, 0x85, "test", read_instr_test_rm1632); + + register_opcode(proc->opcodes[X86_OP_MOV_REG1632], 0x66, 0x89, "mov", read_instr_mov_with_reg1632); + register_opcode(proc->opcodes[X86_OP_MOV_FROM_CONTENT1632], 0x66, 0x8b, "mov", read_instr_mov_from_content_1632); register_opcode(proc->opcodes[X86_OP_LEA], 0x66, 0x8d, "lea", read_instr_lea); register_opcode(proc->opcodes[X86_OP_NOP], 0x00, 0x90, "nop", read_instr_nop); + register_opcode(proc->opcodes[X86_OP_TEST_AL], 0x00, 0xa8, "test", read_instr_test_al); + register_opcode(proc->opcodes[X86_OP_TEST_E_AX], 0x66, 0xa9, "test", read_instr_test_e_ax); + register_opcode(proc->opcodes[X86_OP_MOV_E_AX], 0x66, 0xb8, "mov", read_instr_mov_to_1632); register_opcode(proc->opcodes[X86_OP_MOV_E_CX], 0x66, 0xb9, "mov", read_instr_mov_to_1632); register_opcode(proc->opcodes[X86_OP_MOV_E_DX], 0x66, 0xba, "mov", read_instr_mov_to_1632); |