/* OpenIDA - Outil d'analyse de fichiers binaires
* processor.c - gestion 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 .
*/
#include "processor.h"
#include
#include
#include "../processor-int.h"
#include "instruction.h"
#include "opcodes.h"
#include "operand.h"
typedef asm_x86_instr * (* read_instr) (const uint8_t *, off_t *, off_t);
/* Carte d'identité d'un opcode */
typedef struct _x86_opcode
{
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, pre, bin, n, func) \
do {\
target.prefix = pre; \
target.opcode = bin; \
target.name = n; \
target.read = func; \
} while (0)
/* Définition générique d'une architecture */
typedef struct _asm_x86_processor
{
asm_processor base; /* A laisser en premier... */
x86_opcode opcodes[X86_OP_COUNT]; /* Liste des opcodes supportés */
} asm_x86_processor;
/* Enregistre toutes les instructions reconnues pour x86. */
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 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);
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée le support de l'architecture x86. *
* *
* Retour : Architecture mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
asm_processor *create_x86_processor(void)
{
asm_x86_processor *result; /* Architecture à retourner */
result = (asm_x86_processor *)calloc(1, sizeof(asm_x86_processor));
x86_register_instructions(result);
ASM_PROCESSOR(result)->fetch_instr = x86_fetch_instruction;
ASM_PROCESSOR(result)->print_instr = x86_print_instruction;
return ASM_PROCESSOR(result);
}
/******************************************************************************
* *
* Paramètres : proc = architecture visée par la procédure. *
* *
* Description : Enregistre toutes les instructions reconnues pour x86. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void x86_register_instructions(asm_x86_processor *proc)
{
/* TODO : voir pour une inversion avec le mode 16 bits ! */
register_opcode(proc->opcodes[X86_OP_INC_EAX], 0x00, 0x40, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_ECX], 0x00, 0x41, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_EDX], 0x00, 0x42, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_EBX], 0x00, 0x43, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_ESP], 0x00, 0x44, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_EBP], 0x00, 0x45, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_ESI], 0x00, 0x46, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_EDI], 0x00, 0x47, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_DEC_EAX], 0x00, 0x48, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_ECX], 0x00, 0x49, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_EDX], 0x00, 0x4a, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_EBX], 0x00, 0x4b, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_ESP], 0x00, 0x4c, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_EBP], 0x00, 0x4d, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_ESI], 0x00, 0x4e, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_EDI], 0x00, 0x4f, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_EAX], 0x00, 0x50, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_ECX], 0x00, 0x51, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_EDX], 0x00, 0x52, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_EBX], 0x00, 0x53, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_ESP], 0x00, 0x54, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_EBP], 0x00, 0x55, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_ESI], 0x00, 0x56, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_EDI], 0x00, 0x57, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_POP_EAX], 0x00, 0x58, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_ECX], 0x00, 0x59, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_EDX], 0x00, 0x5a, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_EBX], 0x00, 0x5b, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_ESP], 0x00, 0x5c, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_EBP], 0x00, 0x5d, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_ESI], 0x00, 0x5e, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_EDI], 0x00, 0x5f, "pop", read_instr_pop_1632);
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_CX], 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_HLT], 0x00, 0xf4, "hlt", read_instr_hlt);
register_opcode(proc->opcodes[X86_OP_INC_AX], 0x66, 0x40, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_CX], 0x66, 0x41, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_DX], 0x66, 0x42, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_BX], 0x66, 0x43, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_SP], 0x66, 0x44, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_BP], 0x66, 0x45, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_SI], 0x66, 0x46, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_INC_DI], 0x66, 0x47, "inc", read_instr_inc_1632);
register_opcode(proc->opcodes[X86_OP_DEC_AX], 0x66, 0x48, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_CX], 0x66, 0x49, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_DX], 0x66, 0x4a, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_BX], 0x66, 0x4b, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_SP], 0x66, 0x4c, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_BP], 0x66, 0x4d, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_SI], 0x66, 0x4e, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_DEC_DI], 0x66, 0x4f, "dec", read_instr_dec_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_AX], 0x66, 0x50, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_CX], 0x66, 0x51, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_DX], 0x66, 0x52, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_BX], 0x66, 0x53, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_SP], 0x66, 0x54, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_BP], 0x66, 0x55, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_SI], 0x66, 0x56, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_PUSH_DI], 0x66, 0x57, "push", read_instr_push_1632);
register_opcode(proc->opcodes[X86_OP_POP_AX], 0x66, 0x58, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_CX], 0x66, 0x59, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_DX], 0x66, 0x5a, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_BX], 0x66, 0x5b, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_SP], 0x66, 0x5c, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_BP], 0x66, 0x5d, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_SI], 0x66, 0x5e, "pop", read_instr_pop_1632);
register_opcode(proc->opcodes[X86_OP_POP_DI], 0x66, 0x5f, "pop", read_instr_pop_1632);
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);
}
/******************************************************************************
* *
* Paramètres : proc = architecture visée par la procédure. *
* 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 dans un flux de données. *
* *
* Retour : Instruction mise en place ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
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;
for (i = 0; i < X86_OP_COUNT; i++)
{
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;
printf("err while decoding :: [0x%02hhx] 0x%02hhx\n", proc->opcodes[i].prefix, proc->opcodes[i].opcode);
break;
}
}
return ASM_INSTRUCTION(result);
}
/******************************************************************************
* *
* Paramètres : proc = architecture visée par la procédure. *
* instr = instruction à traiter. *
* buffer = tampon de sortie mis à disposition. [OUT] *
* len = taille de ce tampon. *
* syntax = type de représentation demandée. *
* *
* Description : Traduit une instruction en version humainement lisible. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
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 */
/* Impression des opérandes */
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 */
if (ASM_INSTRUCTION(instr)->opcode == DB_OPCODE)
snprintf(buffer, len, "db\t%s", opbuffer[0]);
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;
}
}