diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2008-07-27 19:38:15 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2008-07-27 19:38:15 (GMT) |
commit | 1bf9c5ebe8bb3326e10491974cd43b221e2a56a1 (patch) | |
tree | 01a745a798661478eb7a6e02c0a0831bb1b4950c /src/arch | |
parent | dbf4d1f93e54251568854bff0ebc9c84f60857f6 (diff) |
Supported new x86 opcodes (nop and mov).
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@7 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/instruction-int.h | 6 | ||||
-rw-r--r-- | src/arch/instruction.c | 6 | ||||
-rw-r--r-- | src/arch/instruction.h | 3 | ||||
-rw-r--r-- | src/arch/operand-int.h | 18 | ||||
-rw-r--r-- | src/arch/operand.c | 164 | ||||
-rw-r--r-- | src/arch/operand.h | 29 | ||||
-rw-r--r-- | src/arch/processor-int.h | 5 | ||||
-rw-r--r-- | src/arch/processor.c | 6 | ||||
-rw-r--r-- | src/arch/processor.h | 5 | ||||
-rw-r--r-- | src/arch/x86/Makefile.am | 3 | ||||
-rw-r--r-- | src/arch/x86/instruction.h | 36 | ||||
-rw-r--r-- | src/arch/x86/op_int.c | 22 | ||||
-rw-r--r-- | src/arch/x86/op_mov.c | 89 | ||||
-rw-r--r-- | src/arch/x86/op_nop.c | 56 | ||||
-rw-r--r-- | src/arch/x86/opcodes.h | 10 | ||||
-rw-r--r-- | src/arch/x86/operand.c | 402 | ||||
-rw-r--r-- | src/arch/x86/operand.h | 53 | ||||
-rw-r--r-- | src/arch/x86/processor.c | 105 |
18 files changed, 966 insertions, 52 deletions
diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h index 11180dc..72c7914 100644 --- a/src/arch/instruction-int.h +++ b/src/arch/instruction-int.h @@ -43,10 +43,10 @@ /* Définition générique d'une instruction */ struct _asm_instr { - char opcode; + uint8_t opcode; - asm_operand operands[MAX_OPERANDS]; - unsigned int operands_count; /* Nbre. d'opérandes utilisées */ + asm_operand **operands; /* Liste des opérandes */ + size_t operands_count; /* Nbre. d'opérandes utilisées */ }; diff --git a/src/arch/instruction.c b/src/arch/instruction.c index 1af3b97..e199dc5 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -45,7 +45,7 @@ * * ******************************************************************************/ -asm_instr *create_db_instruction(const char *data, off_t *pos, off_t len) +asm_instr *create_db_instruction(const uint8_t *data, off_t *pos, off_t len) { asm_instr *result; /* Représentation à renvoyer */ @@ -54,7 +54,9 @@ asm_instr *create_db_instruction(const char *data, off_t *pos, off_t len) result->opcode = DB_OPCODE; /* TODO: check result */ - fill_db_operand(&result->operands[0], data[(*pos)++]); + result->operands = (asm_operand **)calloc(1, sizeof(asm_operand *)); + result->operands[0] = (asm_operand *)calloc(1, sizeof(asm_operand)); + fill_db_operand(result->operands[0], data[(*pos)++]); result->operands_count = 1; diff --git a/src/arch/instruction.h b/src/arch/instruction.h index 3be2bf7..19cc6ab 100644 --- a/src/arch/instruction.h +++ b/src/arch/instruction.h @@ -25,6 +25,7 @@ #define _ARCH_INSTRUCTION_H +#include <stdint.h> #include <sys/types.h> @@ -35,7 +36,7 @@ typedef struct _asm_instr asm_instr; /* Crée une instruction de type 'db' à partir de données. */ -asm_instr *create_db_instruction(const char *, off_t *, off_t); +asm_instr *create_db_instruction(const uint8_t *, off_t *, off_t); diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h index f09d9a9..49470a4 100644 --- a/src/arch/operand-int.h +++ b/src/arch/operand-int.h @@ -29,22 +29,36 @@ +/* Types d'opérandes rencontrables */ +typedef enum _AsmOperandType +{ + AOT_NONE, /* Type d'opérande inconnu ! */ + AOT_IMM, /* Valeur immédiate */ + AOT_REG, /* Registre quelconque */ + AOT_MEM /* Accès à la mémoire */ + +} AsmOperandType; /* Définition générique d'une opérande */ struct _asm_operand { - + AsmOperandType type; /* Type d'opérande */ + AsmOperandSize size; /* Taille de l'opérande */ union { uint8_t val8; /* Valeur sur 8 bits */ + uint16_t val16; /* Valeur sur 16 bits */ + uint32_t val32; /* Valeur sur 32 bits */ + uint64_t val64; /* Valeur sur 64 bits */ } value; +}; -}; +#define ASM_OPERAND(o) ((asm_operand *)o) diff --git a/src/arch/operand.c b/src/arch/operand.c index 98460c9..cd7c2b4 100644 --- a/src/arch/operand.c +++ b/src/arch/operand.c @@ -24,10 +24,10 @@ #include "operand.h" -#include "operand-int.h" - +#include <stdio.h> +#include "operand-int.h" @@ -46,6 +46,9 @@ bool fill_db_operand(asm_operand *operand, uint8_t value) { + operand->type = AOT_NONE; + operand->size = AOS_8_BITS; + operand->value.val8 = value; return true; @@ -53,3 +56,160 @@ bool fill_db_operand(asm_operand *operand, uint8_t value) } +/****************************************************************************** +* * +* Paramètres : operand = instruction à traiter. * +* buffer = tampon de sortie mis à disposition. [OUT] * +* len = taille de ce tampon. * +* syntax = type de représentation demandée. * +* * +* Description : Traduit une opérande de type 'db' en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void print_db_operand(const asm_operand *operand, char *buffer, size_t len, AsmSyntax syntax) +{ + switch (syntax) + { + case ASX_INTEL: + snprintf(buffer, len, "0x%02hhx", operand->value.val8); + break; + + case ASX_ATT: + snprintf(buffer, len, "$0x%02hhx", operand->value.val8); + break; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : operand = structure dont le contenu est à définir. * +* size = taille de l'opérande souhaitée. * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* * +* Description : Crée une opérande contenant une valeur sur x bits. * +* * +* Retour : true si l'opération s'est effectuée avec succès, false sinon.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool fill_imm_operand(asm_operand *operand, AsmOperandSize size, const uint8_t *data, off_t *pos, off_t len) +{ + /* Vérifications sanitaires */ + switch (size) + { + case AOS_8_BITS: + if ((len - *pos) < 1) return false; + break; + case AOS_16_BITS: + if ((len - *pos) < 2) return false; + break; + case AOS_32_BITS: + if ((len - *pos) < 4) return false; + break; + case AOS_64_BITS: + if ((len - *pos) < 8) return false; + break; + } + + operand->type = AOT_IMM; + operand->size = size; + + switch (size) + { + case AOS_8_BITS: + operand->value.val8 = data[*pos]; + *pos += 1; + break; + case AOS_16_BITS: + operand->value.val16 = data[*pos] || (data[*pos + 1] << 8); + *pos += 2; + break; + case AOS_32_BITS: + operand->value.val32 = data[*pos] || (data[*pos + 1] << 8) || (data[*pos + 2] << 16); + *pos += 4; + break; + case AOS_64_BITS: + /* + operand->value.val64 = data[*pos] || (data[*pos + 1] << 8) || (data[*pos + 2] << 16) + || (data[*pos + 3] << 24) || (data[*pos + 4] << 32) || (data[*pos + 5] << 40) + || (data[*pos + 6] << 48) || (data[*pos + 7] << 56); + */ + *pos += 8; + break; + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = instruction à traiter. * +* buffer = tampon de sortie mis à disposition. [OUT] * +* len = taille de ce tampon. * +* syntax = type de représentation demandée. * +* * +* Description : Traduit une opérande de valeur immédiate en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void print_imm_operand(const asm_operand *operand, char *buffer, size_t len, AsmSyntax syntax) +{ + switch (syntax) + { + case ASX_INTEL: + switch (operand->size) + { + case AOS_8_BITS: + snprintf(buffer, len, "0x%hhx", operand->value.val8); + break; + case AOS_16_BITS: + snprintf(buffer, len, "0x%hx", operand->value.val16); + break; + case AOS_32_BITS: + snprintf(buffer, len, "0x%x", operand->value.val32); + break; + case AOS_64_BITS: + snprintf(buffer, len, "0x%llx", operand->value.val64); + break; + } + break; + + case ASX_ATT: + switch (operand->size) + { + case AOS_8_BITS: + snprintf(buffer, len, "$0x%hhx", operand->value.val8); + break; + case AOS_16_BITS: + snprintf(buffer, len, "$0x%hx", operand->value.val16); + break; + case AOS_32_BITS: + snprintf(buffer, len, "$0x%x", operand->value.val32); + break; + case AOS_64_BITS: + snprintf(buffer, len, "$0x%llx", operand->value.val64); + break; + } + break; + + } + +} diff --git a/src/arch/operand.h b/src/arch/operand.h index 81c9a53..1b5b33f 100644 --- a/src/arch/operand.h +++ b/src/arch/operand.h @@ -27,17 +27,46 @@ #include <stdbool.h> #include <stdint.h> +#include <sys/types.h> +/* Taille des données intégrées */ +typedef enum _AsmOperandSize +{ + AOS_8_BITS, /* Opérande sur 8 bits */ + AOS_16_BITS, /* Opérande sur 16 bits */ + AOS_32_BITS, /* Opérande sur 32 bits */ + AOS_64_BITS /* Opérande sur 64 bits */ + +} AsmOperandSize; + + /* Définition générique d'une opérande */ typedef struct _asm_operand asm_operand; +/* Différentes formes de représentation humaine */ +typedef enum _AsmSyntax +{ + ASX_INTEL, /* Syntaxe Intel */ + ASX_ATT /* Syntaxte AT&T */ + +} AsmSyntax; + + /* Crée une opérande pour l'instruction 'db'. */ bool fill_db_operand(asm_operand *, uint8_t); +/* Traduit une opérande de type 'db' en texte. */ +void print_db_operand(const asm_operand *, char *, size_t, AsmSyntax); + +/* Crée une opérande contenant une valeur sur x bits. */ +bool fill_imm_operand(asm_operand *, AsmOperandSize, const uint8_t *, off_t *, off_t); + +/* Traduit une opérande de valeur immédiate en texte. */ +void print_imm_operand(const asm_operand *, char *, size_t, AsmSyntax); diff --git a/src/arch/processor-int.h b/src/arch/processor-int.h index 602bab6..a4f983c 100644 --- a/src/arch/processor-int.h +++ b/src/arch/processor-int.h @@ -28,17 +28,16 @@ #include <sys/types.h> +#include "operand.h" /* TODO: AsmSyntax ? */ #include "instruction.h" #include "processor.h" -typedef int AsmSyntax; - /* Décode une instruction dans un flux de données. */ -typedef asm_instr * (* fetch_instruction) (const asm_processor *, const char *, off_t *, off_t); +typedef asm_instr * (* fetch_instruction) (const asm_processor *, const uint8_t *, off_t *, off_t); /* Traduit une instruction en version humainement lisible. */ typedef void (* print_instruction) (const asm_processor *, const asm_instr *, char *, size_t, AsmSyntax); diff --git a/src/arch/processor.c b/src/arch/processor.c index fc59fdb..a8efb60 100644 --- a/src/arch/processor.c +++ b/src/arch/processor.c @@ -45,7 +45,7 @@ * * ******************************************************************************/ -asm_instr *decode_instruction(const asm_processor *proc, const char *data, off_t *pos, off_t len) +asm_instr *decode_instruction(const asm_processor *proc, const uint8_t *data, off_t *pos, off_t len) { asm_instr *result; /* Représentation à renvoyer */ @@ -86,9 +86,9 @@ asm_instr *decode_instruction(const asm_processor *proc, const char *data, off_t * * ******************************************************************************/ -void print_hinstruction(const asm_processor *proc, const asm_instr *instr, char *buffer, size_t len/*, AsmSyntax syntax*/) +void print_hinstruction(const asm_processor *proc, const asm_instr *instr, char *buffer, size_t len, AsmSyntax syntax) { - proc->print_instr(proc, instr, buffer, len, 0); + proc->print_instr(proc, instr, buffer, len, syntax); } diff --git a/src/arch/processor.h b/src/arch/processor.h index 1023d45..9ad4be0 100644 --- a/src/arch/processor.h +++ b/src/arch/processor.h @@ -28,6 +28,7 @@ #include <sys/types.h> +#include "operand.h" /* AsmSyntax */ #include "instruction.h" @@ -38,10 +39,10 @@ typedef struct _asm_processor asm_processor; /* Décode une instruction dans un flux de données. */ -asm_instr *decode_instruction(const asm_processor *, const char *, off_t *, off_t); +asm_instr *decode_instruction(const asm_processor *, const uint8_t *, off_t *, off_t); /* Traduit une instruction en version humainement lisible. */ -void print_hinstruction(const asm_processor *, const asm_instr *, char *, size_t); +void print_hinstruction(const asm_processor *, const asm_instr *, char *, size_t, AsmSyntax); diff --git a/src/arch/x86/Makefile.am b/src/arch/x86/Makefile.am index 6fe55c8..4947118 100644 --- a/src/arch/x86/Makefile.am +++ b/src/arch/x86/Makefile.am @@ -4,7 +4,10 @@ lib_LIBRARIES = libarchx86.a libarchx86_a_SOURCES = \ instruction.h \ op_int.c \ + op_nop.c \ + op_mov.c \ opcodes.h \ + operand.h operand.c \ processor.h processor.c libarchx86_a_CFLAGS = $(AM_CFLAGS) diff --git a/src/arch/x86/instruction.h b/src/arch/x86/instruction.h index 47617ea..c3c417b 100644 --- a/src/arch/x86/instruction.h +++ b/src/arch/x86/instruction.h @@ -38,8 +38,27 @@ typedef struct _asm_x86_instr asm_x86_instr; /* Enumération de tous les opcodes */ typedef enum _X86Opcodes { + X86_OP_NOP, /* nop (0x90) */ + + X86_OP_MOV_AX, /* mov (0xb0) */ + X86_OP_MOV_CX, /* mov (0xb1) */ + X86_OP_MOV_DX, /* mov (0xb2) */ + X86_OP_MOV_BX, /* mov (0xb3) */ + X86_OP_MOV_SP, /* mov (0xb4) */ + X86_OP_MOV_BP, /* mov (0xb5) */ + X86_OP_MOV_SI, /* mov (0xb6) */ + X86_OP_MOV_DI, /* mov (0xb7) */ + X86_OP_INT, /* int (0xcd) */ + X86_OP_MOV_EAX, /* mov (0x66 0xb0) */ + X86_OP_MOV_ECX, /* mov (0x66 0xb1) */ + X86_OP_MOV_EDX, /* mov (0x66 0xb2) */ + X86_OP_MOV_EBX, /* mov (0x66 0xb3) */ + X86_OP_MOV_ESP, /* mov (0x66 0xb4) */ + X86_OP_MOV_EBP, /* mov (0x66 0xb5) */ + X86_OP_MOV_ESI, /* mov (0x66 0xb6) */ + X86_OP_MOV_EDI, /* mov (0x66 0xb7) */ X86_OP_COUNT @@ -48,6 +67,19 @@ typedef enum _X86Opcodes +/* Eventuel préfixe rencontré */ +typedef enum _X86Prefix +{ + X86_PRE_NONE = 0, /* Aucun préfixe */ + + + X86_PRE_OPSIZE /* Basculement des opérandes */ + + +} X86Prefix; + + + /* Définition d'une instruction x86 */ struct _asm_x86_instr { @@ -55,6 +87,10 @@ struct _asm_x86_instr X86Opcodes type; + + X86Prefix prefix; /* Eventuel préfixe trouvé */ + + }; diff --git a/src/arch/x86/op_int.c b/src/arch/x86/op_int.c index e7805e1..3c621d6 100644 --- a/src/arch/x86/op_int.c +++ b/src/arch/x86/op_int.c @@ -24,9 +24,9 @@ #include <malloc.h> -#include "instruction.h" #include "../instruction-int.h" - +#include "opcodes.h" +#include "operand.h" @@ -44,20 +44,28 @@ * * ******************************************************************************/ -asm_x86_instr *read_instr_int(const char *data, off_t *pos, off_t len) +asm_x86_instr *read_instr_int(const uint8_t *data, off_t *pos, off_t len) { - asm_x86_instr *result; + asm_x86_instr *result; /* Instruction à retourner */ + asm_x86_operand *syscall; /* Indice de l'appel système */ result = (asm_x86_instr *)calloc(1, sizeof(asm_x86_instr)); ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; - /* TODO: check result */ - fill_db_operand(&ASM_INSTRUCTION(result)->operands[0], data[(*pos)++]); + syscall = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(syscall), AOS_8_BITS, data, pos, len)) + { + free(syscall); + free(result); + return NULL; + } + ASM_INSTRUCTION(result)->operands = (asm_operand **)calloc(1, sizeof(asm_operand *)); ASM_INSTRUCTION(result)->operands_count = 1; + ASM_INSTRUCTION(result)->operands[0] = ASM_OPERAND(syscall); + return result; } - diff --git a/src/arch/x86/op_mov.c b/src/arch/x86/op_mov.c new file mode 100644 index 0000000..22cb828 --- /dev/null +++ b/src/arch/x86/op_mov.c @@ -0,0 +1,89 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * op_mov.c - décodage des déplacements de données + * + * Copyright (C) 2008 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <malloc.h> + + +#include "../instruction-int.h" +#include "opcodes.h" +#include "operand.h" + + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* * +* Description : Décode une instruction de type 'mov' (16 ou 32 bits). * +* * +* Retour : Instruction mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_instr *read_instr_mov_to_1632(const uint8_t *data, off_t *pos, off_t len) +{ + asm_x86_instr *result; /* Instruction à retourner */ + bool is_reg32; /* Implique un registre 32 bits*/ + asm_x86_operand *reg; /* Registre de destination */ + asm_x86_operand *value; /* Valeur portée */ + + result = (asm_x86_instr *)calloc(1, sizeof(asm_x86_instr)); + + /* Utilisation des registres 32 bits ? */ + is_reg32 = (data[*pos] == 0x66); + if (is_reg32) + { + (*pos)++; + } + + ASM_INSTRUCTION(result)->opcode = data[*pos]; + + reg = x86_create_reg1632_operand(data[(*pos)++], is_reg32); + if (reg == NULL) + { + free(result); + return NULL; + } + + value = create_new_x86_operand(); + if (!fill_imm_operand(ASM_OPERAND(value), is_reg32 ? AOS_32_BITS : AOS_16_BITS, data, pos, len)) + { + free(reg); + free(value); + free(result); + return NULL; + } + + ASM_INSTRUCTION(result)->operands = (asm_operand **)calloc(2, sizeof(asm_operand *)); + ASM_INSTRUCTION(result)->operands_count = 2; + + ASM_INSTRUCTION(result)->operands[0] = ASM_OPERAND(reg); + ASM_INSTRUCTION(result)->operands[1] = ASM_OPERAND(value); + + return result; + +} diff --git a/src/arch/x86/op_nop.c b/src/arch/x86/op_nop.c new file mode 100644 index 0000000..c23b5f1 --- /dev/null +++ b/src/arch/x86/op_nop.c @@ -0,0 +1,56 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * op_nop.c - décodage des instructions nulles + * + * Copyright (C) 2008 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <malloc.h> + + +#include "../instruction-int.h" +#include "opcodes.h" + + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* * +* Description : Décode une instruction de type 'nop'. * +* * +* Retour : Instruction mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_instr *read_instr_nop(const uint8_t *data, off_t *pos, off_t len) +{ + asm_x86_instr *result; + + result = (asm_x86_instr *)calloc(1, sizeof(asm_x86_instr)); + + ASM_INSTRUCTION(result)->opcode = data[(*pos)++]; + + return result; + +} diff --git a/src/arch/x86/opcodes.h b/src/arch/x86/opcodes.h index 17316e7..d6be6a1 100644 --- a/src/arch/x86/opcodes.h +++ b/src/arch/x86/opcodes.h @@ -28,12 +28,18 @@ #include <sys/types.h> -#include "../instruction.h" +#include "instruction.h" /* Décode une instruction de type 'int'. */ -asm_x86_instr *read_instr_int(const char *, off_t *, off_t); +asm_x86_instr *read_instr_int(const uint8_t *, off_t *, off_t); + +/* Décode une instruction de type 'mov' (16 ou 32 bits). */ +asm_x86_instr *read_instr_mov_to_1632(const uint8_t *, off_t *, off_t); + +/* Décode une instruction de type 'nop'. */ +asm_x86_instr *read_instr_nop(const uint8_t *, off_t *, off_t); diff --git a/src/arch/x86/operand.c b/src/arch/x86/operand.c new file mode 100644 index 0000000..84d4038 --- /dev/null +++ b/src/arch/x86/operand.c @@ -0,0 +1,402 @@ +/* OpenIDA - Outil d'analyse de fichiers binaires + * operand.c - gestion des operandes de l'architecture x86 + * + * Copyright (C) 2008 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "operand.h" + + +#include <malloc.h> +#include <stdio.h> + + +#include "../operand.h" +#include "../operand-int.h" + + + + +/* Liste des registres 8 bits */ +typedef enum _X868bRegister +{ + X86_REG8_AL = 0, /* Registre AL */ + X86_REG8_CL = 1, /* Registre AL */ + X86_REG8_DL = 2, /* Registre AL */ + X86_REG8_BL = 3, /* Registre AL */ + X86_REG8_AH = 4, /* Registre AH */ + X86_REG8_CH = 5, /* Registre AH */ + X86_REG8_DH = 6, /* Registre AH */ + X86_REG8_BH = 7, /* Registre AH */ + +} X868bRegister; + +/* Liste des registres 16 bits */ +typedef enum _X8616bRegister +{ + X86_REG16_AX = 0, /* Registre AX */ + X86_REG16_CX = 1, /* Registre AX */ + X86_REG16_DX = 2, /* Registre AX */ + X86_REG16_BX = 3, /* Registre AX */ + X86_REG16_SP = 4, /* Registre SP */ + X86_REG16_BP = 5, /* Registre BP */ + X86_REG16_SI = 6, /* Registre SI */ + X86_REG16_DI = 7, /* Registre DI */ + +} X8616bRegister; + +/* Liste des registres 32 bits */ +typedef enum _X8632bRegister +{ + X86_REG32_EAX = 0, /* Registre EAX */ + X86_REG32_ECX = 1, /* Registre EAX */ + X86_REG32_EDX = 2, /* Registre EAX */ + X86_REG32_EBX = 3, /* Registre EAX */ + X86_REG32_ESP = 4, /* Registre ESP */ + X86_REG32_EBP = 5, /* Registre EBP */ + X86_REG32_ESI = 6, /* Registre ESI */ + X86_REG32_EDI = 7, /* Registre EDI */ + +} X8632bRegister; + + + + + +/* Définition d'une opérande x86 */ +struct _asm_x86_operand +{ + asm_operand base; /* A laisser en premier */ + + union + { + X868bRegister reg8; /* Registre 8 bits */ + X8616bRegister reg16; /* Registre 16 bits */ + X8632bRegister reg32; /* Registre 32 bits */ + + } x86_value; + +}; + + + +#define NULL ((void *)0) + + + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une opérande vierge pour x86. * +* * +* Retour : Opérande nouvellement créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_x86_operand *create_new_x86_operand(void) +{ + return (asm_x86_operand *)calloc(1, sizeof(asm_x86_operand)); + +} + + + + + + + +/****************************************************************************** +* * +* Paramètres : data = donnée à analyser. * +* is_reg32 = indique si le registre est un registre 32 bits. * +* * +* 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_reg1632_operand(uint8_t data, bool is_reg32) +{ + asm_x86_operand *result; /* Registre à retourner */ + X8616bRegister reg16; /* Registre 16 bits */ + X8632bRegister reg32; /* Registre 32 bits */ + + if (is_reg32) + switch (data - 0xb8) + { + case 0 ... 7: + reg32 = (X8632bRegister)(data - 0xb8); + break; + default: + return NULL; + break; + } + + else + switch (data - 0xb0) + { + case 0 ... 7: + reg16 = (X8616bRegister)(data - 0xb0); + break; + default: + return NULL; + break; + } + + result = create_new_x86_operand(); + + ASM_OPERAND(result)->type = AOT_REG; + ASM_OPERAND(result)->size = (is_reg32 ? AOS_32_BITS : AOS_16_BITS); + + if (is_reg32) result->x86_value.reg32 = reg32; + else result->x86_value.reg16 = reg16; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = instruction à traiter. * +* buffer = tampon de sortie mis à disposition. [OUT] * +* len = taille de ce tampon. * +* syntax = type de représentation demandée. * +* * +* Description : Traduit une opérande de registre en texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void x86_print_reg_operand(const asm_x86_operand *operand, char *buffer, size_t len, AsmSyntax syntax) +{ + switch (syntax) + { + case ASX_INTEL: + switch (ASM_OPERAND(operand)->size) + { + case AOS_8_BITS: + switch (operand->x86_value.reg8) + { + case X86_REG8_AL: + snprintf(buffer, len, "al"); + break; + case X86_REG8_CL: + snprintf(buffer, len, "cl"); + break; + case X86_REG8_DL: + snprintf(buffer, len, "dl"); + break; + case X86_REG8_BL: + snprintf(buffer, len, "bl"); + break; + case X86_REG8_AH: + snprintf(buffer, len, "ah"); + break; + case X86_REG8_CH: + snprintf(buffer, len, "ch"); + break; + case X86_REG8_DH: + snprintf(buffer, len, "dh"); + break; + case X86_REG8_BH: + snprintf(buffer, len, "bh"); + break; + } + break; + + case AOS_16_BITS: + switch (operand->x86_value.reg16) + { + case X86_REG16_AX: + snprintf(buffer, len, "ax"); + break; + case X86_REG16_CX: + snprintf(buffer, len, "cx"); + break; + case X86_REG16_DX: + snprintf(buffer, len, "dx"); + break; + case X86_REG16_BX: + snprintf(buffer, len, "bx"); + break; + case X86_REG16_SP: + snprintf(buffer, len, "sp"); + break; + case X86_REG16_BP: + snprintf(buffer, len, "bp"); + break; + case X86_REG16_SI: + snprintf(buffer, len, "si"); + break; + case X86_REG16_DI: + snprintf(buffer, len, "di"); + break; + } + break; + + case AOS_32_BITS: + switch (operand->x86_value.reg32) + { + case X86_REG32_EAX: + snprintf(buffer, len, "eax"); + break; + case X86_REG32_ECX: + snprintf(buffer, len, "ecx"); + break; + case X86_REG32_EDX: + snprintf(buffer, len, "edx"); + break; + case X86_REG32_EBX: + snprintf(buffer, len, "ebx"); + break; + case X86_REG32_ESP: + snprintf(buffer, len, "esp"); + break; + case X86_REG32_EBP: + snprintf(buffer, len, "ebp"); + break; + case X86_REG32_ESI: + snprintf(buffer, len, "esi"); + break; + case X86_REG32_EDI: + snprintf(buffer, len, "edi"); + break; + } + break; + + case AOS_64_BITS: + break; + + } + break; + + case ASX_ATT: + switch (ASM_OPERAND(operand)->size) + { + case AOS_8_BITS: + switch (operand->x86_value.reg8) + { + case X86_REG8_AL: + snprintf(buffer, len, "%%al"); + break; + case X86_REG8_CL: + snprintf(buffer, len, "%%cl"); + break; + case X86_REG8_DL: + snprintf(buffer, len, "%%dl"); + break; + case X86_REG8_BL: + snprintf(buffer, len, "%%bl"); + break; + case X86_REG8_AH: + snprintf(buffer, len, "%%ah"); + break; + case X86_REG8_CH: + snprintf(buffer, len, "%%ch"); + break; + case X86_REG8_DH: + snprintf(buffer, len, "%%dh"); + break; + case X86_REG8_BH: + snprintf(buffer, len, "%%bh"); + break; + } + break; + + case AOS_16_BITS: + switch (operand->x86_value.reg16) + { + case X86_REG16_AX: + snprintf(buffer, len, "%%ax"); + break; + case X86_REG16_CX: + snprintf(buffer, len, "%%cx"); + break; + case X86_REG16_DX: + snprintf(buffer, len, "%%dx"); + break; + case X86_REG16_BX: + snprintf(buffer, len, "%%bx"); + break; + case X86_REG16_SP: + snprintf(buffer, len, "%%sp"); + break; + case X86_REG16_BP: + snprintf(buffer, len, "%%bp"); + break; + case X86_REG16_SI: + snprintf(buffer, len, "%%si"); + break; + case X86_REG16_DI: + snprintf(buffer, len, "%%di"); + break; + } + break; + + case AOS_32_BITS: + switch (operand->x86_value.reg32) + { + case X86_REG32_EAX: + snprintf(buffer, len, "%%eax"); + break; + case X86_REG32_ECX: + snprintf(buffer, len, "%%ecx"); + break; + case X86_REG32_EDX: + snprintf(buffer, len, "%%edx"); + break; + case X86_REG32_EBX: + snprintf(buffer, len, "%%ebx"); + break; + case X86_REG32_ESP: + snprintf(buffer, len, "%%esp"); + break; + case X86_REG32_EBP: + snprintf(buffer, len, "%%ebp"); + break; + case X86_REG32_ESI: + snprintf(buffer, len, "%%esi"); + break; + case X86_REG32_EDI: + snprintf(buffer, len, "%%edi"); + break; + } + break; + + case AOS_64_BITS: + break; + + } + break; + + } + +} diff --git a/src/arch/x86/operand.h b/src/arch/x86/operand.h new file mode 100644 index 0000000..0773333 --- /dev/null +++ b/src/arch/x86/operand.h @@ -0,0 +1,53 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * operand.h - prototypes pour la gestion des operandes de l'architecture x86 + * + * Copyright (C) 2008 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ARCH_X86_OPERAND_H +#define _ARCH_X86_OPERAND_H + + +#include <stdbool.h> +#include <stdint.h> + + +#include "../operand.h" /* TODO : AsmSyntax ? */ + + +/* Définition d'une opérande x86 */ +typedef struct _asm_x86_operand asm_x86_operand; + + + +/* Crée une opérande vierge pour x86. */ +asm_x86_operand *create_new_x86_operand(void); + + + +/* Crée une opérande renvoyant vers un registre 16 ou 32 bits. */ +asm_x86_operand *x86_create_reg1632_operand(uint8_t, bool); + +/*Traduit une opérande de registre en texte. */ +void x86_print_reg_operand(const asm_x86_operand *, char *, size_t, AsmSyntax); + + + +#endif /* _ARCH_X86_OPERAND_H */ diff --git a/src/arch/x86/processor.c b/src/arch/x86/processor.c index 4ef1377..895c8b1 100644 --- a/src/arch/x86/processor.c +++ b/src/arch/x86/processor.c @@ -24,30 +24,34 @@ #include "processor.h" +#include <malloc.h> +#include <stdio.h> + + #include "../processor-int.h" #include "instruction.h" #include "opcodes.h" - - -#include <malloc.h> +#include "operand.h" -typedef asm_x86_instr * (* read_instr) (const char *, off_t *, off_t); +typedef asm_x86_instr * (* read_instr) (const uint8_t *, off_t *, off_t); /* Carte d'identité d'un opcode */ typedef struct _x86_opcode { - char opcode; /* Opcode + préfixe eventuel */ + uint8_t prefix; /* préfixe eventuel */ + uint8_t opcode; /* Opcode seul */ const char *name; /* Désignation humaine */ read_instr read; /* Décodage de l'instruction */ } x86_opcode; -#define register_opcode(target, bin, n, func) \ +#define register_opcode(target, pre, bin, n, func) \ do {\ +target.prefix = pre; \ target.opcode = bin; \ target.name = n; \ target.read = func; \ @@ -72,7 +76,7 @@ void x86_register_instructions(asm_x86_processor *); /* Décode une instruction dans un flux de données. */ -asm_instr *x86_fetch_instruction(const asm_x86_processor *, const char *, off_t *, off_t); +asm_instr *x86_fetch_instruction(const asm_x86_processor *, const uint8_t *, off_t *, off_t); /* Traduit une instruction en version humainement lisible. */ void x86_print_instruction(const asm_x86_processor *, const asm_x86_instr *, char *, size_t, AsmSyntax); @@ -129,11 +133,32 @@ void x86_register_instructions(asm_x86_processor *proc) - register_opcode(proc->opcodes[X86_OP_INT], 0xcd, "int", read_instr_int); + register_opcode(proc->opcodes[X86_OP_NOP], 0x00, 0x90, "nop", read_instr_nop); + register_opcode(proc->opcodes[X86_OP_MOV_AX], 0x00, 0xb8, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_DX], 0x00, 0xb9, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_DX], 0x00, 0xba, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_BX], 0x00, 0xbb, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_SP], 0x00, 0xbc, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_BP], 0x00, 0xbd, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_SI], 0x00, 0xbe, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_DI], 0x00, 0xbf, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_INT], 0x00, 0xcd, "int", read_instr_int); + + + + register_opcode(proc->opcodes[X86_OP_MOV_EAX], 0x66, 0xb8, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_ECX], 0x66, 0xb9, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_EDX], 0x66, 0xba, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_EBX], 0x66, 0xbb, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_ESP], 0x66, 0xbc, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_EBP], 0x66, 0xbd, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_ESI], 0x66, 0xbe, "mov", read_instr_mov_to_1632); + register_opcode(proc->opcodes[X86_OP_MOV_EDI], 0x66, 0xbf, "mov", read_instr_mov_to_1632); + } @@ -155,25 +180,17 @@ void x86_register_instructions(asm_x86_processor *proc) * * ******************************************************************************/ -asm_instr *x86_fetch_instruction(const asm_x86_processor *proc, const char *data, off_t *pos, off_t len) +asm_instr *x86_fetch_instruction(const asm_x86_processor *proc, const uint8_t *data, off_t *pos, off_t len) { asm_x86_instr *result; /* Résultat à faire remonter */ X86Opcodes i; /* Boucle de parcours */ result = NULL; - //printf("--------\n"); - for (i = 0; i < X86_OP_COUNT; i++) { - - /* - printf(" cmp :: 0x%02hhx vs 0x%02hhx ? %d\n", - data[*pos], proc->opcodes[i].opcode, - data[*pos] == proc->opcodes[i].opcode); - */ - - if (data[*pos] == proc->opcodes[i].opcode) + if ((proc->opcodes[i].prefix > 0 && data[*pos] == proc->opcodes[i].prefix && data[*pos + 1] == proc->opcodes[i].opcode) + || (proc->opcodes[i].prefix == 0 && data[*pos] == proc->opcodes[i].opcode)) { result = proc->opcodes[i].read(data, pos, len); if (result != NULL) result->type = i; @@ -182,7 +199,6 @@ asm_instr *x86_fetch_instruction(const asm_x86_processor *proc, const char *data } - return ASM_INSTRUCTION(result); } @@ -206,17 +222,56 @@ asm_instr *x86_fetch_instruction(const asm_x86_processor *proc, const char *data void x86_print_instruction(const asm_x86_processor *proc, const asm_x86_instr *instr, char *buffer, size_t len, AsmSyntax syntax) { + size_t i; /* Boucle de parcours */ + char opbuffer[3][64]; /* Tampon pour les textes */ - if (ASM_INSTRUCTION(instr)->opcode == DB_OPCODE) - + /* Impression des opérandes */ - snprintf(buffer, len, "db\t0x%02hhx", ASM_INSTRUCTION(instr)->operands[0].value.val8); + for (i = 0; i < ASM_INSTRUCTION(instr)->operands_count; i++) + switch (ASM_OPERAND(ASM_INSTRUCTION(instr)->operands[i])->type) + { + case AOT_NONE: + print_db_operand(ASM_OPERAND(ASM_INSTRUCTION(instr)->operands[i]), opbuffer[i], 64, syntax); + break; + case AOT_IMM: + print_imm_operand(ASM_OPERAND(ASM_INSTRUCTION(instr)->operands[i]), opbuffer[i], 64, syntax); + break; + case AOT_REG: + x86_print_reg_operand(ASM_INSTRUCTION(instr)->operands[i], opbuffer[i], 64, syntax); + break; + case AOT_MEM: + break; + } + /* Impression globale finale */ - else + if (ASM_INSTRUCTION(instr)->opcode == DB_OPCODE) + snprintf(buffer, len, "db\t%s", opbuffer[0]); - snprintf(buffer, len, "%s\t0x%02hhx", proc->opcodes[instr->type].name, ASM_INSTRUCTION(instr)->operands[0].value.val8); + else + switch (ASM_INSTRUCTION(instr)->operands_count) + { + case 0: + snprintf(buffer, len, "%s", proc->opcodes[instr->type].name); + break; + + case 1: + snprintf(buffer, len, "%s\t%s", proc->opcodes[instr->type].name, opbuffer[0]); + break; + + case 2: + switch (syntax) + { + case ASX_INTEL: + snprintf(buffer, len, "%s\t%s, %s", proc->opcodes[instr->type].name, opbuffer[0], opbuffer[1]); + break; + case ASX_ATT: + snprintf(buffer, len, "%s\t%s, %s", proc->opcodes[instr->type].name, opbuffer[1], opbuffer[0]); + break; + } + break; + } } |