diff options
Diffstat (limited to 'src/analysis/disass/area.c')
-rw-r--r-- | src/analysis/disass/area.c | 637 |
1 files changed, 402 insertions, 235 deletions
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c index 71e2784..2bc7a53 100644 --- a/src/analysis/disass/area.c +++ b/src/analysis/disass/area.c @@ -35,6 +35,7 @@ #include "../../analysis/contents/restricted.h" #include "../../arch/raw.h" #include "../../common/bits.h" +#include "../../common/sort.h" #include "../../format/format.h" #include "../../glibext/delayed-int.h" #include "../../gui/panels/log.h" @@ -115,11 +116,32 @@ typedef struct _GAreaCollector mem_area *areas; /* Zone de productions */ - size_t begin; /* Début du parcours à mener */ - size_t end; /* Fin de ce même parcours */ + union + { + struct + { + size_t acount; /* Nombre de zones créées */ + + GLoadedBinary *binary; /* Binaire à associer aux zones*/ - GArchInstruction **collected; /* Instructions collectées */ - size_t count; /* Quantité de ces instructions*/ + phys_t first; /* Début de traitement */ + phys_t last; /* Fin de traitement */ + + bool closing; /* Tâche clôturant le parcours */ + + }; + + struct + { + size_t begin; /* Début du parcours à mener */ + size_t end; /* Fin de ce même parcours */ + + GArchInstruction **collected; /* Instructions collectées */ + size_t ccount; /* Quantité de ces instructions*/ + + }; + + }; } GAreaCollector; @@ -149,6 +171,12 @@ static void g_area_collector_finalize(GAreaCollector *); /* Assure un traitement particulier concernant les zones. */ static void g_area_collector_process(GAreaCollector *, GtkStatusStack *); +/* Crée une tâche de calcul des zones binaires à désassembler. */ +static GAreaCollector *g_area_collector_new_intro(activity_id_t, GLoadedBinary *, phys_t, phys_t, bool); + +/* Construit une liste bornée de zones contigües. */ +static void g_area_collector_do_compute(GAreaCollector *, GtkStatusStack *); + /* Crée une tâche de récupération d'instructions différée. */ static GAreaCollector *g_area_collector_new_outro(activity_id_t, mem_area *, size_t, size_t); @@ -779,230 +807,6 @@ static GArchInstruction **get_instructions_from_mem_area(const mem_area *area, G /****************************************************************************** * * -* Paramètres : binary = binaire analysé contenant quantités d'infos. * -* 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(const GLoadedBinary *binary, phys_t bin_length, size_t *count) -{ - mem_area *result; /* Liste à renvoyer */ - GExeFormat *format; /* Format de fichier associé */ - 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 */ - bool status; /* Bilan d'une conversion */ - size_t i; /* Boucle de parcours #1 */ - const vmpa2t *border; /* Nouvelle bordure rencontrée */ - mem_area *area; /* Zone avec valeurs à éditer */ - vmpa2t tmp; /* Stockage temporaire */ - GPortionLayer *layer; /* Couche première de portions */ - GBinPortion **portions; /* Morceaux d'encadrement */ - size_t portions_count; /* Taille de cette liste */ - const vmpa2t *portion_start; /* Point de départ de portion */ - const vmpa2t *portion_next; /* Départ de portion suivante */ - size_t j; /* Boucle de parcours #2 */ - SymbolType type; /* Nature d'un symbole */ - const mrange_t *range; /* Couverture d'un symbole */ - phys_t length; /* Taille de ce même symbole */ - phys_t new_length; /* Nouvelle taille déterminée */ - - result = NULL; - *count = 0; - - /** - * Le parcours n'est valide que si les zones exécutables sont triées ! - */ - - format = g_loaded_binary_get_format(binary); - - 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 ! */ - - status = g_exe_format_translate_offset_into_vmpa(format, 0, &last); - assert(status); - - for (i = 0; i < exe_count; i++) - { - border = get_mrange_addr(&exe_ranges[i]); - - /* Zone tampon à constituer */ - - if (cmp_vmpa(&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), binary); - area->is_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_addr(area, get_mrange_addr(&exe_ranges[i]), - get_mrange_length(&exe_ranges[i]), binary); - area->is_exec = true; - - /* Avancée du curseur */ - - compute_mrange_end_addr(&exe_ranges[i], &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), binary); - area->is_exec = false; - - } - - /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */ - - layer = g_exe_format_get_main_layer(format); - - portions = g_portion_layer_collect_all_portions(layer, &portions_count); - - for (i = 1; i < portions_count; i++) - { - portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i])); - - /** - * Si plusieurs portions débutent au même endroit, il ne sert - * à rien de découper plusieurs fois. - */ - if ((i + 1) < portions_count) - { - portion_next = get_mrange_addr(g_binary_portion_get_range(portions[i + 1])); - - if (cmp_vmpa(portion_start, portion_next) == 0) - continue; - - } - - 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)); - - status = result[j].is_exec; - - /* Première moitié */ - - area = &result[j]; - - copy_vmpa(&tmp, get_mrange_addr(&area->range)); - length = get_mrange_length(&area->range); - - new_length = compute_vmpa_diff(&tmp, portion_start); - - init_mem_area_from_addr(area, &tmp, new_length, binary); - area->is_exec = status; - - /* Seconde moitié */ - - length -= get_mrange_length(&area->range); - - area = &result[j + 1]; - - init_mem_area_from_addr(area, portion_start, length, binary); - area->is_exec = status; - - } - - j = *count; - - } - - } - - if (portions != NULL) - free(portions); - - g_object_unref(G_OBJECT(layer)); - - /* Troisième étape : on insère les symboles existants */ - - for (i = 0; i < sym_count; i++) - { - type = g_binary_symbol_get_target_type(symbols[i]); - - /** - * On ne garde que les symboles renvoyant directement une ou - * plusieurs instructions, c'est à dire les symboles valides - * pour un appel à g_binary_symbol_get_instruction(). - * - * Les instructions des autres symboles sont obtenues et mises - * en place durant la procédure de désassemblage. - */ - - if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL) - continue; - - range = g_binary_symbol_get_range(symbols[i]); - - length = get_mrange_length(range); - - if (length == 0) - continue; - - insert_extra_symbol_into_mem_areas(result, *count, symbols[i]); - - } - - /* Nettoyage final */ - - if (exe_ranges != NULL) - free(exe_ranges); - - g_object_unref(G_OBJECT(format)); - - 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. * @@ -1212,6 +1016,9 @@ static void g_area_collector_init(GAreaCollector *collector) static void g_area_collector_dispose(GAreaCollector *collector) { + if (collector->run == (run_task_fc)g_area_collector_do_compute) + g_object_unref(G_OBJECT(collector->binary)); + G_OBJECT_CLASS(g_area_collector_parent_class)->dispose(G_OBJECT(collector)); } @@ -1258,6 +1065,366 @@ static void g_area_collector_process(GAreaCollector *collector, GtkStatusStack * /****************************************************************************** * * +* Paramètres : id = identifiant pour signaler la progression courante. * +* binary = binaire chargé à conserver dans les zones définies.* +* first = localisation du début de la portion à traiter. * +* last = localisation de la fin de la portion à traiter. * +* closing = indique si la tâche doit terminer l'analyse. * +* * +* Description : Crée une tâche de calcul des zones binaires à désassembler. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GAreaCollector *g_area_collector_new_intro(activity_id_t id, GLoadedBinary *binary, phys_t first, phys_t last, bool closing) +{ + GAreaCollector *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_AREA_COLLECTOR, NULL); + + result->id = id; + result->run = (run_task_fc)g_area_collector_do_compute; + + result->areas = NULL; + + result->acount = 0; + + result->binary = binary; + g_object_ref(G_OBJECT(binary)); + + result->first = first; + result->last = last; + + result->closing = closing; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : fetching = récupération à mener. * +* status = barre de statut à tenir informée. * +* * +* Description : Construit une liste bornée de zones contigües. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_area_collector_do_compute(GAreaCollector *collector, GtkStatusStack *status) +{ + mem_area **list; /* Liste de zones à constituer */ + size_t *count; /* Nombre d'éléments intégrés */ + vmpa2t first; /* Point de départ */ + vmpa2t last; /* Point d'arrivée */ + GExeFormat *format; /* Format du binaire */ + vmpa2t prev; /* Dernière bordure rencontrée */ + bool state; /* Bilan d'une conversion */ + GBinSymbol **symbols; /* Symboles à représenter */ + size_t sym_count; /* Qté de symboles présents */ + bool has_sym_index; /* Détermine une validité */ + size_t sym_index; /* Prochain symbole non traité */ + GBinPortion *portions; /* Couche première de portions */ + + void populate_with_symbols(const vmpa2t *limit) + { + GBinSymbol *symbol; /* Symbole en cours d'analyse */ + SymbolType type; /* Nature d'un symbole */ + const mrange_t *range; /* Couverture d'un symbole */ + vmpa2t end; /* Adresse de fin du symbole */ + + for (; sym_index < sym_count; sym_index++) + { + symbol = symbols[sym_index]; + + type = g_binary_symbol_get_target_type(symbol); + + /** + * On ne garde que les symboles renvoyant directement une ou + * plusieurs instructions, c'est à dire les symboles valides + * pour un appel à g_binary_symbol_get_instruction(). + * + * Les instructions des autres symboles sont obtenues et mises + * en place durant la procédure de désassemblage. + */ + + if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL) + continue; + + range = g_binary_symbol_get_range(symbol); + + if (get_mrange_length(range) == 0) + continue; + + if (cmp_vmpa(get_mrange_addr(range), limit) >= 0) + break; + + compute_mrange_end_addr(range, &end); + + /** + * Si un symbole est à cheval entre deux zones, tant pis pour lui ! + */ + + if (cmp_vmpa(&end, limit) > 0) + break; + + insert_extra_symbol_into_mem_areas(*list, *count, symbol); + + } + + } + + void fill_gap(vmpa2t *old, vmpa2t *new, bool exec) + { + phys_t diff; /* Espace entre bordures */ + mem_area *area; /* Zone avec valeurs à éditer */ + + diff = compute_vmpa_diff(old, new); + + /** + * S'il existe un écart entre la dernière bordure ajoutée et + * l'extréminité de la portion courante, on le comble ! + */ + + if (diff > 0) + { + /* Zone tampon à constituer */ + + *list = (mem_area *)realloc(*list, ++(*count) * sizeof(mem_area)); + + area = &(*list)[*count - 1]; + + init_mem_area_from_addr(area, old, diff, collector->binary); + area->is_exec = exec; + + /* Insertion des symboles existants */ + + if (!has_sym_index) + { + int cmp_vmpa_with_symbol(const vmpa2t *a, const GBinSymbol **s) + { + return g_binary_symbol_cmp_with_vmpa(*s, a); + } + + bsearch_index(old, symbols, sym_count, sizeof(GBinSymbol *), + (__compar_fn_t)cmp_vmpa_with_symbol, &sym_index); + + has_sym_index = true; + + } + + populate_with_symbols(new); + + /* Avancée du curseur */ + + copy_vmpa(old, new); + + gtk_status_stack_update_activity_value(status, collector->id, diff); + + } + + } + + bool build_area_from_portion(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, void *unused) + { + const mrange_t *range; /* Espace de portion à traiter */ + vmpa2t border; /* Nouvelle bordure rencontrée */ + bool on_track; /* Le tronçon courant est bon ?*/ + PortionAccessRights rights; /* Droits d'accès à analyser */ + + range = g_binary_portion_get_range(portion); + + if (visit == BPV_ENTER) + { + copy_vmpa(&border, get_mrange_addr(range)); + + on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0; + + if (on_track) + { + rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE); + fill_gap(&prev, &border, rights & PAC_EXEC); + } + else + copy_vmpa(&prev, &border); + + } + + else if (visit == BPV_SHOW) + { + copy_vmpa(&border, get_mrange_addr(range)); + + on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0; + + if (on_track) + { + rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE); + fill_gap(&prev, &border, rights & PAC_EXEC); + + compute_mrange_end_addr(range, &border); + + rights = g_binary_portion_get_rights(portion); + fill_gap(&prev, &border, rights & PAC_EXEC); + + } + else + compute_mrange_end_addr(range, &prev); + + } + + else if (visit == BPV_EXIT) + { + compute_mrange_end_addr(range, &border); + + if (collector->closing) + on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) <= 0; + else + on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0; + + if (on_track) + { + rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE); + fill_gap(&prev, &border, rights & PAC_EXEC); + } + else + copy_vmpa(&prev, &border); + + } + +#ifndef NDEBUG + else + assert(false); +#endif + + return (cmp_vmpa(&prev, &last) < 0); + + } + + list = &collector->areas; + count = &collector->acount; + + init_vmpa(&first, collector->first, VMPA_NO_VIRTUAL); + init_vmpa(&last, collector->last, VMPA_NO_VIRTUAL); + + format = g_loaded_binary_get_format(collector->binary); + +#ifndef NDEBUG + state = g_exe_format_translate_offset_into_vmpa(format, 0, &prev); + assert(state); +#else + g_exe_format_translate_offset_into_vmpa(format, 0, &prev); +#endif + + symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count); + + has_sym_index = false; + + portions = g_exe_format_get_portions(format); + + g_binary_portion_visit(portions, (visit_portion_fc)build_area_from_portion, NULL); + + g_object_unref(G_OBJECT(portions)); + + g_object_unref(G_OBJECT(format)); + +} + + +/****************************************************************************** +* * +* Paramètres : gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * +* binary = binaire analysé contenant quantités d'infos. * +* 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 *collect_memory_areas(wgroup_id_t gid, GtkStatusStack *status, GLoadedBinary *binary, phys_t length, size_t *count) +{ + mem_area *result; /* Liste finale à retourner */ + guint runs_count; /* Qté d'exécutions parallèles */ + GAreaCollector **collectors; /* Collecteurs à suivre */ + phys_t run_size; /* Volume réparti par exécution*/ + GWorkQueue *queue; /* Gestionnaire de différés */ + activity_id_t id; /* Identifiant de progression */ + guint i; /* Boucle de parcours */ + phys_t first; /* Début de zone de traitement */ + bool closing; /* Détection de fin en amont */ + phys_t last; /* Fin de zone de traitement */ + + runs_count = g_get_num_processors(); + + collectors = (GAreaCollector **)calloc(runs_count, sizeof(GAreaCollector *)); + + run_size = length / runs_count; + + queue = get_work_queue(); + + id = gtk_status_stack_add_activity(status, _("Computing memory areas to disassemble"), length); + + for (i = 0; i < runs_count; i++) + { + first = i * run_size; + + closing = ((i + 1) == runs_count); + + if (closing) + last = length; + else + last = first + run_size; + + collectors[i] = g_area_collector_new_intro(id, binary, first, last, closing); + + g_object_ref(G_OBJECT(collectors[i])); + g_work_queue_schedule_work(queue, G_DELAYED_WORK(collectors[i]), gid); + + } + + g_work_queue_wait_for_completion(queue, gid); + + /* Récupération des aires */ + + result = NULL; + *count = 0; + + for (i = 0; i < runs_count; i++) + { + result = (mem_area *)realloc(result, (*count + collectors[i]->acount) * sizeof(mem_area)); + + memcpy(&result[*count], collectors[i]->areas, collectors[i]->acount * sizeof(mem_area)); + *count += collectors[i]->acount; + + g_object_unref(G_OBJECT(collectors[i])); + + } + + /* Fin */ + + free(collectors); + + gtk_status_stack_remove_activity(status, id); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : id = identifiant pour signaler la progression courante. * * list = liste des zones en place à parcourir. * * begin = indice de la première zone à traiter. * @@ -1286,7 +1453,7 @@ static GAreaCollector *g_area_collector_new_outro(activity_id_t id, mem_area *li result->end = end; result->collected = NULL; - result->count = 0; + result->ccount = 0; return result; @@ -1313,7 +1480,7 @@ static void g_area_collector_do_collect(GAreaCollector *collector, GtkStatusStac for (i = collector->begin; i < collector->end; i++) { collector->collected = get_instructions_from_mem_area(&collector->areas[i], - collector->collected, &collector->count); + collector->collected, &collector->ccount); fini_mem_area(&collector->areas[i]); @@ -1326,8 +1493,8 @@ static void g_area_collector_do_collect(GAreaCollector *collector, GtkStatusStac /****************************************************************************** * * -* Paramètres : gid = groupe de travail impliqué. * -* status = barre de statut à tenir informée. * +* Paramètres : gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * * list = liste des zones de données à relire puis libérer. * * acount = taille de cette liste de zones. * * icount = nombre d'instructions récupérées. [OUT] * @@ -1388,10 +1555,10 @@ GArchInstruction **collect_disassembled_instructions(wgroup_id_t gid, GtkStatusS for (i = 0; i < runs_count; i++) { result = (GArchInstruction **)realloc(result, - (*icount + collectors[i]->count) * sizeof(GArchInstruction *)); + (*icount + collectors[i]->ccount) * sizeof(GArchInstruction *)); - memcpy(&result[*icount], collectors[i]->collected, collectors[i]->count * sizeof(GArchInstruction *)); - *icount += collectors[i]->count; + memcpy(&result[*icount], collectors[i]->collected, collectors[i]->ccount * sizeof(GArchInstruction *)); + *icount += collectors[i]->ccount; g_object_unref(G_OBJECT(collectors[i])); |