diff options
Diffstat (limited to 'plugins/dalvik/link.c')
-rw-r--r-- | plugins/dalvik/link.c | 322 |
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)); + + } + +} |