diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2017-10-18 20:50:10 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2017-10-18 20:50:10 (GMT) |
commit | dce9d9cdfef1d37ef11a987a21f36e83b6b1944f (patch) | |
tree | 830623ade20e892954fcbddd3b7b05d09aac1dd7 /plugins/dalvik/operand.c | |
parent | 1e7c7de85438749d3faf7b76984b86a9c088fbc1 (diff) |
Created plugins for the Dex and Dalvik support.
Diffstat (limited to 'plugins/dalvik/operand.c')
-rw-r--r-- | plugins/dalvik/operand.c | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/plugins/dalvik/operand.c b/plugins/dalvik/operand.c new file mode 100644 index 0000000..e37a0bb --- /dev/null +++ b/plugins/dalvik/operand.c @@ -0,0 +1,752 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand.c - aide à la création d'opérandes Dalvik + * + * Copyright (C) 2010-2017 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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. + * + * Chrysalide 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 <assert.h> +#include <malloc.h> +#include <stdarg.h> + + + +/* Liste de tous les types d'opérandes */ +typedef enum _DalvikOperandID +{ + DOI_INVALID, + + DOI_REGISTER_4, + DOI_REGISTER_8, + DOI_REGISTER_16, + + DOI_IMMEDIATE_4, + DOI_IMMEDIATE_8, + DOI_IMMEDIATE_16, + DOI_IMMEDIATE_32, + DOI_IMMEDIATE_64, + DOI_IMMEDIATE_H16, + + DOI_POOL_CONST, + DOI_POOL_CONST_WIDE, + + DOI_TARGET_8, + DOI_TARGET_16, + DOI_TARGET_32 + +} DalvikOperandID; + + +/* Crée un opérande visant une instruction Dalvik. */ +static GArchOperand *dalvik_build_target_operand(const GBinContent *, vmpa2t *, MemoryDataSize , SourceEndian, const vmpa2t *); + +/* Procède à la lecture d'opérandes pour une instruction. */ +static bool dalvik_read_basic_operands(GArchInstruction *, GDexFormat *, const GBinContent *, vmpa2t *, bool *, SourceEndian, DalvikOperandType, ...); + +/* Procède à la lecture d'opérandes pour une instruction. */ +static bool dalvik_read_fixed_operands(GArchInstruction *, GDexFormat *, const GBinContent *, vmpa2t *, bool *, SourceEndian, DalvikOperandType); + +/* Procède à la lecture d'opérandes pour une instruction. */ +static bool dalvik_read_variatic_operands(GArchInstruction *, GDexFormat *, const GBinContent *, vmpa2t *, bool *, SourceEndian, DalvikOperandType); + + + +/****************************************************************************** +* * +* Paramètres : content = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* size = taille de l'opérande. * +* endian = ordre des bits dans la source. * +* base = adresse de référence pour le calcul. * +* * +* Description : Crée un opérande visant une instruction Dalvik. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GArchOperand *dalvik_build_target_operand(const GBinContent *content, vmpa2t *pos, MemoryDataSize size, SourceEndian endian, const vmpa2t *base) +{ + GArchOperand *result; /* Structure à retourner */ + phys_t offset; /* Emplacement de base */ + int8_t val8; /* Valeur sur 8 bits */ + int16_t val16; /* Valeur sur 16 bits */ + int32_t val32; /* Valeur sur 32 bits */ + bool test; /* Bilan de lecture */ + phys_t address; /* Adresse finale visée */ + + offset = get_phy_addr(base); + + switch (size) + { + case MDS_8_BITS_SIGNED: + test = g_binary_content_read_s8(content, pos, &val8); + address = offset + val8 * sizeof(uint16_t); + break; + case MDS_16_BITS_SIGNED: + test = g_binary_content_read_s16(content, pos, endian, &val16); + address = offset + val16 * sizeof(uint16_t); + break; + case MDS_32_BITS_SIGNED: + test = g_binary_content_read_s32(content, pos, endian, &val32); + address = offset + val32 * sizeof(uint16_t); + break; + default: + test = false; + break; + } + + if (!test) + return NULL; + + result = g_imm_operand_new_from_value(MDS_32_BITS, address); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction dont la définition est incomplète.[OUT]* +* format = format du fichier contenant le code. * +* content = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* low = position éventuelle des 4 bits visés. [OUT] * +* endian = boutisme lié au binaire accompagnant. * +* model = type d'opérandes attendues. * +* ... = éventuels arguments complémentaires. * +* * +* Description : Procède à la lecture d'opérandes pour une instruction. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool dalvik_read_basic_operands(GArchInstruction *instr, GDexFormat *format, const GBinContent *content, vmpa2t *pos, bool *low, SourceEndian endian, DalvikOperandType model, ...) +{ + bool result; /* Bilan à retourner */ + DalvikOperandID *types; /* Liste des chargements */ + DalvikOperandID *iter; /* Boucle de parcours */ + GArchOperand *op; /* Opérande unique décodé */ + uint16_t value16; /* Valeur sur 16 bits */ + DalvikPoolType pool_type; /* Type de table à manipuler */ + va_list ap; /* Arguments complémentaires */ + const vmpa2t *base; /* Base pour les sauts de code */ + + result = true; + + /* Choix des opérandes à charger */ + + switch (model & ~DALVIK_OP_EXTRA_MASK) + { + case DALVIK_OPT_10T: + types = (DalvikOperandID []) { + DOI_TARGET_8, + DOI_INVALID + }; + break; + + case DALVIK_OPT_11N: + types = (DalvikOperandID []) { + DOI_REGISTER_4, + DOI_IMMEDIATE_4, + DOI_INVALID + }; + break; + + case DALVIK_OPT_11X: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_INVALID + }; + break; + + case DALVIK_OPT_12X: + types = (DalvikOperandID []) { + DOI_REGISTER_4, + DOI_REGISTER_4, + DOI_INVALID + }; + break; + + case DALVIK_OPT_20T: + types = (DalvikOperandID []) { + DOI_TARGET_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_21C: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_POOL_CONST, + DOI_INVALID + }; + break; + + case DALVIK_OPT_21H: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_IMMEDIATE_H16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_21S: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_IMMEDIATE_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_21T: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_TARGET_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_22B: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_REGISTER_8, + DOI_IMMEDIATE_8, + DOI_INVALID + }; + break; + + case DALVIK_OPT_22C: + types = (DalvikOperandID []) { + DOI_REGISTER_4, + DOI_REGISTER_4, + DOI_POOL_CONST, + DOI_INVALID + }; + break; + + case DALVIK_OPT_22S: + types = (DalvikOperandID []) { + DOI_REGISTER_4, + DOI_REGISTER_4, + DOI_IMMEDIATE_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_22T: + types = (DalvikOperandID []) { + DOI_REGISTER_4, + DOI_REGISTER_4, + DOI_TARGET_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_22X: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_REGISTER_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_23X: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_REGISTER_8, + DOI_REGISTER_8, + DOI_INVALID + }; + break; + + case DALVIK_OPT_30T: + types = (DalvikOperandID []) { + DOI_TARGET_32, + DOI_INVALID + }; + break; + + case DALVIK_OPT_31C: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_POOL_CONST_WIDE, + DOI_INVALID + }; + break; + + case DALVIK_OPT_31I: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_IMMEDIATE_32, + DOI_INVALID + }; + break; + + case DALVIK_OPT_31T: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_TARGET_32, + DOI_INVALID + }; + break; + + case DALVIK_OPT_32X: + types = (DalvikOperandID []) { + DOI_REGISTER_16, + DOI_REGISTER_16, + DOI_INVALID + }; + break; + + case DALVIK_OPT_51L: + types = (DalvikOperandID []) { + DOI_REGISTER_8, + DOI_IMMEDIATE_64, + DOI_INVALID + }; + break; + + default: + types = (DalvikOperandID []) { + DOI_INVALID + }; + break; + + } + + /* Chargement des opérandes */ + + for (iter = types; *iter != G_TYPE_INVALID && result; iter++) + { + op = NULL; /* Nul de GCC */ + + switch (*iter) + { + case DOI_REGISTER_4: + op = g_dalvik_register_operand_new(content, pos, low, MDS_4_BITS, endian); + break; + + case DOI_REGISTER_8: + op = g_dalvik_register_operand_new(content, pos, NULL, MDS_8_BITS, endian); + break; + + case DOI_REGISTER_16: + op = g_dalvik_register_operand_new(content, pos, NULL, MDS_16_BITS, endian); + break; + + case DOI_IMMEDIATE_4: + op = _g_imm_operand_new_from_data(MDS_4_BITS, content, pos, low, endian); + break; + + case DOI_IMMEDIATE_8: + op = g_imm_operand_new_from_data(MDS_8_BITS, content, pos, endian); + break; + + case DOI_IMMEDIATE_16: + op = g_imm_operand_new_from_data(MDS_16_BITS, content, pos, endian); + break; + + case DOI_IMMEDIATE_32: + op = g_imm_operand_new_from_data(MDS_32_BITS, content, pos, endian); + break; + + case DOI_IMMEDIATE_64: + op = g_imm_operand_new_from_data(MDS_64_BITS, content, pos, endian); + break; + + case DOI_IMMEDIATE_H16: + result = g_binary_content_read_u16(content, pos, endian, &value16); + if (result) + op = g_imm_operand_new_from_value(MDS_32_BITS_SIGNED, ((uint32_t)value16) << 16); + break; + + case DOI_POOL_CONST: + pool_type = DALVIK_OP_GET_POOL(model); + op = g_dalvik_pool_operand_new(format, pool_type, content, pos, MDS_16_BITS, endian); + break; + + case DOI_POOL_CONST_WIDE: + pool_type = DALVIK_OP_GET_POOL(model); + op = g_dalvik_pool_operand_new(format, pool_type, content, pos, MDS_32_BITS, endian); + break; + + case DOI_TARGET_8: + va_start(ap, model); + base = va_arg(ap, const vmpa2t *); + op = dalvik_build_target_operand(content, pos, MDS_8_BITS_SIGNED, endian, base); + va_end(ap); + break; + + case DOI_TARGET_16: + va_start(ap, model); + base = va_arg(ap, const vmpa2t *); + op = dalvik_build_target_operand(content, pos, MDS_16_BITS_SIGNED, endian, base); + va_end(ap); + break; + + case DOI_TARGET_32: + va_start(ap, model); + base = va_arg(ap, const vmpa2t *); + op = dalvik_build_target_operand(content, pos, MDS_32_BITS_SIGNED, endian, base); + va_end(ap); + break; + + default: + op = NULL; + break; + + } + + if (op == NULL) result = false; + else g_arch_instruction_attach_extra_operand(instr, op); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction dont la définition est incomplète.[OUT]* +* format = format du fichier contenant le code. * +* content = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* low = position éventuelle des 4 bits visés. [OUT] * +* endian = boutisme lié au binaire accompagnant. * +* model = type d'opérandes attendues. * +* * +* Description : Procède à la lecture d'opérandes pour une instruction. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool dalvik_read_fixed_operands(GArchInstruction *instr, GDexFormat *format, const GBinContent *content, vmpa2t *pos, bool *low, SourceEndian endian, DalvikOperandType model) +{ + GArchOperand *opg; /* Opérande G décodé */ + uint8_t a; /* Nbre. de registres utilisés */ + GArchOperand *target; /* Opérande visant la table #1 */ + GArchOperand *args; /* Liste des opérandes */ + uint8_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande unique décodé */ + + opg = g_dalvik_register_operand_new(content, pos, low, MDS_4_BITS, endian); + + if (!g_binary_content_read_u4(content, pos, low, &a)) + goto err_va; + + if (a == 5 && opg == NULL) + goto err_no_opg; + + target = g_dalvik_pool_operand_new(format, DALVIK_OP_GET_POOL(model), content, pos, MDS_16_BITS, endian); + if (target == NULL) goto err_target; + + /* Mise en place des arguments */ + + args = g_dalvik_args_operand_new(); + + for (i = 0; i < MIN(a, 4); i++) + { + op = g_dalvik_register_operand_new(content, pos, low, MDS_4_BITS, endian); + if (op == NULL) goto err_registers; + + g_dalvik_args_operand_add(G_DALVIK_ARGS_OPERAND(args), op); + + } + + /* Consommation pleine et entière */ + + for (; i < 4; i++) + if (!g_binary_content_read_u4(content, pos, low, (uint8_t []) { 0 })) + goto err_padding; + + /* Rajout des éléments finaux déjà chargés */ + + if (a == 5) + g_dalvik_args_operand_add(G_DALVIK_ARGS_OPERAND(args), opg); + + else + { + if (opg != NULL) + g_object_unref(G_OBJECT(opg)); + } + + g_arch_instruction_attach_extra_operand(instr, args); + + /* Rajout de la cible */ + + g_arch_instruction_attach_extra_operand(instr, target); + + return true; + + err_padding: + + err_registers: + + g_object_unref(G_OBJECT(target)); + + err_target: + + if (opg != NULL) + g_object_unref(G_OBJECT(opg)); + + err_no_opg: + err_va: + + return false; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction dont la définition est incomplète.[OUT]* +* format = format du fichier contenant le code. * +* content = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* low = position éventuelle des 4 bits visés. [OUT] * +* endian = boutisme lié au binaire accompagnant. * +* model = type d'opérandes attendues. * +* * +* Description : Procède à la lecture d'opérandes pour une instruction. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool dalvik_read_variatic_operands(GArchInstruction *instr, GDexFormat *format, const GBinContent *content, vmpa2t *pos, bool *low, SourceEndian endian, DalvikOperandType model) +{ + uint8_t a; /* Nbre. de registres utilisés */ + uint16_t c; /* Indice de registre */ + GArchOperand *target; /* Opérande visant la table */ + GArchOperand *args; /* Liste des opérandes */ + uint8_t i; /* Boucle de parcours */ + GArchOperand *op; /* Opérande unique décodé */ + + if (!g_binary_content_read_u8(content, pos, &a)) + return false; + + target = g_dalvik_pool_operand_new(format, DALVIK_OP_GET_POOL(model), content, pos, MDS_16_BITS, endian); + if (target == NULL) return false; + + if (!g_binary_content_read_u16(content, pos, endian, &c)) + return false; + + /* Mise en place des arguments */ + + args = g_dalvik_args_operand_new(); + + for (i = 0; i < a; i++) + { + op = g_dalvik_register_operand_new_from_existing(g_dalvik_register_new(c + i)); + if (op == NULL) goto drvo_registers; + + g_dalvik_args_operand_add(G_DALVIK_ARGS_OPERAND(args), op); + + } + + g_arch_instruction_attach_extra_operand(instr, args); + + /* Rajout de la cible */ + + g_arch_instruction_attach_extra_operand(instr, target); + + return true; + + drvo_registers: + + g_object_unref(G_OBJECT(target)); + + return false; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction dont la définition est incomplète.[OUT]* +* format = format du fichier contenant le code. * +* content = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* endian = boutisme lié au binaire accompagnant. * +* model = type d'opérandes attendues. * +* * +* Description : Procède à la lecture d'opérandes pour une instruction. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool dalvik_read_operands(GArchInstruction *instr, GExeFormat *format, const GBinContent *content, vmpa2t *pos, SourceEndian endian, DalvikOperandType model) +{ + bool result; /* Bilan à retourner */ + GDexFormat *dformat; /* Autre version du format */ + bool low; /* Partie d'octets à lire */ +#ifndef NDEBUG + vmpa2t old; /* Position avant traitements */ +#endif + vmpa2t base; /* Base pour les sauts de code */ + vmpa2t *extra; /* Information complémentaire */ +#ifndef NDEBUG + phys_t expected; /* Consommation attendue */ + phys_t consumed; /* Consommation réelle */ +#endif + + result = true; + + dformat = G_DEX_FORMAT(format); + + low = true; + +#ifndef NDEBUG + + copy_vmpa(&old, pos); + +#endif + + /* Récupération de la base ? */ + + if (DALVIK_OP_GET_MNEMONIC(model) == 'T') + { + extra = &base; + + copy_vmpa(extra, pos); + deminish_vmpa(extra, 1); + + } + else extra = NULL; + + /* Bourrage : ØØ|op ? */ + + switch (model & ~DALVIK_OP_EXTRA_MASK) + { + case DALVIK_OPT_10X: + case DALVIK_OPT_20T: + case DALVIK_OPT_30T: + case DALVIK_OPT_32X: + result = g_binary_content_seek(content, pos, 1); + break; + + default: + break; + + } + + /* Décodage... */ + + switch (model & ~DALVIK_OP_EXTRA_MASK) + { + case DALVIK_OPT_10T: + case DALVIK_OPT_11N: + case DALVIK_OPT_11X: + case DALVIK_OPT_12X: + case DALVIK_OPT_20T: + case DALVIK_OPT_21C: + case DALVIK_OPT_21H: + case DALVIK_OPT_21S: + case DALVIK_OPT_21T: + case DALVIK_OPT_22B: + case DALVIK_OPT_22C: + case DALVIK_OPT_22S: + case DALVIK_OPT_22T: + case DALVIK_OPT_22X: + case DALVIK_OPT_23X: + case DALVIK_OPT_30T: + case DALVIK_OPT_31C: + case DALVIK_OPT_31I: + case DALVIK_OPT_31T: + case DALVIK_OPT_32X: + case DALVIK_OPT_51L: + result = dalvik_read_basic_operands(instr, dformat, content, pos, &low, endian, model, extra); + break; + + case DALVIK_OPT_35C: + result = dalvik_read_fixed_operands(instr, dformat, content, pos, &low, endian, model); + break; + + case DALVIK_OPT_3RC: + case DALVIK_OPT_3RMS: + case DALVIK_OPT_3RFS: + result = dalvik_read_variatic_operands(instr, dformat, content, pos, &low, endian, model); + break; + + default: + break; + + } + +#ifndef NDEBUG + + /* Vérification d'implémentation */ + + if (result) + { + expected = DALVIK_OP_GET_LEN(model) * 2; + consumed = 1 + compute_vmpa_diff(&old, pos); + + assert(consumed == expected); + + } + +#endif + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction dont la définition est incomplète. * +* * +* Description : Procède à la lecture d'opérandes pour une instruction. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void dalvik_mark_first_operand_as_written(GArchInstruction *instr) +{ + GArchOperand *operand; /* Première opérande visé */ + + operand = g_arch_instruction_get_operand(instr, 0); + + g_dalvik_register_operand_mark_as_written(G_DALVIK_REGISTER_OPERAND(operand)); + +} |