summaryrefslogtreecommitdiff
path: root/plugins/dalvik/operand.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dalvik/operand.c')
-rw-r--r--plugins/dalvik/operand.c752
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));
+
+}