diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2013-06-30 13:01:38 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2013-06-30 13:01:38 (GMT) |
commit | e5314b83cf2521f4a1fee5d3cbb5011d7ac7bff7 (patch) | |
tree | 3af6d5b430d3a07753e273e9ddb1ff656e706661 /src/arch/arm/v456/instruction.c | |
parent | 0f3bbcb376ee4f76142ac4ddf729403fecac2641 (diff) |
Provided first basic support for a few ARM instructions.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@354 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/arch/arm/v456/instruction.c')
-rw-r--r-- | src/arch/arm/v456/instruction.c | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/src/arch/arm/v456/instruction.c b/src/arch/arm/v456/instruction.c new file mode 100644 index 0000000..7f69beb --- /dev/null +++ b/src/arch/arm/v456/instruction.c @@ -0,0 +1,683 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * instruction.c - gestion des instructions ARM v4/v5/v6 + * + * Copyright (C) 2013 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 "instruction.h" + + +#include "encoding.h" + + +#include "../instruction-int.h" + + + +//////// +#include <malloc.h> +///////// + + + +typedef unsigned char bin_t; + +typedef unsigned int arch_version_t; + + + +/* -------------------------- INSTRUCTIONS POUR ARM v4/5/6 -------------------------- */ + + +/* Définition d'une instruction d'architecture ARM v4/5/6 (instance) */ +struct _GArmV456Instruction +{ + GArchInstruction parent; /* A laisser en premier */ + + ArmV456Opcodes type; /* Type d'instruction en place */ + +}; + +/* Définition d'une instruction d'architecture ARM v4/5/6 (classe) */ +struct _GArmV456InstructionClass +{ + GArchInstructionClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des instructions pour ARM v4/5/6. */ +static void g_armv456_instruction_class_init(GArmV456InstructionClass *); + +/* Initialise une instance d'opérande d'architecture ARM v4/5/6. */ +static void g_armv456_instruction_init(GArmV456Instruction *); + +/* Traduit une instruction en version humainement lisible. */ +static const char *g_armv456_get_instruction_text(const GArmV456Instruction *, const GExeFormat *, AsmSyntax); + + + + +/* --------------------- AIDE A LA MISE EN PLACE D'INSTRUCTIONS --------------------- */ + + +/* Répertoire de toutes les instructions ARM v4/5/6 */ +typedef struct _arm_v456_instruction +{ + bin_t opcode; /* Opcode de l'instruction */ + const char *keyword; /* Mot clef de la commande */ + + arch_version_t version; /* Version de l'architecture */ + + //decomp_instr_fc decomp; /* Procédure de décompilation */ + +} arm_v456_instruction; + + +/* Liste de toutes les instructions */ +static arm_v456_instruction _instructions[AOP_COUNT] = { + + [AOP_AND] = { 0x00, "and", ARM_VERSION_ALL_456 }, + [AOP_EOR] = { 0x01, "eor", ARM_VERSION_ALL_456 }, + [AOP_SUB] = { 0x02, "sub", ARM_VERSION_ALL_456 }, + [AOP_RSB] = { 0x03, "rsb", ARM_VERSION_ALL_456 }, + [AOP_ADD] = { 0x04, "add", ARM_VERSION_ALL_456 }, + [AOP_ADC] = { 0x05, "adc", ARM_VERSION_ALL_456 }, + [AOP_SBC] = { 0x06, "sbc", ARM_VERSION_ALL_456 }, + [AOP_RSC] = { 0x07, "rsc", ARM_VERSION_ALL_456 }, + [AOP_TST] = { 0x08, "tst", ARM_VERSION_ALL_456 }, + [AOP_TEQ] = { 0x09, "teq", ARM_VERSION_ALL_456 }, + [AOP_CMP] = { 0x0a, "cmp", ARM_VERSION_ALL_456 }, + [AOP_CMN] = { 0x0b, "cmn", ARM_VERSION_ALL_456 }, + [AOP_ORR] = { 0x0c, "orr", ARM_VERSION_ALL_456 }, + [AOP_MOV] = { 0x0d, "mov", ARM_VERSION_ALL_456 }, + [AOP_BIC] = { 0x0e, "bic", ARM_VERSION_ALL_456 }, + [AOP_MVN] = { 0x0f, "mov", ARM_VERSION_ALL_456 }, + + [AOP_LDR] = { 0xff, "ldr", ARM_VERSION_ALL_456 }, + [AOP_STR] = { 0xff, "ldr", ARM_VERSION_ALL_456 } + + + +}; + + +/* Constitution d'un groupe */ +static arm_v456_instruction *_data_processing_instrs[17] = { + + &_instructions[AOP_AND], &_instructions[AOP_EOR], &_instructions[AOP_SUB], + &_instructions[AOP_RSB], &_instructions[AOP_ADD], &_instructions[AOP_ADC], + &_instructions[AOP_SBC], &_instructions[AOP_RSC], &_instructions[AOP_TST], + &_instructions[AOP_TEQ], &_instructions[AOP_CMP], &_instructions[AOP_CMN], + &_instructions[AOP_ORR], &_instructions[AOP_MOV], &_instructions[AOP_BIC], + &_instructions[AOP_MVN], NULL + +}; + + + + +/* ---------------------------------------------------------------------------------- */ +/* INSTRUCTIONS POUR ARM v4/5/6 */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une instruction d'architecture Dalvik. */ +G_DEFINE_TYPE(GArmV456Instruction, g_armv456_instruction, G_TYPE_ARCH_INSTRUCTION); + + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des instructions pour Dalvik. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv456_instruction_class_init(GArmV456InstructionClass *klass) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instance à initialiser. * +* * +* Description : Initialise une instance d'instruction d'architecture Dalvik. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv456_instruction_init(GArmV456Instruction *instr) +{ + GArchInstruction *parent; /* Instance parente */ + + parent = G_ARCH_INSTRUCTION(instr); + + parent->get_text = (get_instruction_text_fc)g_armv456_get_instruction_text; + + /* + parent->get_rw_regs = (get_instruction_rw_regs_fc)g_armv456_instruction_get_rw_registers; + parent->get_text = (get_instruction_text_fc)dalvik_get_instruction_text; + parent->get_link = (get_instruction_link_fc)dalvik_get_instruction_link; + parent->is_return = (is_instruction_return_fc)dalvik_instruction_is_return; + parent->decomp = (decomp_instr_fc)dalvik_instruction_decompile; + */ + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'instruction à représenter. * +* * +* Description : Crée une instruction pour l'architecture Dalvik. * +* * +* Retour : Architecture mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchInstruction *g_armv456_instruction_new(ArmV456Opcodes type) +{ + GArchInstruction *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_ARMV456_INSTRUCTION, NULL); + + G_ARMV456_INSTRUCTION(result)->type = type; + + return result; + +} + + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à traiter. * +* format = format du binaire manipulé. * +* syntax = type de représentation demandée. * +* * +* Description : Traduit une instruction en version humainement lisible. * +* * +* Retour : Chaîne de caractères à libérer de la mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const char *g_armv456_get_instruction_text(const GArmV456Instruction *instr, const GExeFormat *format, AsmSyntax syntax) +{ + return _instructions[instr->type].keyword; + +} + + +#include "addressing.h" + + +GArchInstruction *try_to_decode_arm_v456_instr(bin_t *data) +{ + GArchInstruction *result; /* Instruction à retourner */ + uint32_t *instr; + + ArmV456InstrSets i; /* Boucle de parcours */ + + result = NULL; + + instr = (uint32_t *)data; + + //printf("instr = 0x%x\n", *instr); + + + + for (i = 0; i < ARM_V456_ISET_COUNT; i++) + if (IS_ENCODING_SET(*instr, _arm_v456_encoding_sets[i])) + break; + + switch (i) + { + case ARM_V456_ISET_COUNT: + printf("failed !\n"); + break; + + + case ARM_V456_LD_ST_IMM_OFFSET: + //printf("LOAD !! %s\n", *instr & ARM_V456_BIT_L ? "load" : "store"); + + + + result = g_armv456_instruction_new(*instr & ARM_V456_BIT_L ? AOP_LDR : AOP_STR); + + + /*bool */build_v456_operands_with_load_immediate_offset(result, *instr, NULL); + + + break; + + + default: + //printf("got it !\n"); + break; + + } + + + + + return result; + +} + + + + +#if 0 + +#include "instruction-int.h" +#include "decomp/translate.h" +#include "operands/register.h" +#include "operands/target.h" +#include "../instruction-int.h" +#include "../register-int.h" + + + +/* Initialise la classe des instructions pour Dalvik. */ +static void g_dalvik_instruction_class_init(GDalvikInstructionClass *); + +/* Initialise une instance d'opérande d'architecture Dalvik. */ +static void g_dalvik_instruction_init(GDalvikInstruction *); + +/* Liste les registres lus et écrits par l'instruction. */ +static void g_dalvik_instruction_get_rw_registers(const GDalvikInstruction *, GArchRegister ***, size_t *, GArchRegister ***, size_t *); + + + +/* --------------------- AIDE A LA MISE EN PLACE D'INSTRUCTIONS --------------------- */ + + +/* Répertoire de toutes les instructions Dalvik */ +typedef struct _dalvik_instruction +{ + bin_t opcode; /* Opcode de l'instruction */ + + const char *keyword; /* Mot clef de la commande */ + + decomp_instr_fc decomp; /* Procédure de décompilation */ + +} dalvik_instruction; + + +static dalvik_instruction _instructions[DOP_COUNT] = { + +}; + + +/* Traduit une instruction en version humainement lisible. */ +static const char *dalvik_get_instruction_text(const GDalvikInstruction *, const GExeFormat *, AsmSyntax); + +/* Informe sur une éventuelle référence à une autre instruction. */ +static InstructionLinkType dalvik_get_instruction_link(const GDalvikInstruction *, vmpa_t *); + +/* Indique si l'instruction correspond à un retour de fonction. */ +static bool dalvik_instruction_is_return(const GDalvikInstruction *); + +/* Décompile une instruction de la machine virtuelle Dalvik. */ +GDecInstruction *dalvik_instruction_decompile(const GDalvikInstruction *, GDecContext *); + + + +/* Indique le type défini pour une instruction d'architecture Dalvik. */ +G_DEFINE_TYPE(GDalvikInstruction, g_dalvik_instruction, G_TYPE_ARCH_INSTRUCTION); + + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des instructions pour Dalvik. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dalvik_instruction_class_init(GDalvikInstructionClass *klass) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instance à initialiser. * +* * +* Description : Initialise une instance d'instruction d'architecture Dalvik. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dalvik_instruction_init(GDalvikInstruction *instr) +{ + GArchInstruction *parent; /* Instance parente */ + + parent = G_ARCH_INSTRUCTION(instr); + + parent->get_rw_regs = (get_instruction_rw_regs_fc)g_dalvik_instruction_get_rw_registers; + parent->get_text = (get_instruction_text_fc)dalvik_get_instruction_text; + parent->get_link = (get_instruction_link_fc)dalvik_get_instruction_link; + parent->is_return = (is_instruction_return_fc)dalvik_instruction_is_return; + parent->decomp = (decomp_instr_fc)dalvik_instruction_decompile; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type d'instruction à représenter. * +* * +* Description : Crée une instruction pour l'architecture Dalvik. * +* * +* Retour : Architecture mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchInstruction *g_dalvik_instruction_new(DalvikOpcodes type) +{ + GArchInstruction *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_DALVIK_INSTRUCTION, NULL); + + G_DALVIK_INSTRUCTION(result)->type = type; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction Dalvik à consulter. * +* * +* Description : Indique l'opcode associé à une instruction Dalvik. * +* * +* Retour : Identifiant de l'instruction en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +DalvikOpcodes g_dalvik_instruction_get_opcode(const GDalvikInstruction *instr) +{ + return instr->type; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à consulter. * +* rregs = liste des rgistres lus. [OUT] * +* rcount = nombre de registres lus. [OUT] * +* wregs = liste des rgistres écrits. [OUT] * +* wcount = nombre de registres écrits. [OUT] * +* * +* Description : Liste les registres lus et écrits par l'instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dalvik_instruction_get_rw_registers(const GDalvikInstruction *instr, GArchRegister ***rregs, size_t *rcount, GArchRegister ***wregs, size_t *wcount) +{ + GArchInstruction *base; /* Version basique à manipuler */ + size_t i; /* Boucle de parcours */ + GArchOperand *operand; /* Operande à analyser */ + GDalvikRegister *reg; /* Registre concerné */ + + base = G_ARCH_INSTRUCTION(instr); + + for (i = 0; i < base->operands_count; i++) + { + operand = base->operands[i]; + + if (!G_IS_DALVIK_REGISTER_OPERAND(operand)) + continue; + + reg = g_dalvik_register_operand_get(G_DALVIK_REGISTER_OPERAND(operand)); + + if (g_dalvik_register_operand_is_written(G_DALVIK_REGISTER_OPERAND(operand))) + { + (*wregs) = (GArchRegister **)realloc(*wregs, ++(*wcount) * sizeof(GArchRegister *)); + (*wregs)[(*wcount) - 1] = G_ARCH_REGISTER(reg); + } + else + { + (*rregs) = (GArchRegister **)realloc(*rregs, ++(*rcount) * sizeof(GArchRegister *)); + (*rregs)[(*rcount) - 1] = G_ARCH_REGISTER(reg); + } + + } + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* AIDE A LA MISE EN PLACE D'INSTRUCTIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : data = flux de données à analyser. * +* pos = position courante dans ce flux. * +* len = taille totale des données à analyser. * +* * +* Description : Recherche l'identifiant de la prochaine instruction. * +* * +* Retour : Identifiant de la prochaine instruction à tenter de charger. * +* * +* Remarques : - * +* * +******************************************************************************/ + +DalvikOpcodes dalvik_guess_next_instruction(const bin_t *data, off_t pos, off_t len) +{ + DalvikOpcodes result; /* Identifiant à retourner */ + + result = (DalvikOpcodes)data[pos]; + + /* Si l'instruction est marquée comme non utilisée... */ + if (_instructions[result].keyword == NULL) + result = DOP_COUNT; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à traiter. * +* format = format du binaire manipulé. * +* syntax = type de représentation demandée. * +* * +* Description : Traduit une instruction en version humainement lisible. * +* * +* Retour : Chaîne de caractères à libérer de la mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const char *dalvik_get_instruction_text(const GDalvikInstruction *instr, const GExeFormat *format, AsmSyntax syntax) +{ + return _instructions[instr->type].keyword; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à consulter. * +* addr = eventuelle adresse associée à faire connaître. [OUT] * +* * +* Description : Informe sur une éventuelle référence à une autre instruction.* +* * +* Retour : Type de lien trouvé ou ILT_NONE si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static InstructionLinkType dalvik_get_instruction_link(const GDalvikInstruction *instr, vmpa_t *addr) +{ + InstructionLinkType result; /* Type de lien à retourner */ + GArchOperand *operand; /* Opérande à manipuler */ + const GImmOperand *imm; /* Valeur immédiate */ + + switch (instr->type) + { + case DOP_GOTO: + case DOP_GOTO_16: + case DOP_GOTO_32: + + operand = g_arch_instruction_get_operand(G_ARCH_INSTRUCTION(instr), 0); + imm = g_dalvik_target_operand_get_value(G_DALVIK_TARGET_OPERAND(operand)); + + if (g_imm_operand_to_vmpa_t(imm, addr)) result = ILT_JUMP; + else result = ILT_NONE; + + break; + + case DOP_IF_EQ: + case DOP_IF_NE: + case DOP_IF_LT: + case DOP_IF_GE: + case DOP_IF_GT: + case DOP_IF_LE: + + operand = g_arch_instruction_get_operand(G_ARCH_INSTRUCTION(instr), 2); + imm = g_dalvik_target_operand_get_value(G_DALVIK_TARGET_OPERAND(operand)); + + if (g_imm_operand_to_vmpa_t(imm, addr)) result = ILT_JUMP_IF_TRUE; + else result = ILT_NONE; + + break; + + case DOP_IF_EQZ: + case DOP_IF_NEZ: + case DOP_IF_LTZ: + case DOP_IF_GEZ: + case DOP_IF_GTZ: + case DOP_IF_LEZ: + + operand = g_arch_instruction_get_operand(G_ARCH_INSTRUCTION(instr), 1); + imm = g_dalvik_target_operand_get_value(G_DALVIK_TARGET_OPERAND(operand)); + + if (g_imm_operand_to_vmpa_t(imm, addr)) result = ILT_JUMP_IF_TRUE; + else result = ILT_NONE; + + break; + + default: + result = ILT_NONE; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction à consulter. * +* * +* Description : Indique si l'instruction correspond à un retour de fonction. * +* * +* Retour : true si l'instruction est un 'return' quelconque ou false. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool dalvik_instruction_is_return(const GDalvikInstruction *instr) +{ + return (instr->type == DOP_RETURN_VOID + || instr->type == DOP_RETURN + || instr->type == DOP_RETURN_WIDE + || instr->type == DOP_RETURN_OBJECT); + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction d'origine à convertir. * +* ctx = contexte de la phase de décompilation. * +* * +* Description : Décompile une instruction de la machine virtuelle Dalvik. * +* * +* Retour : Instruction mise en place ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDecInstruction *dalvik_instruction_decompile(const GDalvikInstruction *instr, GDecContext *ctx) +{ + GDecInstruction *result; /* Instruction à retourner */ + + if (_instructions[instr->type].decomp != NULL) + result = _instructions[instr->type].decomp(G_ARCH_INSTRUCTION(instr), ctx); + + else + result = NULL; + + return result; + +} + + + +#endif |