diff options
Diffstat (limited to 'src/arch/x86/operand.c')
-rw-r--r-- | src/arch/x86/operand.c | 343 |
1 files changed, 342 insertions, 1 deletions
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. * |