From 57d7eff57c20e75aaa4ccd34f1d9d733e12bb232 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 30 Dec 2014 08:25:05 +0000 Subject: Tracked each binary area during the disassembling process and tried to follow the execution flow. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@445 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 38 ++ src/analysis/disass/Makefile.am | 1 + src/analysis/disass/area.c | 1289 +++++++++++++++++++++++++++++++++++++++ src/analysis/disass/area.h | 96 +++ src/analysis/disass/fetch.c | 552 ++--------------- src/arch/arm/context.c | 44 ++ src/arch/arm/processor.c | 28 + src/arch/arm/v7/link.c | 7 + src/arch/context-int.h | 6 + src/arch/context.c | 26 +- src/arch/context.h | 4 +- src/arch/vmpa.c | 31 + src/arch/vmpa.h | 3 + src/gtkext/gtkextstatusbar.h | 13 + 14 files changed, 1647 insertions(+), 491 deletions(-) create mode 100644 src/analysis/disass/area.c create mode 100644 src/analysis/disass/area.h diff --git a/ChangeLog b/ChangeLog index 9f1a780..37e210a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,41 @@ +14-12-30 Cyrille Bagard + + * src/analysis/disass/area.c: + * src/analysis/disass/area.h: + New entries: track each binary area during the disassembling process + and try to follow the execution flow. + + * src/analysis/disass/fetch.c: + Clean and update the code. + + * src/analysis/disass/Makefile.am: + Add the 'area.[ch]' files to libanalysisdisass_la_SOURCES. + + * src/arch/arm/context.c: + Handle entry points for the disassembling process. + + * src/arch/arm/processor.c: + Provide a context for the ARM processor. + + * src/arch/arm/v7/link.c: + Add debug code. + + * src/arch/context.c: + Handle entry points for the disassembling process. + + * src/arch/context.h: + Typo. + + * src/arch/context-int.h: + Handle entry points for the disassembling process. + + * src/arch/vmpa.c: + * src/arch/vmpa.h: + Allow to check if a range contains another range. + + * src/gtkext/gtkextstatusbar.h: + Prepare some new extensions. + 14-12-25 Cyrille Bagard * src/analysis/disass/fetch.c: diff --git a/src/analysis/disass/Makefile.am b/src/analysis/disass/Makefile.am index 65ed9c9..54b0fa5 100644 --- a/src/analysis/disass/Makefile.am +++ b/src/analysis/disass/Makefile.am @@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libanalysisdisass.la libanalysisdisass_la_SOURCES = \ + area.h area.c \ disassembler.h disassembler.c \ fetch.h fetch.c \ limit.h limit.c \ diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c new file mode 100644 index 0000000..9d8dcf5 --- /dev/null +++ b/src/analysis/disass/area.c @@ -0,0 +1,1289 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * area.c - définition et manipulation des aires à désassembler + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * 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 . + */ + + +#include "area.h" + + +#include + + + +#if 0 + + +/* Zone mémoire bien bornée */ +struct _mem_area +{ + mrange_t range; /* Couverture de la zone */ + + unsigned long *processed; /* Octets traités dans la zone */ + + bool has_sym; /* Représentation via symbole ?*/ + + union + { + bool exec; /* Zone exécutable ? */ + GBinSymbol *symbol; /* Symbole associé à la zone */ + }; + +}; + + +#endif + + + +/* Initialise une aire de données à partir d'une adresse donnée. */ +static void init_mem_area_from_addr(mem_area *, const vmpa2t *, phys_t); + +/* Initialise une aire de données à partir d'un espace donné. */ +static void init_mem_area_from_range(mem_area *, const mrange_t *); + +/* Copie certaines propriétés d'une aire à une autre. */ +static void copy_mem_area_properties(mem_area *, const mem_area *); + +/* Libère d'une aire de données les ressources allouées. */ +static void fini_mem_area(mem_area *); + +/* Indique si une zone donnée est intégralement vierge ou non. */ +static bool is_range_blank_in_mem_area(mem_area *, phys_t, phys_t, GArchInstruction *); + +/* Marque une série d'octets comme ayant été traités. */ +static bool mark_range_in_mem_area_as_processed(mem_area *, phys_t, phys_t, GArchInstruction *); + + + + + +/* Procède au désassemblage d'un contenu binaire non exécutable. */ +static void load_data_from_mem_area(mem_area *, mem_area *, size_t, const GLoadedBinary *, GProcContext *, const vmpa2t *, status_info *); + +/* S'assure qu'une aire contient toutes ses instructions. */ +static void fill_mem_area(mem_area *, mem_area *, size_t, const GLoadedBinary *, GProcContext *, status_info *); + + + +/* Rassemble les instructions conservées dans une zone donnée. */ +static GArchInstruction *get_instructions_from_mem_area(const mem_area *); + + + + +/////////////////////////////// + + + +/* Manipule la cartographie des octets traités d'une zone. */ +typedef bool (* visit_bytes_map_fc) (mem_area *, phys_t, phys_t, GArchInstruction *); + + + + + +/* Manipule la cartographie des octets d'aires de données. */ +static bool handle_bytes_map_in_mem_area(mem_area *, size_t, const mrange_t *, GArchInstruction *, visit_bytes_map_fc); + +/* Indique si une zone donnée est intégralement vierge ou non. */ +static bool is_range_blank_in_mem_areas(mem_area *, size_t, const mrange_t *); + +/* Marque une série d'octets comme ayant été traités. */ +static bool mark_range_in_mem_areas_as_processed(mem_area *, size_t, GArchInstruction *); + + + + + + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à initialiser. * +* addr = adresse de départ de l'espace à mettre en place. * +* len = longueur de l'espace à créer. * +* * +* Description : Initialise une aire de données à partir d'une adresse donnée.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_mem_area_from_addr(mem_area *area, const vmpa2t *addr, phys_t len) +{ + size_t requested; /* Nombre de mots à allouer */ + + init_mrange(&area->range, addr, len); + + requested = len / sizeof(unsigned long); + if (len % sizeof(unsigned long) != 0) requested++; + + area->processed = (unsigned long *)calloc(requested, sizeof(unsigned long)); + area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *)); + +} + + +/****************************************************************************** +* * +* Paramètres : dest = aire délimitée représentant des données. * +* src = aire délimitée contenant les informations à copier. * +* * +* Description : Copie certaines propriétés d'une aire à une autre. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void copy_mem_area_properties(mem_area *dest, const mem_area *src) +{ + dest->has_sym = src->has_sym; + + if (src->has_sym) + dest->symbol = src->symbol; + else + dest->exec = src->exec; + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à initialiser. * +* range = espace limitant à associer à l'aire de données. * +* * +* Description : Initialise une aire de données à partir d'un espace donné. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_mem_area_from_range(mem_area *area, const mrange_t *range) +{ + phys_t len; /* Taille de la zone courante */ + size_t requested; /* Nombre de mots à allouer */ + + copy_mrange(&area->range, range); + + len = get_mrange_length(range); + + requested = len / sizeof(unsigned long); + if (len % sizeof(unsigned long) != 0) requested++; + + area->processed = (unsigned long *)calloc(requested, sizeof(unsigned long)); + area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *)); + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à nettoyer en mémoire. * +* * +* Description : Libère d'une aire de données les ressources allouées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void fini_mem_area(mem_area *area) +{ + free(area->processed); + + if (area->has_sym) + g_object_unref(area->symbol); + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* start = début de la zone à manipuler. * +* len = taille de cette même aire de données. * +* instr = instruction à mémoriser pour la suite. * +* * +* Description : Indique si une zone donnée est intégralement vierge ou non. * +* * +* Retour : true si l'aire visée n'a jamais été traitée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool is_range_blank_in_mem_area(mem_area *area, phys_t start, phys_t len, GArchInstruction *instr) +{ + bool result; /* Bilan à renvoyer */ + phys_t max; /* Point d'arrêt de la boucle */ + phys_t i; /* Boucle de parcours */ + size_t index; /* Cellule de tableau visée */ + unsigned int remaining; /* Nombre de bits restants */ + + max = start + len; + + assert(max <= get_mrange_length(&area->range)); + + result = true; + + for (i = start; i < max && result; i++) + { + index = i / (sizeof(unsigned long) * 8); + remaining = i % (sizeof(unsigned long) * 8); + + result &= ((area->processed[index] & (1ul << remaining)) == 0); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* start = début de la zone à manipuler. * +* len = taille de cette même aire de données. * +* instr = instruction à mémoriser pour la suite. * +* * +* Description : Marque une série d'octets comme ayant été traités. * +* * +* Retour : true. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool mark_range_in_mem_area_as_processed(mem_area *area, phys_t start, phys_t len, GArchInstruction *instr) +{ + phys_t max; /* Point d'arrêt de la boucle */ + phys_t i; /* Boucle de parcours */ + size_t index; /* Cellule de tableau visée */ + unsigned int remaining; /* Nombre de bits restants */ + + max = start + len; + + assert(max <= get_mrange_length(&area->range)); + + for (i = start; i < max; i++) + { + index = i / (sizeof(unsigned long) * 8); + remaining = i % (sizeof(unsigned long) * 8); + + area->processed[index] |= (1ul << remaining); + + } + + area->instructions[start] = instr; + + return true; + +} + + + + + + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* binary = représentation de binaire chargé. * +* ctx = contexte offert en soutien à un désassemblage. * +* start = démarrage de l'exécution au sein de la zone. * +* info = indications quant à la progression à afficher. * +* * +* Description : Procède au désassemblage d'un contenu binaire exécutable. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void load_code_from_mem_area(mem_area *area, mem_area *list, size_t count, const GLoadedBinary *binary, GProcContext *ctx, const vmpa2t *start, status_info *info) +{ + + + GBinFormat *format; /* Format du fichier binaire */ + GArchProcessor *proc; /* Architecture du binaire */ + off_t bin_length; /* Taille des données à lire */ + bin_t *bin_data; /* Données binaires à lire */ + + phys_t diff; /* Volume de données traité */ + phys_t alen; /* Taille de l'aire utilisée */ + + phys_t i; /* Boucle de parcours */ + + + vmpa2t pos; /* Boucle de parcours */ + vmpa2t prev; /* Boucle de parcours */ + + GArchInstruction *instr; /* Instruction décodée */ + + + + mrange_t range; /* Couverture de l'instruction */ + + + + /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */ + + init_mrange(&range, start, 1); + if (!is_range_blank_in_mem_areas(list, count, &range)) printf("CODE OK!!\n");; + if (!is_range_blank_in_mem_areas(list, count, &range)) return; + + /* Récupération des informations de base */ + + format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); + proc = get_arch_processor_from_format(G_EXE_FORMAT(format)); + bin_data = g_loaded_binary_get_data(binary, &bin_length); + + diff = compute_vmpa_diff(get_mrange_addr(&area->range), start); + alen = get_mrange_length(&area->range); + + /** + * On copie la position courante à partir de l'aire plutôt que du + * point de départ car cette première est potentiellement plus complète. + */ + + copy_vmpa(&pos, get_mrange_addr(&area->range)); + advance_vmpa(&pos, diff); + + printf(" [%p] CODE start @ %u (len=%u)\n", area, (unsigned int)diff, (unsigned int)alen); + + for (i = diff; i < alen; i += diff) + { + //il y a eu un point d'entrée... -> STOP + + /* Décodage d'une nouvelle instruction */ + + copy_vmpa(&prev, &pos); + + instr = g_arch_processor_disassemble(proc, ctx, bin_data, &pos, bin_length); + + //printf(" @ 0x%08x -> %p\n", (uint32_t)get_virt_addr(&prev), instr); + + if (instr == NULL) break; + + + + + /* Enregistrement des positions et adresses */ + + diff = compute_vmpa_diff(&prev, &pos); + + init_mrange(&range, &prev, diff); + + g_arch_instruction_set_range(instr, &range); + + /* Eventuel renvoi vers d'autres adresses */ + + g_arch_instruction_call_hook(instr, IPH_LINK, ctx, format); + + /* Progression dans les traitements */ + + mark_range_in_mem_areas_as_processed(list, count, instr); + + //done += (new_phy - old_phy); + //gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / sum); + + + + + + + + + } + + + printf("\n"); + + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* binary = représentation de binaire chargé. * +* ctx = contexte offert en soutien à un désassemblage. * +* start = démarrage de l'exécution au sein de la zone. * +* info = indications quant à la progression à afficher. * +* * +* Description : Procède au désassemblage d'un contenu binaire non exécutable.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void load_data_from_mem_area(mem_area *area, mem_area *list, size_t count, const GLoadedBinary *binary, GProcContext *ctx, const vmpa2t *start, status_info *info) +{ + GBinFormat *format; /* Format du fichier binaire */ + GArchProcessor *proc; /* Architecture du binaire */ + SourceEndian endianness; /* Boutisme de cette machine */ + off_t bin_length; /* Taille des données à lire */ + bin_t *bin_data; /* Données binaires à lire */ + phys_t diff; /* Volume de données traité */ + phys_t alen; /* Taille de l'aire utilisée */ + phys_t i; /* Boucle de parcours */ + vmpa2t pos; /* Boucle de parcours */ + vmpa2t prev; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction décodée */ + mrange_t range; /* Couverture de l'instruction */ + + /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */ + + init_mrange(&range, start, 1); + if (!is_range_blank_in_mem_areas(list, count, &range)) printf("DATA OK!!\n");; + if (!is_range_blank_in_mem_areas(list, count, &range)) return; + + /* Récupération des informations de base */ + + format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); + proc = get_arch_processor_from_format(G_EXE_FORMAT(format)); + endianness = g_arch_processor_get_endianness(proc); + bin_data = g_loaded_binary_get_data(binary, &bin_length); + + diff = compute_vmpa_diff(get_mrange_addr(&area->range), start); + alen = get_mrange_length(&area->range); + + /** + * On copie la position courante à partir de l'aire plutôt que du + * point de départ car cette première est potentiellement plus complète. + */ + + copy_vmpa(&pos, get_mrange_addr(&area->range)); + advance_vmpa(&pos, diff); + + printf(" [%p] DATA start @ 0x%08x -> %u (len=%u)\n", + area, (unsigned int)get_phy_addr(&pos), (unsigned int)diff, (unsigned int)alen); + + for (i = diff; i < alen; i += diff) + { + /* Décodage d'une nouvelle instruction, sur mesure */ + + copy_vmpa(&prev, &pos); + + instr = NULL; + + if (instr == NULL && (i + 4) <= alen) + { + init_mrange(&range, &pos, 4); + + if (is_range_blank_in_mem_areas(list, count, &range)) + instr = g_raw_instruction_new_array(bin_data, MDS_32_BITS, 1, &pos, bin_length, endianness); + + } + + if (instr == NULL && (i + 2) <= alen) + { + copy_vmpa(&pos, &prev); + init_mrange(&range, &pos, 2); + + if (is_range_blank_in_mem_areas(list, count, &range)) + instr = g_raw_instruction_new_array(bin_data, MDS_16_BITS, 1, &pos, bin_length, endianness); + + } + + if (instr == NULL/* && (i + 1) <= alen*/) + { + copy_vmpa(&pos, &prev); + init_mrange(&range, &pos, 1); + + if (is_range_blank_in_mem_areas(list, count, &range)) + instr = g_raw_instruction_new_array(bin_data, MDS_8_BITS, 1, &pos, bin_length, endianness); + else + { + printf(" break !! 0x%08x\n", + (unsigned int)get_phy_addr(&pos)); + assert(0); + break; + } + + } + + assert(instr != NULL); + + /* Enregistrement des positions et adresses */ + + diff = compute_vmpa_diff(&prev, &pos); + + printf(" decomp @ 0x%08x -> ++ %u\n", + (unsigned int)get_phy_addr(&pos), (unsigned int)diff); + + init_mrange(&range, &prev, diff); + + g_arch_instruction_set_range(instr, &range); + + /* Progression dans les traitements */ + + mark_range_in_mem_areas_as_processed(list, count, instr); + + assert(!is_range_blank_in_mem_areas(list, count, &range)); + + //done += (new_phy - old_phy); + //gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / sum); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* binary = représentation de binaire chargé. * +* ctx = contexte offert en soutien à un désassemblage. * +* info = indications quant à la progression à afficher. * +* * +* Description : S'assure qu'une aire contient toutes ses instructions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void fill_mem_area(mem_area *area, mem_area *list, size_t count, const GLoadedBinary *binary, GProcContext *ctx, status_info *info) +{ + phys_t len; /* Taille de la zone à remplir */ + phys_t i; /* Boucle de parcours */ + vmpa2t start; /* Adresse de départ de combles*/ + + + printf(" === FILLING | 0x%08x (%u)...\n", + (unsigned int)get_phy_addr(get_mrange_addr(&area->range)), + (unsigned int)get_phy_addr(get_mrange_addr(&area->range))); + + + /* Les symboles se doivent d'être indépendants ! */ + if (area->has_sym) return; + + len = get_mrange_length(&area->range); + + for (i = 0; i < len; i++) + { + if (is_range_blank_in_mem_area(area, i, 1, NULL)) + { + copy_vmpa(&start, get_mrange_addr(&area->range)); + advance_vmpa(&start, i); + + if (area->exec) + load_code_from_mem_area(area, list, count, binary, ctx, &start, info); + + if (is_range_blank_in_mem_area(area, i, 1, NULL)) + load_data_from_mem_area(area, list, count, binary, ctx, &start, info); + + } + + if (is_range_blank_in_mem_area(area, i, 1, NULL)) + printf(" [%p] error with %u\n", area, (unsigned int)i); + + assert(!is_range_blank_in_mem_area(area, i, 1, NULL)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* * +* Description : Rassemble les instructions conservées dans une zone donnée. * +* * +* Retour : Liste d'instructions prêtes à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GArchInstruction *get_instructions_from_mem_area(const mem_area *area) +{ + GArchInstruction *result; /* Liste d'instr. à renvoyer */ + phys_t len; /* Nombre d'instructions au max*/ + phys_t i; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction décodée */ + + result = NULL; + + if (area->has_sym) + switch (g_binary_symbol_get_target_type(area->symbol)) + { + case STP_DATA: + result = g_binary_symbol_get_instruction(area->symbol); + g_object_ref(G_OBJECT(result)); + break; + + case STP_ROUTINE: + assert(false); + //instr = load_code_binary(binary, start, end, statusbar, id); + // + fill + break; + + default: + assert(false); + break; + + } + + else + { + len = get_mrange_length(&area->range); + + for (i = 0; i < len; i++) + { + instr = area->instructions[i]; + + if (instr != NULL) + { + g_object_ref(G_OBJECT(instr)); + g_arch_instruction_add_to_list(&result, instr); + } + + } + + } + + return result; + +} + + + + + + + + + + + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : format = format d'un exécutable à consulter. * +* bin_length = quantité d'octets à traiter au total. * +* count = nombre de zones mises en place. [OUT] * +* * +* Description : Détermine une liste de zones contigües à traiter. * +* * +* Retour : Liste de zones mémoire à libérer après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +mem_area *compute_memory_areas(GExeFormat *format, phys_t bin_length, size_t *count) +{ + mem_area *result; /* Liste à renvoyer */ + mrange_t *exe_ranges; /* Liste de zones exécutables */ + size_t exe_count; /* Nombre de ces zones */ + GBinSymbol **symbols; /* Symboles à représenter */ + size_t sym_count; /* Qté de symboles présents */ + vmpa2t *last; /* Dernière bordure rencontrée */ + size_t i; /* Boucle de parcours #1 */ + vmpa2t *border; /* Nouvelle bordure rencontrée */ + mem_area *area; /* Zone avec valeurs à éditer */ + vmpa2t tmp; /* Stockage temporaire */ + + + GBinPortion **portions; /* Morceaux d'encadrement */ + size_t portions_count; /* Taille de cette liste */ + const vmpa2t *portion_start; /* Point de départ de portion */ + + size_t j; /* Boucle de parcours #2 */ + const mrange_t *range; /* Couverture d'un symbole */ + const vmpa2t *start; /* Point de départ du symbole */ + phys_t length; /* Taille de ce même symbole */ + bool included; /* Inclusion dans une zone ? */ + mem_area orig; /* Copie de la zone réduite */ + phys_t old_length; /* Taille de zone originelle */ + phys_t new_length; /* Nouvelle taille déterminée */ + size_t next; /* Indice de zone suivante */ + + result = NULL; + *count = 0; + + /** + * Le parcours n'est valide que si les listes, symboles et zones exécutables, + * sont triées ! + */ + + exe_ranges = g_exe_format_get_x_ranges(format, &exe_count); + + symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count); + + + + + + + for (i = 0; i < exe_count; i++) + { + printf(" (init) AREA %zu :: 0x%08x + %u\n", + i, + (unsigned int)get_phy_addr(get_mrange_addr(&exe_ranges[i])), + (unsigned int)get_mrange_length(&exe_ranges[i])); + + } + + + printf("----------------\n"); + + + + /* Première étape : on comble les trous ! */ + + last = make_vmpa(0, VMPA_NO_VIRTUAL); + + for (i = 0; i < exe_count; i++) + { + border = get_mrange_addr(&exe_ranges[i]); + + /* Zone tampon à constituer */ + + if (cmp_vmpa_by_phy(last, border) < 0) + { + result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); + + area = &result[*count - 1]; + + init_mem_area_from_addr(area, last, compute_vmpa_diff(last, border)); + area->has_sym = false; + area->exec = false; + + } + + /* Insertion d'une zone exécutable déjà définie */ + + result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); + + area = &result[*count - 1]; + + init_mem_area_from_range(area, &exe_ranges[i]); + area->has_sym = false; + area->exec = true; + + /* Avancée du curseur */ + + copy_vmpa(last, border); + + advance_vmpa(last, get_mrange_length(&exe_ranges[i])); + + } + + delete_vmpa(last); + + /* Extension finale complémentaire ? */ + + area = &result[*count - 1]; + + copy_vmpa(&tmp, get_mrange_addr(&area->range)); + advance_vmpa(&tmp, get_mrange_length(&area->range)); + + if (get_phy_addr(&tmp) < bin_length) + { + result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); + + area = &result[*count - 1]; + + init_mem_area_from_addr(area, &tmp, bin_length - get_phy_addr(&tmp)); + area->has_sym = false; + area->exec = false; + + } + + /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */ + + + + for (i = 0; i < *count; i++) + { + printf(" (fini) AREA %zu :: 0x%08x + %u\n", + i, + (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)), + (unsigned int)get_mrange_length(&result[i].range)); + + } + + printf("--------------------\n"); + + portions = g_exe_format_get_portions_at_level(format, -1, &portions_count); + + + for (i = 1; i < portions_count; i++) + { + portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i])); + + for (j = 0; j < *count; j++) + { + area = &result[j]; + + if (!mrange_contains_addr(&area->range, portion_start)) + continue; + + /* Si le déccoupage actuel ne correspond pas au besoin des portions... */ + if (cmp_vmpa(get_mrange_addr(&area->range), portion_start) != 0) + { + fini_mem_area(&result[j]); + + result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); + + memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area)); + + copy_mem_area_properties(&result[j + 1], &result[j]); + + /* Première moitié */ + + area = &result[j]; + + copy_vmpa(&tmp, get_mrange_addr(&area->range)); + length = get_mrange_length(&area->range); + + init_mem_area_from_addr(area, &tmp, compute_vmpa_diff(&tmp, portion_start)); + + /* Seconde moitié */ + + length -= get_mrange_length(&area->range); + + area = &result[j + 1]; + + init_mem_area_from_addr(area, portion_start, length); + + } + + j = *count; + + } + + } + + + + + + + for (i = 0; i < *count; i++) + { + printf(" (sect) AREA %zu :: 0x%08x + %u\n", + i, + (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)), + (unsigned int)get_mrange_length(&result[i].range)); + + } + + + //exit(0); + + + + /* Troisième étape : on insère les symboles existants */ + + j = 0; + +#define SKIP_EMPTY_SYMBOLS \ + for (; j < sym_count; j++) \ + { \ + range = g_binary_symbol_get_range(symbols[j]); \ + \ + length = get_mrange_length(range); \ + if (length > 0) break; \ + \ + } \ + + SKIP_EMPTY_SYMBOLS + + for (i = 0; i < *count && j < sym_count; i++) + { + range = g_binary_symbol_get_range(symbols[j]); + + start = get_mrange_addr(range); + length = get_mrange_length(range); + + /* Si un découpage s'impose... */ + + if (mrange_contains_addr(&result[i].range, start)) + { + copy_vmpa(&tmp, start); + advance_vmpa(&tmp, length); + + included = mrange_contains_addr(&result[i].range, &tmp); + + memcpy(&orig, &result[i], sizeof(mem_area)); + + fini_mem_area(&orig); + + /* Réduction de la zone de départ */ + + copy_vmpa(&tmp, get_mrange_addr(&result[i].range)); + old_length = get_mrange_length(&result[i].range); + + new_length = compute_vmpa_diff(get_mrange_addr(&result[i].range), start); + + if (new_length == 0) + { + memmove(&result[i], &result[i + 1], (*count - i - 1) * sizeof(mem_area)); + + (*count)--; + next = i; + + } + else + { + init_mem_area_from_addr(&result[i], &tmp, new_length); + next = i + 1; + } + + /* Insertion de la zone du symbole */ + + result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); + + memmove(&result[next + 1], &result[next], (*count - next - 1) * sizeof(mem_area)); + + area = &result[next]; + + init_mem_area_from_range(area, range); + + area->has_sym = true; + area->symbol = symbols[j]; + + /* Jointure finale... */ + + if (included) + { + /* Simple extension pour rattraper la fin originelle */ + + if ((old_length - new_length - length) > 0) + { + result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); + + memmove(&result[next + 2], &result[next + 1], (*count - next - 2) * sizeof(mem_area)); + + area = &result[next + 1]; + + copy_vmpa(&tmp, start); + advance_vmpa(&tmp, length); + + init_mem_area_from_addr(area, &tmp, old_length - new_length - length); + + copy_mem_area_properties(area, &orig); + + } + + i = next; + + } + else + { + /* Suppression des éventuelles zones totalement recouvertes */ + + + + /* Réduction de la zone d'arrivée */ + + + } + + + + + + j++; + + SKIP_EMPTY_SYMBOLS + + } + + } + + + + //free + + //exit(0); + + return result; + +} + + + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : list = listes de zones utable à consulter. * +* count = nombre de zones mises en place. * +* addr = adresse à retrouver dans les aires présentes. * +* * +* Description : Détermine une liste de zones contigües à traiter. * +* * +* Retour : Liste de zones mémoire à libérer après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +mem_area *find_memory_area_by_addr(mem_area *list, size_t count, const vmpa2t *addr) +{ + mem_area *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < count && result == NULL; i++) + if (mrange_contains_addr(&list[i].range, addr)) + result = &list[i]; + + return result; + +} + + + + + + + +/****************************************************************************** +* * +* Paramètres : list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* range = aire des octets à manipuler. * +* visitor = fonction opérationnelle finale à appeler. * +* * +* Description : Manipule la cartographie des octets d'aires de données. * +* * +* Retour : valeur retournée par le visiteur, voire false si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool handle_bytes_map_in_mem_area(mem_area *list, size_t count, const mrange_t *range, GArchInstruction *instr, visit_bytes_map_fc visitor) +{ + bool result; /* Bilan à retourner */ + mem_area *area; /* Aire à traiter trouvée */ + phys_t offset; /* Point de départ dans l'aire */ + phys_t remaining; /* Quantité restant à traiter */ + phys_t processed; /* Quantité traitée */ + vmpa2t start; /* Point de départ suivant */ + + result = false; + + area = find_memory_area_by_addr(list, count, get_mrange_addr(range)); + if (area == NULL) printf("NOT FOUND!\n"); + if (area == NULL) return false; + + offset = compute_vmpa_diff(get_mrange_addr(&area->range), get_mrange_addr(range)); + remaining = get_mrange_length(range); + + /* Traitement intégral dans la zone trouvée */ + + if ((offset + remaining) <= get_mrange_length(&area->range)) + result = visitor(area, offset, remaining, instr); + + else + { + assert(0); + + /* Traitement de la fin de la première aire */ + + processed = get_mrange_length(&area->range) - offset; + + result = visitor(area, offset, processed, instr); + + /* Traitement des zones adjacentes suivantes */ + + copy_vmpa(&start, get_mrange_addr(range)); + + for (remaining -= processed; remaining > 0 && result; remaining -= processed) + { + advance_vmpa(&start, processed); + + area = find_memory_area_by_addr(list, count, &start); + if (area == NULL) + { + result = false; + break; + } + + processed = get_mrange_length(&area->range); + if (remaining < processed) processed = remaining; + + result = visitor(area, 0, processed, instr); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* range = aire des octets à manipuler. * +* * +* Description : Indique si une zone donnée est intégralement vierge ou non. * +* * +* Retour : true si l'aire visée n'a jamais été traitée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool is_range_blank_in_mem_areas(mem_area *list, size_t count, const mrange_t *range) +{ + return handle_bytes_map_in_mem_area(list, count, + range, NULL, + is_range_blank_in_mem_area); + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* instr = instruction désassemblée à conserver en mémoire. * +* * +* Description : Marque une série d'octets comme ayant été traités. * +* * +* Retour : true. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool mark_range_in_mem_areas_as_processed(mem_area *list, size_t count, GArchInstruction *instr) +{ + return handle_bytes_map_in_mem_area(list, count, + g_arch_instruction_get_range(instr), instr, + mark_range_in_mem_area_as_processed); + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* binary = représentation de binaire chargé. * +* ctx = contexte offert en soutien à un désassemblage. * +* info = indications quant à la progression à afficher. * +* * +* Description : S'assure que l'ensemble des aires est entièrement décodé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void ensure_all_mem_areas_are_filled(mem_area *list, size_t count, const GLoadedBinary *binary, GProcContext *ctx, status_info *info) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < count; i++) + fill_mem_area(&list[i], list, count, binary, ctx, info); + +} + + +/****************************************************************************** +* * +* Paramètres : areas = série d'aires représentant à contenu à parcourir. * +* count = nombre de ces zones présentes. * +* * +* Description : Rassemble les instructions conservées dans des zones données.* +* * +* Retour : Liste d'instructions prêtes à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchInstruction *collect_instructions_from_mem_areas(mem_area *list, size_t count) +{ + GArchInstruction *result; /* Liste d'instr. à renvoyer */ + size_t i; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction(s) à insérer */ + + result = NULL; + + for (i = 0; i < count; i++) + { + instr = get_instructions_from_mem_area(&list[i]); + g_arch_instruction_merge_lists(&result, &instr); + } + + return result; + +} diff --git a/src/analysis/disass/area.h b/src/analysis/disass/area.h new file mode 100644 index 0000000..58539ca --- /dev/null +++ b/src/analysis/disass/area.h @@ -0,0 +1,96 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * area.h - prototypes pour la définition et la manipulation des aires à désassembler + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * 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 . + */ + + +#ifndef _ANALYSIS_DISASS_AREA_H +#define _ANALYSIS_DISASS_AREA_H + + +#include "../binary.h" +#include "../../format/executable.h" +#include "../../gtkext/gtkextstatusbar.h" + + +////// +#include "../../arch/raw.h" +#include "../../arch/instruction.h" + + + +/* Zone mémoire bien bornée */ +typedef struct _mem_area +{ + mrange_t range; /* Couverture de la zone */ + + unsigned long *processed; /* Octets traités dans la zone */ + GArchInstruction **instructions; /* Instructions en place */ + + bool has_sym; /* Représentation via symbole ?*/ + + union + { + bool exec; /* Zone exécutable ? */ + GBinSymbol *symbol; /* Symbole associé à la zone */ + }; + +} mem_area; + + + + +/* Zone mémoire bien bornée */ +//typedef struct _mem_area mem_area; + + + + +/* Procède au désassemblage d'un contenu binaire exécutable. */ +void load_code_from_mem_area(mem_area *, mem_area *, size_t, const GLoadedBinary *, GProcContext *, const vmpa2t *, status_info *); + + + +/* Détermine une liste de zones contigües à traiter. */ +mem_area *compute_memory_areas(GExeFormat *, phys_t, size_t *); + + + + + + + + + +/* Détermine une liste de zones contigües à traiter. */ +mem_area *find_memory_area_by_addr(mem_area *, size_t, const vmpa2t *); + + + + +/* S'assure que l'ensemble des aires est entièrement décodé. */ +void ensure_all_mem_areas_are_filled(mem_area *, size_t, const GLoadedBinary *, GProcContext *, status_info *); + +/* Rassemble les instructions conservées dans des zones données. */ +GArchInstruction *collect_instructions_from_mem_areas(mem_area *, size_t); + + + +#endif /* _ANALYSIS_DISASS_AREA_H */ diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c index 1fd5550..8bddaa1 100644 --- a/src/analysis/disass/fetch.c +++ b/src/analysis/disass/fetch.c @@ -24,429 +24,96 @@ #include "fetch.h" -#include +#include "area.h" -#include "../../arch/raw.h" -#include "../../arch/instruction.h" +/* Suit un flot d'exécution pour désassembler du code. */ +static void follow_execution_flow(const GLoadedBinary *, GProcContext *, mem_area *, size_t, status_info *, virt_t); -/* Zone mémoire bien bornée */ -typedef struct _mem_area -{ - mrange_t range; /* Couverture de la zone */ - - bool has_sym; /* Représentation via symbole ?*/ - - union - { - bool exec; /* Zone exécutable ? */ - GBinSymbol *symbol; /* Symbole associé à la zone */ - }; -} mem_area; -/* Détermine une liste de zones contigües à traiter. */ -static mem_area *compute_memory_areas(const GExeFormat *, phys_t, size_t *); -/* Procède au désassemblage basique d'un contenu binaire. */ -static GArchInstruction *load_raw_binary(const GLoadedBinary *, const vmpa2t *, off_t, GtkExtStatusBar *, bstatus_id_t); -/* Procède au désassemblage d'un contenu binaire exécutable. */ -static GArchInstruction *load_code_binary(const GLoadedBinary *, const vmpa2t *, off_t, GtkExtStatusBar *, bstatus_id_t); /****************************************************************************** * * -* Paramètres : format = format d'un exécutable à consulter. * -* bin_length = quantité d'octets à traiter au total. * -* count = nombre de zones mises en place. [OUT] * +* Paramètres : binary = représentation de binaire chargé. * +* ctx = contexte offert en soutien à un désassemblage. * +* areas = liste de zones contenant des données à traiter. * +* count = nombre de ces aires à disposition. * +* info = informations liées à l'affichage de la progression. * +* virt = adresse d'un point de départ d'un traitement. * * * -* Description : Détermine une liste de zones contigües à traiter. * +* Description : Suit un flot d'exécution pour désassembler du code. * * * -* Retour : Liste de zones mémoire à libérer après usage. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static mem_area *compute_memory_areas(const GExeFormat *format, phys_t bin_length, size_t *count) +static void follow_execution_flow(const GLoadedBinary *binary, GProcContext *ctx, mem_area *areas, size_t count, status_info *info, virt_t virt) { - mem_area *result; /* Liste à renvoyer */ - mrange_t *exe_ranges; /* Liste de zones exécutables */ - size_t exe_count; /* Nombre de ces zones */ - GBinSymbol **symbols; /* Symboles à représenter */ - size_t sym_count; /* Qté de symboles présents */ - vmpa2t *last; /* Dernière bordure rencontrée */ - size_t i; /* Boucle de parcours #1 */ - vmpa2t *border; /* Nouvelle bordure rencontrée */ - mem_area *area; /* Zone avec valeurs à éditer */ - vmpa2t tmp; /* Stockage temporaire */ - size_t j; /* Boucle de parcours #2 */ - const mrange_t *range; /* Couverture d'un symbole */ - const vmpa2t *start; /* Point de départ du symbole */ - phys_t length; /* Taille de ce même symbole */ - bool included; /* Inclusion dans une zone ? */ - mem_area orig; /* Copie de la zone réduite */ - phys_t old_length; /* Taille de zone originelle */ - phys_t new_length; /* Nouvelle taille déterminée */ - size_t next; /* Indice de zone suivante */ - - result = NULL; - *count = 0; - - /** - * Le parcours n'est valide que si les listes, symboles et zones exécutables, - * sont triées ! - */ - - exe_ranges = g_exe_format_get_x_ranges(format, &exe_count); - - symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count); - - /* Première étape : on comble les trous ! */ - - last = make_vmpa(0, VMPA_NO_VIRTUAL); - - for (i = 0; i < exe_count; i++) - { - border = get_mrange_addr(&exe_ranges[i]); - - /* Zone tampon à constituer */ - - if (cmp_vmpa_by_phy(last, border) < 0) - { - result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); - - area = &result[*count - 1]; - - init_mrange(&area->range, last, compute_vmpa_diff(last, border)); - area->has_sym = false; - area->exec = false; - - } - - /* Insertion d'une zone exécutable déjà définie */ - - result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); - area = &result[*count - 1]; - copy_mrange(&area->range, &exe_ranges[i]); - area->has_sym = false; - area->exec = true; - /* Avancée du curseur */ - copy_vmpa(last, border); - advance_vmpa(last, get_mrange_length(&exe_ranges[i])); + vmpa2t addr; /* Conversion en pleine adresse*/ - } - - delete_vmpa(last); - - /* Extension finale complémentaire ? */ - - area = &result[*count - 1]; - - copy_vmpa(&tmp, get_mrange_addr(&area->range)); - advance_vmpa(&tmp, get_mrange_length(&area->range)); - - if (get_phy_addr(&tmp) < bin_length) - { - result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); - area = &result[*count - 1]; + mem_area *area; /* Zone de désassemblage */ - init_mrange(&area->range, &tmp, bin_length - get_phy_addr(&tmp)); - area->has_sym = false; - area->exec = false; - } - /* Seconde étape : on insère les symboles existants */ - j = 0; -#define SKIP_EMPTY_SYMBOLS \ - for (; j < sym_count; j++) \ - { \ - range = g_binary_symbol_get_range(symbols[j]); \ - \ - length = get_mrange_length(range); \ - if (length > 0) break; \ - \ - } \ - SKIP_EMPTY_SYMBOLS + g_proc_context_push_drop_point(ctx, virt); - for (i = 0; i < *count && j < sym_count; i++) + while (g_proc_context_has_drop_points(ctx)) { - range = g_binary_symbol_get_range(symbols[j]); - - start = get_mrange_addr(range); - length = get_mrange_length(range); - - /* Si un découpage s'impose... */ - - if (mrange_contains_addr(&result[i].range, start)) - { - copy_vmpa(&tmp, start); - advance_vmpa(&tmp, length); - - included = mrange_contains_addr(&result[i].range, &tmp); - - memcpy(&orig, &result[i], sizeof(mem_area)); - - /* Réduction de la zone de départ */ - - copy_vmpa(&tmp, get_mrange_addr(&result[i].range)); - old_length = get_mrange_length(&result[i].range); - - new_length = compute_vmpa_diff(get_mrange_addr(&result[i].range), start); - - if (new_length == 0) - { - memmove(&result[i], &result[i + 1], (*count - i - 1) * sizeof(mem_area)); - - (*count)--; - next = i; - - } - else - { - init_mrange(&result[i].range, &tmp, new_length); - next = i + 1; - } - - /* Insertion de la zone du symbole */ - - result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); - - memmove(&result[next + 1], &result[next], (*count - next - 1) * sizeof(mem_area)); - - area = &result[next]; - - copy_mrange(&area->range, range); - - area->has_sym = true; - area->symbol = symbols[j]; - - /* Jointure finale... */ - - if (included) - { - /* Simple extension pour rattraper la fin originelle */ - - if ((old_length - new_length - length) > 0) - { - result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area)); - - memmove(&result[next + 2], &result[next + 1], (*count - next - 2) * sizeof(mem_area)); - - area = &result[next + 1]; - - copy_vmpa(&tmp, start); - advance_vmpa(&tmp, length); - - memcpy(area, &orig, sizeof(mem_area)); - - init_mrange(&area->range, &tmp, old_length - new_length - length); - - } + virt = g_proc_context_pop_drop_point(ctx); + init_vmpa(&addr, VMPA_NO_PHYSICAL, virt); - i = next; - } - else - { - /* Suppression des éventuelles zones totalement recouvertes */ + area = find_memory_area_by_addr(areas, count, &addr); + /* + printf("found area = %p\n", area); + printf(" ... 0x%08x - 0x%08x + %u\n", + area->range.addr.physical, + area->range.addr.virtual, + area->range.length); + */ - /* Réduction de la zone d'arrivée */ + load_code_from_mem_area(area, areas, count, binary, ctx, &addr, info); - } - - - - j++; - - SKIP_EMPTY_SYMBOLS - - } + //exit(0); } - - - //free - - //exit(0); - - return result; - } -/****************************************************************************** -* * -* Paramètres : binary = représentation de binaire chargé. * -* parts = parties binaires à désassembler. * -* count = nombre de parties à traiter. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : Procède au désassemblage basique d'un contenu binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ -static GArchInstruction *load_raw_binary(const GLoadedBinary *binary, const vmpa2t *base, off_t end, GtkExtStatusBar *statusbar, bstatus_id_t id) -{ - GArchInstruction *result; /* Liste d'instr. à renvoyer */ - GBinFormat *format; /* Format du fichier binaire */ - GArchProcessor *proc; /* Architecture du binaire */ - off_t bin_length; /* Taille des données à lire */ - bin_t *bin_data; /* Données binaires à lire */ - vmpa2t pos; /* Boucle de parcours */ - vmpa2t prev; /* Boucle de parcours */ - off_t old_phy; /* Ancienne position physique */ - GArchInstruction *instr; /* Instruction décodée */ - off_t new_phy; /* Nouvelle position physique */ - mrange_t range; /* Couverture de l'instruction */ - result = NULL; - format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); - proc = get_arch_processor_from_format(G_EXE_FORMAT(format)); - bin_data = g_loaded_binary_get_data(binary, &bin_length); - copy_vmpa(&pos, base); - copy_vmpa(&prev, base); - old_phy = get_phy_addr(&prev); - while (old_phy < end) - { - instr = g_raw_instruction_new_array(bin_data, MDS_32_BITS, 1, &pos, end, - g_arch_processor_get_endianness(proc)); - if (instr == NULL) printf(" Break !!!\n"); - if (instr == NULL) break; - new_phy = get_phy_addr(&pos); - init_mrange(&range, &prev, new_phy - old_phy); - g_arch_instruction_set_range(instr, &range); - g_arch_instruction_add_to_list(&result, instr); - - copy_vmpa(&prev, &pos); - old_phy = get_phy_addr(&prev); - - //done += (new_phy - old_phy); - //gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / sum); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : binary = représentation de binaire chargé. * -* parts = parties binaires à désassembler. * -* count = nombre de parties à traiter. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : Procède au désassemblage d'un contenu binaire exécutable. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GArchInstruction *load_code_binary(const GLoadedBinary *binary, const vmpa2t *base, off_t end, GtkExtStatusBar *statusbar, bstatus_id_t id) -{ - GArchInstruction *result; /* Liste d'instr. à renvoyer */ - GBinFormat *format; /* Format du fichier binaire */ - GArchProcessor *proc; /* Architecture du binaire */ - off_t bin_length; /* Taille des données à lire */ - bin_t *bin_data; /* Données binaires à lire */ - vmpa2t pos; /* Boucle de parcours */ - vmpa2t prev; /* Boucle de parcours */ - off_t old_phy; /* Ancienne position physique */ - GArchInstruction *instr; /* Instruction décodée */ - off_t new_phy; /* Nouvelle position physique */ - mrange_t range; /* Couverture de l'instruction */ - - result = NULL; - - format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); - proc = get_arch_processor_from_format(G_EXE_FORMAT(format)); - bin_data = g_loaded_binary_get_data(binary, &bin_length); - - copy_vmpa(&pos, base); - copy_vmpa(&prev, base); - - old_phy = get_phy_addr(&prev); - - while (old_phy < end) - { - instr = g_arch_processor_disassemble(proc, NULL, bin_data, &pos, end); - - //if (!G_IS_RAW_INSTRUCTION(instr)) printf("GOT %p\n", instr); - - if (instr == NULL) - instr = g_raw_instruction_new_array(bin_data, MDS_32_BITS, 1, &pos, end, - g_arch_processor_get_endianness(proc)); - if (instr == NULL) printf(" Break !!!\n"); - if (instr == NULL) break; - - new_phy = get_phy_addr(&pos); - init_mrange(&range, &prev, new_phy - old_phy); - - g_arch_instruction_set_range(instr, &range); - - g_arch_instruction_add_to_list(&result, instr); - - copy_vmpa(&prev, &pos); - old_phy = get_phy_addr(&prev); - - //done += (new_phy - old_phy); - //gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / sum); - - - - - - g_arch_instruction_call_hook(instr, IPH_LINK, NULL, format); - - - g_arch_instruction_call_hook(instr, IPH_POST, NULL, format); - - - - - } - - return result; - -} @@ -467,83 +134,34 @@ static GArchInstruction *load_code_binary(const GLoadedBinary *binary, const vmp * * ******************************************************************************/ -static GArchInstruction *follow_execution_flow(const GLoadedBinary *binary, GProcContext *ctx, mem_area *areas, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id) +GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, GtkExtStatusBar *statusbar, bstatus_id_t id) { - GBinFormat *format; /* Format du fichier binaire */ - - virt_t addr; - - - - mem_area *area; /* Zone de désassemblage */ - - - format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); - - /* Insertion du point de départ */ - - addr = g_binary_format_get_entry_point(format); - - g_proc_context_push_drop_point(ctx, addr); - - /* Suivi de l'exécution autant que possible */ - - while (g_proc_context_has_drop_points(ctx)) - { - //virt = g_proc_context_pop_drop_point(ctx); - - - area = NULL; - - - - - } - - - - - // ctx.add(entry_point) - - // while (ctx.has_pending_addresses) - - // virt = ctx.pop - // find mem_area for virt - - // if area.limit < virt then continue - - + GArchInstruction *result; /* Instruction désassemblées */ + GBinFormat *format; /* Format du fichier binaire */ + GArchProcessor *proc; /* Architecture du binaire */ + GProcContext *ctx; /* Contexte de désassemblage */ -} + status_info *info; + off_t length; /* Taille des données à lire */ + mem_area *areas; /* Zone de productions */ + size_t count; /* Nombre de ces zones */ + virt_t virt; /* Point d'accroche virtuelle */ + GBinSymbol **symbols; /* Symboles à représenter */ + size_t sym_count; /* Qté de symboles présents */ + size_t i; /* Boucle de parcours */ -/****************************************************************************** -* * -* Paramètres : binary = représentation de binaire chargé. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : Procède au désassemblage basique d'un contenu binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ -GArchInstruction *disassemble_binary_content_new(const GLoadedBinary *binary, GtkExtStatusBar *statusbar, bstatus_id_t id) -{ - GBinFormat *format; /* Format du fichier binaire */ - GArchProcessor *proc; /* Architecture du binaire */ + const mrange_t *range; /* Couverture d'un symbole */ + const vmpa2t *addr; /* Point de départ du symbole */ - GProcContext *ctx; /* Contexte de désassemblage */ @@ -553,88 +171,46 @@ GArchInstruction *disassemble_binary_content_new(const GLoadedBinary *binary, Gt ctx = g_arch_processor_get_context(proc); + info = NULL; -} - + /* Définition à la découpe des parties à traiter */ + g_loaded_binary_get_data(binary, &length); + areas = compute_memory_areas(G_EXE_FORMAT(format), length, &count); -/****************************************************************************** -* * -* Paramètres : binary = représentation de binaire chargé. * -* statusbar = barre de statut avec progression à mettre à jour.* -* id = identifiant du message affiché à l'utilisateur. * -* * -* Description : Procède au désassemblage basique d'un contenu binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + /* Insertion du point de départ */ -GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, GtkExtStatusBar *statusbar, bstatus_id_t id) -{ - GArchInstruction *result; /* Instruction désassemblées */ - GExeFormat *format; /* Format du fichier binaire */ - off_t length; /* Taille des données à lire */ - mem_area *areas; /* Zone de productions */ - size_t count; /* Nombre de ces zones */ - size_t i; /* Boucle de parcours */ - mem_area *iter; /* Zone parcourue */ - GArchInstruction *instr; /* Instruction(s) à insérer */ - const vmpa2t *start; /* Début d'une zone traitée */ - phys_t end; /* Fin d'une zone traitée */ + virt = g_binary_format_get_entry_point(format); - result = NULL; + follow_execution_flow(binary, ctx, areas, count, info, virt); - format = g_loaded_binary_get_format(binary); - g_loaded_binary_get_data(binary, &length); + /* Symboles exécutables présents et passés à travers les mailles */ - areas = compute_memory_areas(format, length, &count); + symbols = g_binary_format_get_symbols(format, &sym_count); - for (i = 0; i < count; i++) + for (i = 0; i < sym_count; i++) { - iter = &areas[i]; - - start = get_mrange_addr(&iter->range); - end = get_phy_addr(start) + get_mrange_length(&iter->range); + if (g_binary_symbol_get_target_type(symbols[i]) != STP_FUNCTION) + continue; - assert(get_mrange_length(&iter->range) > 0); + range = g_binary_symbol_get_range(symbols[i]); + addr = get_mrange_addr(range); + virt = get_virt_addr(addr); - if (iter->has_sym) - switch (g_binary_symbol_get_target_type(iter->symbol)) - { - case STP_DATA: - instr = g_binary_symbol_get_instruction(iter->symbol); - g_object_ref(G_OBJECT(instr)); - break; + follow_execution_flow(binary, ctx, areas, count, info, virt); - case STP_ROUTINE: - instr = load_code_binary(binary, start, end, statusbar, id); - break; - - default: - assert(false); - break; + } - } - else - { - if (iter->exec) - instr = load_code_binary(binary, start, end, statusbar, id); - else - instr = load_raw_binary(binary, start, end, statusbar, id); + ensure_all_mem_areas_are_filled(areas, count, binary, ctx, info); - } - g_arch_instruction_merge_lists(&result, &instr); - } + result = collect_instructions_from_mem_areas(areas, count); - free(areas); + /* free */ - return result; + return result; } diff --git a/src/arch/arm/context.c b/src/arch/arm/context.c index c86b190..7f41b92 100644 --- a/src/arch/arm/context.c +++ b/src/arch/arm/context.c @@ -60,6 +60,9 @@ static void g_arm_context_dispose(GArmContext *); /* Procède à la libération totale de la mémoire. */ static void g_arm_context_finalize(GArmContext *); +/* Ajoute une adresse virtuelle comme point de départ de code. */ +static void g_arm_context_push_drop_point(GArmContext *, virt_t ); + /* ------------------------- CONTEXTE POUR LA DECOMPILATION ------------------------- */ @@ -124,12 +127,17 @@ G_DEFINE_TYPE(GArmContext, g_arm_context, G_TYPE_PROC_CONTEXT); static void g_arm_context_class_init(GArmContextClass *klass) { GObjectClass *object; /* Autre version de la classe */ + GProcContextClass *proc; /* Version parente de la classe*/ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_arm_context_dispose; object->finalize = (GObjectFinalizeFunc)g_arm_context_finalize; + proc = G_PROC_CONTEXT_CLASS(klass); + + proc->push_point = (push_drop_point_fc)g_arm_context_push_drop_point; + } @@ -212,6 +220,42 @@ GArmContext *g_arm_context_new(void) } +/****************************************************************************** +* * +* Paramètres : ctx = contexte de désassemblage à compléter. * +* addr = adresse d'un nouveau point de départ à traiter. * +* * +* Description : Ajoute une adresse virtuelle comme point de départ de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_arm_context_push_drop_point(GArmContext *ctx, virt_t addr) +{ + + + printf("PUSH !!\n"); + + + + if (addr & 0x1) + { + addr -= 0x1; + + + } + else ; + + // ARM / Thumb + + G_PROC_CONTEXT_CLASS(g_arm_context_parent_class)->push_point(G_PROC_CONTEXT(ctx), addr); + +} + + /* ---------------------------------------------------------------------------------- */ /* CONTEXTE POUR LA DECOMPILATION */ diff --git a/src/arch/arm/processor.c b/src/arch/arm/processor.c index 2c676be..cf993c0 100644 --- a/src/arch/arm/processor.c +++ b/src/arch/arm/processor.c @@ -24,6 +24,7 @@ #include "processor.h" +#include "context.h" #include "processor-int.h" @@ -40,6 +41,9 @@ static void g_arm_processor_dispose(GArmProcessor *); /* Procède à la libération totale de la mémoire. */ static void g_arm_processor_finalize(GArmProcessor *); +/* Fournit un contexte pour l'exécution du processeur ARM. */ +static GArmContext *g_arm_processor_get_context(const GArmProcessor *); + /* Indique le type défini par la GLib pour le processeur ARM. */ @@ -84,6 +88,11 @@ static void g_arm_processor_class_init(GArmProcessorClass *klass) static void g_arm_processor_init(GArmProcessor *proc) { + GArchProcessor *parent; /* Instance parente */ + + parent = G_ARCH_PROCESSOR(proc); + + parent->get_ctx = (get_processor_context_fc)g_arm_processor_get_context; } @@ -124,3 +133,22 @@ static void g_arm_processor_finalize(GArmProcessor *proc) G_OBJECT_CLASS(g_arm_processor_parent_class)->finalize(G_OBJECT(proc)); } + + +/****************************************************************************** +* * +* Paramètres : proc = architecture, spectatrice ici. * +* * +* Description : Fournit un contexte pour l'exécution du processeur Arm. * +* * +* Retour : Contexte mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GArmContext *g_arm_processor_get_context(const GArmProcessor *proc) +{ + return g_arm_context_new(); + +} diff --git a/src/arch/arm/v7/link.c b/src/arch/arm/v7/link.c index 278b8d0..e7a1b40 100644 --- a/src/arch/arm/v7/link.c +++ b/src/arch/arm/v7/link.c @@ -67,6 +67,9 @@ void handle_links_with_thumb_instruction_bl(GArchInstruction *instr, GProcContex if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_SIGNED, &offset)) g_imm_operand_set_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, pc + offset); + + printf("[@ 0x%08x] Add 0x%08x to %p\n", (uint32_t)get_virt_addr(get_mrange_addr(range)), (uint32_t)(pc + offset), context); + } @@ -110,4 +113,8 @@ void handle_links_with_thumb_instruction_blx(GArchInstruction *instr, GProcConte if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_SIGNED, &offset)) g_imm_operand_set_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, pc + offset); + + printf("[@ 0x%08x] Add 0x%08x to %p\n", (uint32_t)get_virt_addr(get_mrange_addr(range)), (uint32_t)(pc + offset), context); + + } diff --git a/src/arch/context-int.h b/src/arch/context-int.h index 3a65f79..b181202 100644 --- a/src/arch/context-int.h +++ b/src/arch/context-int.h @@ -29,6 +29,10 @@ +/* Ajoute une adresse virtuelle comme point de départ de code. */ +typedef void (* push_drop_point_fc) (GProcContext *, virt_t); + + /* Définition d'un contexte pour processeur (instance) */ struct _GProcContext { @@ -45,6 +49,8 @@ struct _GProcContextClass { GObjectClass parent; /* A laisser en premier */ + push_drop_point_fc push_point; /* Inclusion de points de chute*/ + }; diff --git a/src/arch/context.c b/src/arch/context.c index 46c4dd1..794030a 100644 --- a/src/arch/context.c +++ b/src/arch/context.c @@ -39,6 +39,9 @@ static void g_proc_context_class_init(GProcContextClass *); /* Initialise une instance de contexte de processeur. */ static void g_proc_context_init(GProcContext *); +/* Ajoute une adresse virtuelle comme point de départ de code. */ +static void _g_proc_context_push_drop_point(GProcContext *, virt_t); + /* Indique le type définit par la GLib pour le contexte de processeur. */ @@ -60,6 +63,7 @@ G_DEFINE_TYPE(GProcContext, g_proc_context, G_TYPE_OBJECT); static void g_proc_context_class_init(GProcContextClass *klass) { + klass->push_point = (push_drop_point_fc)_g_proc_context_push_drop_point; } @@ -97,7 +101,7 @@ static void g_proc_context_init(GProcContext *ctx) * * ******************************************************************************/ -void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) +static void _g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) { ctx->drop_points = (virt_t *)realloc(ctx->drop_points, ++ctx->dp_count * sizeof(virt_t)); @@ -108,6 +112,26 @@ void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) /****************************************************************************** * * +* Paramètres : ctx = contexte de désassemblage à compléter. * +* addr = adresse d'un nouveau point de départ à traiter. * +* * +* Description : Ajoute une adresse virtuelle comme point de départ de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) +{ + return G_PROC_CONTEXT_GET_CLASS(ctx)->push_point(ctx, addr); + +} + + +/****************************************************************************** +* * * Paramètres : ctx = contexte de désassemblage à consulter. * * * * Description : Indique si des points de départ restent à traiter ou non. * diff --git a/src/arch/context.h b/src/arch/context.h index 9bb7cd3..97b23b6 100644 --- a/src/arch/context.h +++ b/src/arch/context.h @@ -36,9 +36,9 @@ #define G_TYPE_PROC_CONTEXT g_proc_context_get_type() #define G_PROC_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_proc_context_get_type(), GProcContext)) #define G_IS_PROC_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_proc_context_get_type())) -#define G_PROC_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PROC_CONTEXT, GGProcContextClass)) +#define G_PROC_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PROC_CONTEXT, GProcContextClass)) #define G_IS_PROC_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PROC_CONTEXT)) -#define G_PROC_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PROC_CONTEXT, GGProcContextClass)) +#define G_PROC_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PROC_CONTEXT, GProcContextClass)) /* Définition d'un contexte pour processeur (instance) */ diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c index 024161c..7d57909 100644 --- a/src/arch/vmpa.c +++ b/src/arch/vmpa.c @@ -626,6 +626,37 @@ int cmp_mrange(const mrange_t *a, const mrange_t *b) /****************************************************************************** * * * Paramètres : range = zone mémoire à consulter. * +* sub = éventuelle sous-région à valider. * +* * +* Description : Indique si une zone en contient une autre ou non. * +* * +* Retour : Bilan de la consultation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool mrange_contains_mrange(const mrange_t *range, const mrange_t *sub) +{ + bool result; /* Bilan à retourner */ + phys_t start; /* Point de départ */ + + result = mrange_contains_addr(range, get_mrange_addr(sub)); + + if (result) + { + start = compute_vmpa_diff(get_mrange_addr(range), get_mrange_addr(sub)); + result = (start + get_mrange_length(sub) <= get_mrange_length(range)); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : range = zone mémoire à consulter. * * addr = localisation mémoire à analyser. * * * * Description : Indique si une localisation est incluse dans une zone ou non.* diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index f0a8faf..96e8a56 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -153,6 +153,9 @@ void copy_mrange(mrange_t *, const mrange_t *); /* Compare deux couvertures mémoire selon leurs propriétés. */ int cmp_mrange(const mrange_t *, const mrange_t *); +/* Indique si une zone en contient une autre ou non. */ +bool mrange_contains_mrange(const mrange_t *, const mrange_t *); + /* Indique si une localisation est incluse dans une zone ou non. */ bool mrange_contains_addr(const mrange_t *, const vmpa2t *); diff --git a/src/gtkext/gtkextstatusbar.h b/src/gtkext/gtkextstatusbar.h index fba0823..779a177 100644 --- a/src/gtkext/gtkextstatusbar.h +++ b/src/gtkext/gtkextstatusbar.h @@ -30,6 +30,19 @@ +typedef struct _status_info +{ + + + void *a; + + //GtkExtStatusBar *statusbar, bstatus_id_t id + +} status_info; + + + + #define GTK_TYPE_EXT_STATUS_BAR (gtk_extended_status_bar_get_type()) #define GTK_EXT_STATUS_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_extended_status_bar_get_type (), GtkExtStatusBar)) #define GTK_IS_EXT_STATUS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_extended_status_bar_get_type())) -- cgit v0.11.2-87-g4458