summaryrefslogtreecommitdiff
path: root/plugins/dalvik/link.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dalvik/link.c')
-rw-r--r--plugins/dalvik/link.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/plugins/dalvik/link.c b/plugins/dalvik/link.c
new file mode 100644
index 0000000..ae7aa63
--- /dev/null
+++ b/plugins/dalvik/link.c
@@ -0,0 +1,322 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * link.c - édition des liens après la phase de désassemblage
+ *
+ * Copyright (C) 2016-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 "link.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+
+#include <i18n.h>
+#include <analysis/db/items/comment.h>
+#include <arch/target.h>
+#include <common/extstr.h>
+
+
+#include "pseudo/switch.h"
+
+
+
+/* Mémorisation des cas rencontrés */
+typedef struct _case_comment
+{
+ bool valid; /* Entrée utilisable ? */
+
+ vmpa2t handler; /* Position du code associé */
+
+ bool is_default; /* Gestion par défaut ? */
+ union
+ {
+ int32_t key; /* Clef unique */
+ int32_t *keys; /* Ensemble de clefs dynamique */
+ };
+
+ size_t count; /* Nombre de clefs conservées */
+
+} case_comment;
+
+
+/* REMME */
+#define COMMENT_LINE_SEP "\n"
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction ARMv7 à traiter. *
+* proc = représentation de l'architecture utilisée. *
+* context = contexte associé à la phase de désassemblage. *
+* format = acès aux données du binaire d'origine. *
+* *
+* Description : Etablit tous les liens liés à un embranchement compressé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
+{
+ GArchOperand *op; /* Opérande numérique en place */
+ bool defined; /* Adresse définie ? */
+ vmpa2t addr; /* Adresse de destination */
+ virt_t virt; /* Adresse virtuelle */
+ GArchInstruction *switch_ins; /* Instruction de branchements */
+ const mrange_t *range; /* Zone d'occupation */
+ const vmpa2t *start_addr; /* Adresse de référentiel */
+ const int32_t *keys; /* Conditions de sauts */
+ const int32_t *targets; /* Positions relatives liées */
+ uint16_t count; /* Taille de ces tableaux */
+ case_comment *comments; /* Mémorisation progressive */
+ vmpa2t def_addr; /* Traitement par défaut */
+ GArchInstruction *target; /* Ligne visée par la référence*/
+ case_comment *comment; /* Commentaire à éditer */
+ uint16_t i; /* Boucle de parcours #1 */
+ size_t j; /* Boucle de parcours #2 */
+ int32_t tmp; /* Sauvegarde temporaire */
+ char *msg; /* Indication à imprimer */
+ size_t k; /* Boucle de parcours #3 */
+ char *int_val; /* Valeur en chaîne de carac. */
+ GDbComment *item; /* Indication sur la condition */
+
+ g_arch_instruction_lock_operands(instr);
+
+ assert(_g_arch_instruction_count_operands(instr) == 2);
+
+ op = _g_arch_instruction_get_operand(instr, 1);
+
+ g_arch_instruction_unlock_operands(instr);
+
+ defined = false;
+
+ if (G_IS_TARGET_OPERAND(op))
+ {
+ g_target_operand_get_addr(G_TARGET_OPERAND(op), &addr);
+ defined = true;
+ }
+
+ else if (G_IS_IMM_OPERAND(op))
+ {
+ if (g_imm_operand_to_virt_t(G_IMM_OPERAND(op), &virt))
+ {
+ init_vmpa(&addr, VMPA_NO_PHYSICAL, virt);
+ defined = true;
+ }
+ }
+
+ if (defined)
+ {
+ switch_ins = g_arch_processor_find_instr_by_address(proc, &addr);
+
+ if (G_IS_DALVIK_SWITCH_INSTR(switch_ins))
+ {
+ range = g_arch_instruction_get_range(instr);
+
+ start_addr = get_mrange_addr(range);
+
+ /* Préparation de l'édition des commentaires */
+
+ count = g_dalvik_switch_get_data(G_DALVIK_SWITCH_INSTR(switch_ins), &keys, &targets);
+
+ comments = (case_comment *)calloc(1 + count, sizeof(case_comment));
+
+ /* Cas par défaut */
+
+ compute_mrange_end_addr(range, &def_addr);
+
+ target = g_arch_processor_find_instr_by_address(proc, &def_addr);
+
+ if (target != NULL)
+ {
+ comment = &comments[0];
+
+ comment->valid = true;
+
+ copy_vmpa(&comment->handler, &def_addr);
+
+ comment->is_default = true;
+
+ g_arch_instruction_link_with(instr, target, ILT_CASE_JUMP);
+
+ g_object_unref(G_OBJECT(target));
+
+ }
+
+ /* Autres cas */
+
+ for (i = 0; i < count; i++)
+ {
+ copy_vmpa(&addr, start_addr);
+ advance_vmpa(&addr, targets[i] * sizeof(uint16_t));
+
+ if (cmp_vmpa(&addr, &def_addr) == 0)
+ continue;
+
+ target = g_arch_processor_find_instr_by_address(proc, &addr);
+
+ if (target != NULL)
+ {
+ for (j = 0; j < (1 + count); j++)
+ {
+ if (!comments[j].valid)
+ break;
+
+ if (cmp_vmpa(&addr, &comments[j].handler) == 0)
+ break;
+
+ }
+
+ assert(j < (1 + count));
+
+ comment = &comments[j];
+
+ if (!comment->valid)
+ {
+ comment->valid = true;
+
+ copy_vmpa(&comment->handler, &addr);
+
+ comment->key = keys[i];
+ comment->count = 1;
+
+ }
+ else
+ {
+ if (comment->count == 0)
+ comment->key = keys[i];
+
+ if (comment->count == 1)
+ {
+ tmp = comment->key;
+
+ comment->keys = (int32_t *)calloc(2, sizeof(int32_t));
+
+ comment->keys[0] = tmp;
+ comment->keys[1] = keys[i];
+
+ comment->count = 2;
+
+ }
+
+ else
+ {
+ comment->count++;
+
+ comment->keys = (int32_t *)realloc(comment->keys, comment->count * sizeof(int32_t));
+
+ comment->keys[comment->count - 1] = keys[i];
+
+ }
+
+ }
+
+ g_arch_instruction_link_with(instr, target, ILT_CASE_JUMP);
+
+ g_object_unref(G_OBJECT(target));
+
+ }
+
+ }
+
+ /* Edition des commentaires et nettoyage */
+
+ for (j = 0; j < (1 + count); j++)
+ {
+ comment = &comments[j];
+
+ if (!comment->valid)
+ break;
+
+ switch (comment->count)
+ {
+ case 0:
+ msg = NULL;
+ break;
+
+ case 1:
+ asprintf(&msg, _("Case %d"), comment->key);
+ break;
+
+ default:
+
+ msg = NULL;
+
+ /**
+ * Les spécifications indiquent que les clefs sont triées.
+ * Donc nul besoin de s'occuper de leur ordre ici.
+ */
+
+ for (k = 0; k < comment->count; k++)
+ {
+ if (k > 0)
+ /* FIXME : encapsuler ! */
+ msg = stradd(msg, COMMENT_LINE_SEP);
+
+ asprintf(&int_val, _("Case %d:"), comment->keys[k]);
+ msg = stradd(msg, int_val);
+ free(int_val);
+
+ }
+
+ break;
+
+ }
+
+ if (comment->is_default)
+ {
+ if (msg == NULL)
+ msg = strdup(_("Defaut case:"));
+ else
+ {
+ /* FIXME : encapsuler ! */
+ msg = stradd(msg, COMMENT_LINE_SEP);
+ msg = stradd(msg, _("Defaut case"));
+ }
+
+ }
+
+ item = g_db_comment_new_area(&comment->handler, BLF_NONE, msg, true);
+
+ g_db_item_set_volatile(G_DB_ITEM(item), true);
+ g_proc_context_add_db_item(context, G_DB_ITEM(item));
+
+ free(msg);
+
+ if (comment->count > 1)
+ free(comment->keys);
+
+ }
+
+ free(comments);
+
+ }
+
+ if (switch_ins != NULL)
+ g_object_unref(G_OBJECT(switch_ins));
+
+ }
+
+}