From 6b1a70c16f83a926f7b1f1fb2af5d6a2e017737b Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 26 Nov 2015 23:30:01 +0000 Subject: Used several threads without lock to disassemble binary code. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@610 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 30 + src/analysis/disass/area.c | 1085 +++++++++++++++++++++++++++++++++++- src/analysis/disass/area.h | 43 ++ src/analysis/disass/disassembler.c | 11 +- src/analysis/disass/fetch.c | 429 ++++++++++++-- src/analysis/disass/fetch.h | 3 +- src/arch/archbase.h | 25 + src/arch/arm/context-int.h | 1 + src/arch/arm/context.c | 18 +- src/arch/arm/v7/context.c | 10 +- src/arch/context-int.h | 12 +- src/arch/context.c | 69 ++- src/arch/context.h | 2 +- src/common/bits.c | 68 +++ src/common/bits.h | 9 + src/format/elf/elf.c | 6 + src/format/symbol.h | 4 + 17 files changed, 1741 insertions(+), 84 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e13b93..308e126 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +15-11-27 Cyrille Bagard + + * src/analysis/disass/area.c: + * src/analysis/disass/area.h: + * src/analysis/disass/disassembler.c: + * src/analysis/disass/fetch.c: + * src/analysis/disass/fetch.h: + Use several threads without lock to disassemble binary code. + + * src/arch/archbase.h: + Provide memory data sizes from byte sizes with MDS_FROM_BYTES. + + * src/arch/arm/context.c: + * src/arch/arm/context-int.h: + * src/arch/arm/v7/context.c: + * src/arch/context.c: + * src/arch/context.h: + * src/arch/context-int.h: + Protect data access using locks. + + * src/common/bits.c: + * src/common/bits.h: + Add bits to bit fields in an atomic way. + + * src/format/elf/elf.c: + Do not load inner sections as portions. + + * src/format/symbol.h: + Define the HAS_DATA_INSTR macro to filter symbols. + 15-11-26 Cyrille Bagard * plugins/pychrysa/analysis/content.c: diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c index 1d841be..355b716 100644 --- a/src/analysis/disass/area.c +++ b/src/analysis/disass/area.c @@ -27,6 +27,1087 @@ #include +#include + + +#include "../../analysis/contents/restricted.h" +#include "../../common/bits.h" +#include "../../gui/panels/log.h" + + + + +/* Zone mémoire bien bornée */ +typedef struct _mem_area_v2 +{ + GBinFormat *format; /* Format du fichier binaire */ + GBinContent *content; /* Données binaires à lire */ + GArchProcessor *proc; /* Architecture du binaire */ + SourceEndian endianness; /* Boutisme de cette machine */ + + mrange_t range; /* Couverture de la zone */ + + phys_t packing_size; /* Granularité des découpages */ + + bitfield_t *processed; /* Octets traités dans la zone */ + GArchInstruction **instructions; /* Instructions en place */ + + + + + bool is_exec; /* Zone exécutable ? */ + +} mem_area_v2; + + + +/* Initialise une aire de données à partir d'une adresse donnée. */ +static void init_mem_area_from_addr_v2(mem_area_v2 *, const vmpa2t *, phys_t, const GLoadedBinary *); + +/* Libère d'une aire de données les ressources allouées. */ +static void fini_mem_area_v2(mem_area_v2 *); + +/* Indique si une zone donnée est intégralement vierge ou non. */ +static bool is_range_blank_in_mem_area_v2(mem_area_v2 *, phys_t, phys_t); + +/* Marque une série d'octets comme ayant été traités. */ +static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *, GArchInstruction *, bool); + + + + +/* Procède au désassemblage d'un contenu binaire non exécutable. */ +static void load_data_from_mem_area_v2(mem_area_v2 *, GProcContext *, const vmpa2t *, status_blob_info *); + +/* S'assure qu'une aire contient toutes ses instructions. */ +static void fill_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, status_blob_info *); + +/* Rassemble les instructions conservées dans une zone donnée. */ +static GArchInstruction *get_instructions_from_mem_area_v2(const mem_area_v2 *); + + + + + + +/* S'assure de la présence d'un début de routine à un point. */ +static void update_address_as_routine(GBinFormat *, const vmpa2t *); + + +/** + * Content :: à passer en restricted. + + * Les sections croisées : pas de sens de les traiter ici, car au final une instruction sera à cheval + * sur deux sections différentes -> incohérence au niveau de l'éditeur. + * => régler le périmètres de segments règle donc tous les soucis. + + */ + + + + + + + + +/****************************************************************************** +* * +* 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. * +* binary = binaire analysé content quantités d'informations. * +* * +* Description : Initialise une aire de données à partir d'une adresse donnée.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void init_mem_area_from_addr_v2(mem_area_v2 *area, const vmpa2t *addr, phys_t len, const GLoadedBinary *binary) +{ + GBinContent *content; /* Données binaires à lire */ + + assert(len > 0); + + area->format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); + + content = g_binary_format_get_content(area->format); + + area->proc = g_loaded_binary_get_processor(binary); + area->endianness = g_arch_processor_get_endianness(area->proc); + + init_mrange(&area->range, addr, len); + + area->content = g_restricted_content_new(content, &area->range); + + area->packing_size = 2; /* FIXME */ + + area->processed = create_bit_field(len, false); + 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_v2(mem_area_v2 *area) +{ + phys_t len; /* Etendue du parcours total */ + phys_t i; /* Boucle de parcours */ + + //g_object_unref(area->format); /* FIXME */ + g_object_unref(area->content); + //g_object_unref(area->proc); /* FIXME */ + + delete_bit_field(area->processed); + + len = get_mrange_length(&area->range); + + for (i = 0; i < len; i++) + if (area->instructions[i] != NULL) + g_object_unref(G_OBJECT(area->instructions[i])); + + free(area->instructions); + +} + + +/****************************************************************************** +* * +* 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. * +* * +* 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_v2(mem_area_v2 *area, phys_t start, phys_t len) +{ + bool result; /* Résultat à renvoyer */ + + if ((start + len) >= get_mrange_length(&area->range)) + result = false; + + else + result = !test_in_bit_field(area->processed, start, len); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* instr = instruction à mémoriser pour la suite. * +* force = impose l'enregistrement de l'instruction. * +* * +* Description : Marque une série d'octets comme ayant été traités. * +* * +* Retour : true si l'enregistrement a bien été réalisé, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *area, GArchInstruction *instr, bool force) +{ + bool result; /* Bilan d'action à renvoyer */ + const vmpa2t *start; /* Adresse de départ de la zone*/ + const mrange_t *range; /* Emplacement d'instruction */ + const vmpa2t *addr; /* Début de la zone à traiter */ + phys_t len; /* Taille de l'aire visée */ + phys_t offset; /* Décallage de départ */ + + start = get_mrange_addr(&area->range); + + range = g_arch_instruction_get_range(instr); + addr = get_mrange_addr(range); + len = get_mrange_length(range); + + offset = compute_vmpa_diff(start, addr); + + result = set_atomic_in_bit_field(area->processed, offset, len); + + /* Si l'instruction était bien la première à s'inscrire... */ + + result |= force; + + if (result) + area->instructions[offset] = instr; + + return result; + +} + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* list = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* index = indice de l'aire à considérer pendant l'opération. * +* 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_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, const vmpa2t *start, status_blob_info *info) +{ + + + + GBinFormat *format; /* Format du fichier binaire */ + GArchProcessor *proc; /* Architecture du binaire */ + GBinContent *content; /* 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 */ + + + bool done; /* Enregistrement effectué ? */ + + + vmpa2t sym_addr; /* Adresse de nouveau symbole */ + bool has_new_sym; /* Statut d'un dépilement */ + + GBinSymbol *symbol; /* Symbole créé en parallèle */ + + + + + + /* Récupération des informations de base */ + + format = area->format; + proc = area->proc; + content = area->content; + + diff = compute_vmpa_diff(get_mrange_addr(&area->range), start); + alen = get_mrange_length(&area->range); + + copy_vmpa(&pos, start); + + /* Traitement de la zone */ + + printf("=== processing @ 0x%08x\n", (unsigned int)start->virtual); + + for (i = diff; i < alen; i += diff) + { + /** + * On réalise un premier test informel (car non atomique) peu coûteux + * avant de se lancer dans un désassemblage d'instruction potentiellement + * inutile. + */ + + printf(" (%u) blank ? %d\n", (unsigned int)i, is_range_blank_in_mem_area_v2(area, i, 1)); + printf(" +1 blank ? %d\n", is_range_blank_in_mem_area_v2(area, i + 1, 1)); + + if (!is_range_blank_in_mem_area_v2(area, i, 1)) + break; + + /* Décodage d'une nouvelle instruction */ + + copy_vmpa(&prev, &pos); + + instr = g_arch_processor_disassemble(proc, ctx, content, &pos); + 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); + + /* Progression dans les traitements */ + + done = mark_range_in_mem_area_as_processed_v2(area, instr, false); + + if (!done) + { + g_object_unref(G_OBJECT(instr)); + break; + } + + inc_progessive_status(info, diff); + + assert(!is_range_blank_in_mem_area_v2(area, i, diff)); + + /* Enregistrement d'un éventuel début de routine */ + + if (g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START) + update_address_as_routine(format, &prev); + + /* Eventuel renvoi vers d'autres adresses */ + + g_arch_instruction_call_hook(instr, IPH_FETCH, proc, ctx, format); + + /* Insertion des symboles découverts en parallèle */ + + for (has_new_sym = g_proc_context_pop_new_symbol_at(ctx, &sym_addr); + has_new_sym; + has_new_sym = g_proc_context_pop_new_symbol_at(ctx, &sym_addr)) + { + has_new_sym = g_binary_format_find_symbol_at(format, &sym_addr, &symbol); + assert(has_new_sym); + + insert_extra_symbol_into_mem_areas_v2(list, count, symbol); + + } + + /* Rupture du flot d'exécution ? */ + if (g_arch_instruction_get_flags(instr) & AIF_RETURN_POINT) + break; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : area = aire représentant à contenu à parcourir. * +* 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_v2(mem_area_v2 *area, GProcContext *ctx, const vmpa2t *start, status_blob_info *info) +{ + GBinContent *content; /* Données binaires à lire */ + SourceEndian endianness; /* Boutisme de cette machine */ + phys_t diff; /* Volume de données traité */ + phys_t alen; /* Taille de l'aire utilisée */ + vmpa2t pos; /* Boucle de parcours */ + phys_t i; /* Boucle de parcours */ + vmpa2t prev; /* Boucle de parcours */ + GArchInstruction *instr; /* Instruction décodée */ + mrange_t range; /* Couverture de l'instruction */ + bool done; /* Enregistrement effectué ? */ + + /* Récupération des informations de base */ + + content = area->content; + endianness = area->endianness; + + diff = compute_vmpa_diff(get_mrange_addr(&area->range), start); + alen = get_mrange_length(&area->range); + + copy_vmpa(&pos, start); + + /* Traitement de la zone */ + + for (i = diff; i < alen; i += diff) + { + /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */ + + if (!is_range_blank_in_mem_area_v2(area, i, 1)) + break; + + instr = NULL; + + copy_vmpa(&prev, &pos); + + /* Décodage d'une nouvelle instruction, sur mesure puis minimale */ + + if (get_virt_addr(&pos) % area->packing_size == 0 + && is_range_blank_in_mem_area_v2(area, i, area->packing_size)) + { + diff = area->packing_size; + + instr = g_raw_instruction_new_array(content, MDS_FROM_BYTES(diff), 1, &pos, endianness); + + if (instr == NULL) + copy_vmpa(&pos, &prev); + + } + + if (instr == NULL) + { + diff = 1; + + instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, &pos, endianness); + + } + + /* On rencontre ici un morceau déjà traité. */ + + if (instr == NULL) break; + + /* Enregistrement des positions et adresses */ + + assert(diff == compute_vmpa_diff(&prev, &pos)); + + init_mrange(&range, &prev, diff); + + g_arch_instruction_set_range(instr, &range); + + /* Progression dans les traitements */ + + done = mark_range_in_mem_area_as_processed_v2(area, instr, false); + + if (!done) + { + g_object_unref(G_OBJECT(instr)); + break; + } + + inc_progessive_status(info, diff); + + assert(!is_range_blank_in_mem_area_v2(area, i, diff)); + + /* On laisse une chance au code pour se reprendre... */ + + if (area->is_exec) break; + + } + +} + + +/****************************************************************************** +* * +* 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_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, status_blob_info *info) +{ + const vmpa2t *addr; /* Début de la zone à traiter */ + phys_t len; /* Taille de la zone à remplir */ + phys_t i; /* Boucle de parcours */ + vmpa2t start; /* Adresse de départ de combles*/ + + addr = get_mrange_addr(&area->range); + len = get_mrange_length(&area->range); + + for (i = 0; i < len; i++) + { + if (is_range_blank_in_mem_area_v2(area, i, 1)) + { + copy_vmpa(&start, addr); + advance_vmpa(&start, i); + + if (area->is_exec && get_virt_addr(&start) % area->packing_size == 0) + load_code_from_mem_area_v2(area, list, count, ctx, &start, info); + + if (is_range_blank_in_mem_area_v2(area, i, 1)) + load_data_from_mem_area_v2(area, ctx, &start, info); + + } + + assert(!is_range_blank_in_mem_area_v2(area, i, 1)); + + } + +} + + +/****************************************************************************** +* * +* 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_v2(const mem_area_v2 *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; + + 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 : 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 : Indice de la zone trouvée, ou nombre d'aires en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +mem_area_v2 *find_memory_area_by_addr_v2(mem_area_v2 *list, size_t count, const vmpa2t *addr) +{ + mem_area_v2 *result; /* Elément trouvé à renvoyer */ + + int find_mem_area(const vmpa2t *addr, const mem_area_v2 *area) + { + int status; /* Bilan à retourner */ + + if (mrange_contains_addr(&area->range, addr)) + status = 0; + + else + status = cmp_vmpa(addr, get_mrange_addr(&area->range)); + + return status; + + } + + result = bsearch(addr, list, count, sizeof(mem_area_v2), (__compar_fn_t)find_mem_area); + + return result; + +} + + + + + + + + +/****************************************************************************** +* * +* 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_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_length, size_t *count) +{ + mem_area_v2 *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_v2 *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 */ + 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_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2)); + + area = &result[*count - 1]; + + init_mem_area_from_addr_v2(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_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2)); + + area = &result[*count - 1]; + + init_mem_area_from_addr_v2(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_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2)); + + area = &result[*count - 1]; + + init_mem_area_from_addr_v2(area, &tmp, bin_length - get_phy_addr(&tmp), binary); + area->is_exec = false; + + } + + + + + + + + + for (i = 0; i < *count; i++) + { + printf(" (init) AREA %zu :: 0x%x / 0x%x + 0x%x\n", + i, + (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)), + (unsigned int)get_virt_addr(get_mrange_addr(&result[i].range)), + (unsigned int)get_mrange_length(&result[i].range)); + + } + + printf("--------------------\n"); + + + + + + + + + /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */ + + 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])); + + printf(" [portion % 3zu] addr = 0x%x / 0x%x\n", + i, + (unsigned int)get_phy_addr(portion_start), + (unsigned int)get_virt_addr(portion_start)); + + 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_v2(&result[j]); + + result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2)); + + memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area_v2)); + + 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_v2(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_v2(area, portion_start, length, binary); + area->is_exec = status; + + } + + j = *count; + + } + + } + + + + + + + + + for (i = 0; i < *count; i++) + { + printf(" (fini) AREA %zu :: 0x%x / 0x%x + 0x%x\n", + i, + (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)), + (unsigned int)get_virt_addr(get_mrange_addr(&result[i].range)), + (unsigned int)get_mrange_length(&result[i].range)); + + } + + printf("--------------------\n"); + + + + + + + + + /* 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_v2(result, *count, symbols[i]); + + } + + /* Nettoyage final */ + + if (portions != NULL) + free(portions); + + if (exe_ranges != NULL) + free(exe_ranges); + + /// FIXME g_object_unref(G_OBJECT(format)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : areas = liste de zones délimitant des contenus à traiter. * +* count = nombre de zones à disposition. * +* symbol = élément nouveau à venir insérer dans les zones. * +* * +* Description : Insère un symbole dans un découpage en aires. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *areas, size_t count, const GBinSymbol *symbol) +{ + SymbolType type; /* Type de symbole */ + GArchInstruction *list; /* Ensemble à insérer */ + GArchInstruction *iter; /* Boucle de parcours */ + const mrange_t *range; /* Emplacement d'instruction */ + const vmpa2t *addr; /* Départ de cet emplacement */ + mem_area_v2 *area; /* Zone d'accueil désignée */ + VMPA_BUFFER(loc); /* Description d'un emplacement*/ + phys_t start; /* Point de départ */ + + type = g_binary_symbol_get_target_type(symbol); + + if (!HAS_DATA_INSTR(type)) + return; + + list = g_binary_symbol_get_instruction(symbol); + + for (iter = list; iter != NULL; iter = g_arch_instruction_get_next_iter(list, iter, ~0)) + { + range = g_arch_instruction_get_range(iter); + addr = get_mrange_addr(range); + + /* Une aire d'accueil existe-t-elle ? */ + + area = find_memory_area_by_addr_v2(areas, count, addr); + + if (area == NULL) + { + vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL); + + log_variadic_message(LMT_WARNING, _("No place found for symbol located at %s."), loc); + continue; + + } + + /* L'instruction est-elle accueillie dans son intégralité ? */ + + start = compute_vmpa_diff(get_mrange_addr(&area->range), addr); + + if (start + get_mrange_length(range) > get_mrange_length(&area->range)) + { + vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL); + + log_variadic_message(LMT_WARNING, _("The symbol located at %s is too big for one place only."), loc); + continue; + + } + + /* Inscription d'une instruction de symbole (sans retour arrière possible :/ ) */ + + mark_range_in_mem_area_as_processed_v2(area, iter, true); + + g_object_ref(G_OBJECT(iter)); + + } + +} + + +/****************************************************************************** +* * +* 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_v2 *list, size_t count, GProcContext *ctx, status_blob_info *info) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < count; i++) + fill_mem_area_v2(&list[i], list, count, 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_v2(const mem_area_v2 *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_v2(&list[i]); + g_arch_instruction_merge_lists(&result, &instr); + } + + return result; + +} + + + + + + + + + + + + + + + +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// +//////////////////////////////////:::////////////////////////////////////////////////////////////////////// + + + /* Zone mémoire bien bornée */ typedef struct _mem_area @@ -72,7 +1153,7 @@ static bool mark_range_in_mem_area_as_processed(mem_area *, phys_t, phys_t, GArc /* S'assure de la présence d'un début de routine à un point. */ -static void update_address_as_routine(GBinFormat *, const vmpa2t *); +//static void update_address_as_routine(GBinFormat *, const vmpa2t *); @@ -1468,8 +2549,6 @@ static bool insert_extra_symbol_into_mem_areas(mem_area **list, size_t *count, G memmove(&(*list)[index + 1], &(*list)[index], (*count - index - 1) * sizeof(mem_area)); - /* Aire raccourcie */ - copy_vmpa(&area_pos, get_mrange_addr(&area_range)); new_length = get_mrange_length(&area_range) - get_mrange_length(sym_range); diff --git a/src/analysis/disass/area.h b/src/analysis/disass/area.h index 35a3533..aa26da0 100644 --- a/src/analysis/disass/area.h +++ b/src/analysis/disass/area.h @@ -25,10 +25,52 @@ #define _ANALYSIS_DISASS_AREA_H +#include "../binary.h" +#include "../../arch/instruction.h" +#include "../../gtkext/gtkextstatusbar.h" + + + + +/* Zone mémoire bien bornée */ +typedef struct _mem_area_v2 mem_area_v2; + + + + + +/* Procède au désassemblage d'un contenu binaire exécutable. */ +void load_code_from_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, const vmpa2t *, status_blob_info *); + + + + +/* Détermine une liste de zones contigües à traiter. */ +mem_area_v2 *find_memory_area_by_addr_v2(mem_area_v2 *, size_t, const vmpa2t *); + + + +/* Détermine une liste de zones contigües à traiter. */ +mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *, phys_t, size_t *); + +/* Insère un symbole dans un découpage en aires. */ +void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *, size_t, const GBinSymbol *); + +/* S'assure que l'ensemble des aires est entièrement décodé. */ +void ensure_all_mem_areas_are_filled(mem_area_v2 *, size_t, GProcContext *, status_blob_info *); + +/* Rassemble les instructions conservées dans des zones données. */ +GArchInstruction *collect_instructions_from_mem_areas_v2(const mem_area_v2 *, size_t); + + + + + #include + #include "../binary.h" #include "../../format/executable.h" #include "../../gtkext/gtkextstatusbar.h" @@ -48,6 +90,7 @@ typedef struct _mem_area mem_area; + /* Procède au désassemblage d'un contenu binaire exécutable. */ bool load_code_from_mem_area(mem_area **, size_t *, size_t *, const GLoadedBinary *, GProcContext *, const vmpa2t *, status_blob_info *); diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c index ce49aca..ce2e6ff 100644 --- a/src/analysis/disass/disassembler.c +++ b/src/analysis/disass/disassembler.c @@ -190,6 +190,8 @@ static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *binary, GAr static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar) { + wgroup_id_t gid; /* Identifiant pour les tâches */ + //GBinFormat *format; /* Format du fichier binaire */ GArchProcessor *proc; /* Architecture du binaire */ @@ -208,6 +210,13 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta //GArchProcessor *proc; /* Architecture du binaire */ + + gid = g_work_queue_define_work_group(get_work_queue()); + + + + + //format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); proc = g_loaded_binary_get_processor(disass->binary); @@ -225,7 +234,7 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta - *disass->instrs = disassemble_binary_content(disass->binary, statusbar); + *disass->instrs = disassemble_binary_content(disass->binary, gid, statusbar); g_arch_processor_set_disassembled_instructions(proc, *disass->instrs); diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c index 67a6f3b..bfc0598 100644 --- a/src/analysis/disass/fetch.c +++ b/src/analysis/disass/fetch.c @@ -31,18 +31,331 @@ #include "area.h" +#include "../../glibext/delayed-int.h" + + + + + + + + +/* ------------------------- RECUPERATIONS EN TOILE DE FOND ------------------------- */ +/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ + + +#define G_TYPE_DELAYED_FETCHING g_delayed_fetching_get_type() +#define G_DELAYED_FETCHING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_fetching_get_type(), GDelayedFetching)) +#define G_IS_DELAYED_FETCHING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_fetching_get_type())) +#define G_DELAYED_FETCHING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_FETCHING, GDelayedFetchingClass)) +#define G_IS_DELAYED_FETCHING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_FETCHING)) +#define G_DELAYED_FETCHING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_FETCHING, GDelayedFetchingClass)) + + +/* Ensembles binaires à désassembler (instance) */ +typedef struct _GDelayedFetching +{ + GDelayedWork parent; /* A laisser en premier */ + + wgroup_id_t gid; /* Groupe de travail parallèle */ + + GExeFormat *format; /* Format du fichier binaire */ + + GProcContext *ctx; /* Contexte de désassemblage */ + mem_area_v2 *areas; /* Zone de productions */ + size_t count; /* Nombre de ces zones */ + status_blob_info *info; /* Informations de progression */ + + virt_t virt; /* Adresse de départ dépilée */ + +} GDelayedFetching; + +/* Ensembles binaires à désassembler (classe) */ +typedef struct _GDelayedFetchingClass +{ + GDelayedWorkClass parent; /* A laisser en premier */ + +} GDelayedFetchingClass; + + +/* Indique le type défini pour les tâches de récupération différée. */ +GType g_delayed_fetching_get_type(void); + +/* Initialise la classe des tâches de désassemblage différé. */ +static void g_delayed_fetching_class_init(GDelayedFetchingClass *); + +/* Initialise une tâche de désassemblage différé. */ +static void g_delayed_fetching_init(GDelayedFetching *); + +/* Supprime toutes les références externes. */ +static void g_delayed_fetching_dispose(GDelayedFetching *); + +/* Procède à la libération totale de la mémoire. */ +static void g_delayed_fetching_finalize(GDelayedFetching *); + +/* Crée une tâche de récupération d'instructions différée. */ +static GDelayedFetching *g_delayed_fetching_new(const GDelayedFetching *, virt_t); + +/* Assure la récupération d'instructions en différé. */ +static void g_delayed_fetching_process(GDelayedFetching *, GtkExtStatusBar *); + + + + + + + + + + +/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ +/* ------------------------ DESASSEMBLAGE DE BINAIRE DIFFERE ------------------------ */ + /* Suit un flot d'exécution pour désassembler du code. */ static void follow_execution_flow(const GLoadedBinary *, GProcContext *, mem_area **, size_t *, status_blob_info *); -/* S'assure que l'ensemble des aires est entièrement décodé. */ -static void ensure_all_mem_areas_are_filled(mem_area **, size_t *, const GLoadedBinary *, GProcContext *, status_blob_info *); + + +/* ---------------------------------------------------------------------------------- */ +/* RECUPERATIONS EN TOILE DE FOND */ +/* ---------------------------------------------------------------------------------- */ + + + + + + + + +/* Indique le type défini pour les tâches de récupération différée. */ +G_DEFINE_TYPE(GDelayedFetching, g_delayed_fetching, G_TYPE_DELAYED_WORK); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tâches de récupération différée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_fetching_class_init(GDelayedFetchingClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDelayedWorkClass *work; /* Version en classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_fetching_dispose; + object->finalize = (GObjectFinalizeFunc)g_delayed_fetching_finalize; + + work = G_DELAYED_WORK_CLASS(klass); + + work->run = (run_task_fc)g_delayed_fetching_process; + +} + + +/****************************************************************************** +* * +* Paramètres : fetching = instance à initialiser. * +* * +* Description : Initialise une tâche de récupération différée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_fetching_init(GDelayedFetching *fetching) +{ + + + +} + + +/****************************************************************************** +* * +* Paramètres : fetching = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_fetching_dispose(GDelayedFetching *fetching) +{ + g_object_unref(G_OBJECT(fetching->format)); + + g_object_unref(G_OBJECT(fetching->ctx)); + + G_OBJECT_CLASS(g_delayed_fetching_parent_class)->dispose(G_OBJECT(fetching)); + +} + + +/****************************************************************************** +* * +* Paramètres : fetching = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_fetching_finalize(GDelayedFetching *fetching) +{ + G_OBJECT_CLASS(g_delayed_fetching_parent_class)->finalize(G_OBJECT(fetching)); + +} + + +/****************************************************************************** +* * +* Paramètres : template = modèle dont les informations sont à copier. * +* virt = point départ dépilé et personnalisant l'instance. * +* * +* Description : Crée une tâche de récupération d'instructions différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDelayedFetching *g_delayed_fetching_new(const GDelayedFetching *template, virt_t virt) +{ + GDelayedFetching *result; /* Tâche à retourner */ + + result = g_object_new(G_TYPE_DELAYED_FETCHING, NULL); + + result->gid = template->gid; + + result->format = template->format; + g_object_ref(G_OBJECT(result->format)); + + result->ctx = template->ctx; + g_object_ref(G_OBJECT(result->ctx)); + + result->areas = template->areas; + result->count = template->count; + result->info = template->info; + + result->virt = virt; + + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : fetching = récupération à mener. * +* statusbar = barre de statut à tenir informée. * +* * +* Description : Assure la récupération d'instructions en différé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_delayed_fetching_process(GDelayedFetching *fetching, GtkExtStatusBar *statusbar) +{ + vmpa2t addr; /* Conversion en pleine adresse*/ + mem_area_v2 *area; /* Zone trouvée à traiter */ + + if (!g_exe_format_translate_address_into_vmpa(fetching->format, fetching->virt, &addr)) + init_vmpa(&addr, VMPA_NO_PHYSICAL, fetching->virt); + + area = find_memory_area_by_addr_v2(fetching->areas, fetching->count, &addr); + + if (area != NULL) + load_code_from_mem_area_v2(area, fetching->areas, fetching->count, + fetching->ctx, &addr, fetching->info); + +} + + + + + + + + + + +/* Poursuit l'analyse à partir des points d'entrée découverts. */ +static void follow_execution_flow_v2(GProcContext *, const GDelayedFetching *); + + + + + + + +/****************************************************************************** +* * +* Paramètres : ctx = contexte de désass. avec une nouvelle entrée. * +* template = modèle dont les informations sont à copier. * +* * +* Description : Poursuit l'analyse à partir des points d'entrée découverts. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void follow_execution_flow_v2(GProcContext *ctx, const GDelayedFetching *template) +{ + GWorkQueue *queue; /* Gestionnaire de différés */ + virt_t virt; /* Adresse de départ dépilée */ + GDelayedFetching *fetching; /* Récupération à mener */ + + queue = get_work_queue(); + + while (g_proc_context_pop_drop_point(ctx, &virt)) + { + fetching = g_delayed_fetching_new(template, virt); + + /** + * Pas très élégant : l'identifiant du groupe de travail ne sert qu'ici ; + * il n'est donc aucune utilité dans la tâche elle-même. + * + * Cependant, les paramètres d'appel étant limités, il faudrait créer + * une structure intermediare pour communiquer l'identifiant, ce qui + * est tout aussi moche. + */ + + g_work_queue_schedule_work(queue, G_DELAYED_WORK(fetching), template->gid); + + } + +} + + /****************************************************************************** * * * Paramètres : binary = représentation de binaire chargé. * @@ -68,7 +381,7 @@ static void follow_execution_flow(const GLoadedBinary *binary, GProcContext *ctx while (g_proc_context_has_drop_points(ctx)) { - virt = g_proc_context_pop_drop_point(ctx); + g_proc_context_pop_drop_point(ctx, &virt); format = g_loaded_binary_get_format(binary); @@ -96,38 +409,13 @@ static void follow_execution_flow(const GLoadedBinary *binary, GProcContext *ctx } - -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ - -static void ensure_all_mem_areas_are_filled(mem_area **list, size_t *count, const GLoadedBinary *binary, GProcContext *ctx, status_blob_info *info) -{ - size_t i; /* Boucle de parcours */ - - for (i = 0; i < *count; i++) - fill_mem_area(list, count, &i, binary, ctx, info); - -} - +static GDelayedFetching template; /* Patron des tâches à venir */ /****************************************************************************** * * * Paramètres : binary = représentation de binaire chargé. * +* gid = identifiant du groupe de travail à utiliser. * * 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. * * * @@ -137,75 +425,96 @@ static void ensure_all_mem_areas_are_filled(mem_area **list, size_t *count, cons * * ******************************************************************************/ -GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, GtkExtStatusBar *statusbar) +GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup_id_t gid, GtkExtStatusBar *statusbar) { GArchInstruction *result; /* Instruction désassemblées */ + //GDelayedFetching template; /* Patron des tâches à venir */ GBinFormat *format; /* Format du fichier binaire */ GArchProcessor *proc; /* Architecture du binaire */ - GProcContext *ctx; /* Contexte de désassemblage */ GBinContent *content; /* Contenu binaire à manipuler */ phys_t length; /* Taille des données à lire */ - mem_area *areas; /* Zone de productions */ - size_t count; /* Nombre de ces zones */ - status_blob_info *info; /* Informations de progression */ + GWorkQueue *queue; /* Gestionnaire de différés */ double done; /* Portion de travail accompli */ - format = G_BIN_FORMAT(g_loaded_binary_get_format(binary)); - proc = g_loaded_binary_get_processor(binary); - ctx = g_arch_processor_get_context(proc); - g_binary_format_setup_disassembling_context(format, ctx); - /* Définition à la découpe des parties à traiter */ + + + + + + /* Constitution du modèle de référence */ + + template.gid = gid; + + template.format = g_loaded_binary_get_format(binary); + format = G_BIN_FORMAT(template.format); + + proc = g_loaded_binary_get_processor(binary); + template.ctx = g_arch_processor_get_context(proc); + g_object_unref(G_OBJECT(proc)); content = g_binary_format_get_content(format); length = g_binary_content_compute_size(content); + g_object_unref(G_OBJECT(content)); - areas = compute_memory_areas(G_EXE_FORMAT(format), length, &count); + template.areas = compute_memory_areas_v2(binary, length, &template.count); + + /* Amorce des traitements */ + + g_signal_connect(template.ctx, "drop-point-pushed", G_CALLBACK(follow_execution_flow_v2), &template); + + queue = get_work_queue(); /** * Première phase de désassemblage : suivi des chemins tracés. */ - info = init_progessive_status(statusbar, - _("Disassembling following the execution flow..."), - 0, length); + template.info = init_progessive_status(statusbar, + _("Disassembling following the execution flow..."), + 0, length); + + g_binary_format_setup_disassembling_context(format, template.ctx); + + g_work_queue_wait_for_completion(queue, gid); - follow_execution_flow(binary, ctx, &areas, &count, info); + printf("===================== DONE !\n"); - done = get_current_progessive_status(info); + done = get_current_progessive_status(template.info); - fini_progessive_status(info); + fini_progessive_status(template.info); /** * Seconde phase : on comble les trous laissés. */ - info = init_progessive_status(statusbar, - _("Disassembling the remaining instructions..."), - done, length); + template.info = init_progessive_status(statusbar, + _("Disassembling the remaining instructions..."), + done, length); - ensure_all_mem_areas_are_filled(&areas, &count, binary, ctx, info); + ensure_all_mem_areas_are_filled(template.areas, template.count, template.ctx, template.info); - fini_progessive_status(info); + fini_progessive_status(template.info); /** * Troisième et dernière phase : récolte des fruits. */ - info = init_progessive_status(statusbar, - _("Collecting disassembled instructions..."), - 0, length); + template.info = init_progessive_status(statusbar, + _("Collecting disassembled instructions..."), + 0, length); - result = collect_instructions_from_mem_areas(areas, count); + result = collect_instructions_from_mem_areas_v2(template.areas, template.count); - fini_progessive_status(info); + fini_progessive_status(template.info); - /* free */ + /* Libérations finales */ - g_object_unref(G_OBJECT(content)); + //g_object_unref(G_OBJECT(template.format)); - g_object_unref(G_OBJECT(proc)); + g_object_unref(G_OBJECT(template.ctx)); + + /* TODO / del(areas); */ return result; diff --git a/src/analysis/disass/fetch.h b/src/analysis/disass/fetch.h index 0270f78..37dac80 100644 --- a/src/analysis/disass/fetch.h +++ b/src/analysis/disass/fetch.h @@ -26,12 +26,13 @@ #include "../binary.h" +#include "../../glibext/delayed.h" #include "../../gtkext/gtkextstatusbar.h" /* Procède au désassemblage basique d'un contenu binaire. */ -GArchInstruction *disassemble_binary_content(const GLoadedBinary *, GtkExtStatusBar *); +GArchInstruction *disassemble_binary_content(const GLoadedBinary *, wgroup_id_t, GtkExtStatusBar *); diff --git a/src/arch/archbase.h b/src/arch/archbase.h index 24cfd77..fc6fe4d 100644 --- a/src/arch/archbase.h +++ b/src/arch/archbase.h @@ -74,6 +74,31 @@ typedef enum _MemoryDataSize #define MDS_IS_SIGNED(mds) (mds & 0x80) +#define MDS_FROM_BYTES(sz) \ + ({ \ + MemoryDataSize __result; \ + switch (sz) \ + { \ + case 1: \ + __result = MDS_8_BITS_UNSIGNED; \ + break; \ + case 2: \ + __result = MDS_16_BITS_UNSIGNED; \ + break; \ + case 4: \ + __result = MDS_32_BITS_UNSIGNED; \ + break; \ + case 8: \ + __result = MDS_64_BITS_UNSIGNED; \ + break; \ + default: \ + __result = MDS_UNDEFINED; \ + break; \ + } \ + __result; \ + }) + + #define MDS_4_BITS MDS_4_BITS_UNSIGNED #define MDS_8_BITS MDS_8_BITS_UNSIGNED #define MDS_16_BITS MDS_16_BITS_UNSIGNED diff --git a/src/arch/arm/context-int.h b/src/arch/arm/context-int.h index 51ed6d0..fbd3a6f 100644 --- a/src/arch/arm/context-int.h +++ b/src/arch/arm/context-int.h @@ -50,6 +50,7 @@ struct _GArmContext disass_arm_area *areas; /* Désassemblage découpé */ size_t acount; /* Nombre de zones définies */ + GMutex areas_access; /* Accès aux découpes de zones */ }; diff --git a/src/arch/arm/context.c b/src/arch/arm/context.c index b54de42..d805e8c 100644 --- a/src/arch/arm/context.c +++ b/src/arch/arm/context.c @@ -139,6 +139,7 @@ static void g_arm_context_class_init(GArmContextClass *klass) static void g_arm_context_init(GArmContext *ctx) { + g_mutex_init(&ctx->areas_access); } @@ -157,6 +158,8 @@ static void g_arm_context_init(GArmContext *ctx) static void g_arm_context_dispose(GArmContext *ctx) { + g_mutex_clear(&ctx->areas_access); + G_OBJECT_CLASS(g_arm_context_parent_class)->dispose(G_OBJECT(ctx)); } @@ -263,11 +266,11 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int { size_t selected; /* Zone associée à une adresse */ - /* TODO : pose de verroux ? */ + g_mutex_lock(&ctx->areas_access); selected = find_disass_arm_area(ctx->areas, addr, 0, ctx->acount - 1); - assert(ctx->areas[selected].start != addr || ctx->areas[selected].marker == marker); + //assert(ctx->areas[selected].start != addr || ctx->areas[selected].marker == marker); /* S'agit-il d'une redéfinition ? */ if (ctx->areas[selected].start == addr) @@ -290,6 +293,8 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int } + g_mutex_unlock(&ctx->areas_access); + } @@ -308,13 +313,18 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int unsigned int _g_arm_context_find_encoding(GArmContext *ctx, virt_t addr) { + unsigned int result; /* Identifiant à retourner */ size_t selected; /* Zone associée à une adresse */ - /* TODO : pose de verroux ? */ + g_mutex_lock(&ctx->areas_access); selected = find_disass_arm_area(ctx->areas, addr, 0, ctx->acount - 1); - return ctx->areas[selected].marker; + result = ctx->areas[selected].marker; + + g_mutex_unlock(&ctx->areas_access); + + return result; } diff --git a/src/arch/arm/v7/context.c b/src/arch/arm/v7/context.c index 885ce70..030457e 100644 --- a/src/arch/arm/v7/context.c +++ b/src/arch/arm/v7/context.c @@ -245,7 +245,15 @@ void g_armv7_context_push_drop_point_ext(GArmV7Context *ctx, virt_t addr, ArmV7I g_armv7_context_define_encoding(ctx, addr, marker); - G_PROC_CONTEXT_CLASS(g_armv7_context_parent_class)->push_point(G_PROC_CONTEXT(ctx), addr); + /** + * Il faut impérativement passer pour l'interface publique afin : + * - de poser le verrou associé. + * - de déclencher l'émission du signal lié. + * + * Pas d'appel via G_PROC_CONTEXT_CLASS(g_armv7_context_parent_class)->push_point() donc. + */ + + g_proc_context_push_drop_point(G_PROC_CONTEXT(ctx), addr); } diff --git a/src/arch/context-int.h b/src/arch/context-int.h index 64465a2..086a8ec 100644 --- a/src/arch/context-int.h +++ b/src/arch/context-int.h @@ -29,6 +29,10 @@ +/* Granularité des allocations */ +#define DP_ALLOC_BLOCK 10 + + /* Ajoute une adresse virtuelle comme point de départ de code. */ typedef void (* push_drop_point_fc) (GProcContext *, virt_t); @@ -39,7 +43,9 @@ struct _GProcContext GObject parent; /* A laisser en premier */ virt_t *drop_points; /* Liste de points de départ */ - size_t dp_count; /* Taille de cette liste */ + size_t dp_allocated; /* Taille de liste allouée */ + size_t dp_count; /* Quantité utile de la liste */ + GMutex dp_access; /* Accès à la liste FIFO */ vmpa2t *extra_symbols; /* Adresses de symboles */ size_t esyms_count; /* Nombres de nouveautés */ @@ -54,6 +60,10 @@ struct _GProcContextClass push_drop_point_fc push_point; /* Inclusion de points de chute*/ + /* Signaux */ + + void (* drop_point_pushed) (GProcContext *); + }; diff --git a/src/arch/context.c b/src/arch/context.c index 5427e4a..968a6ea 100644 --- a/src/arch/context.c +++ b/src/arch/context.c @@ -65,6 +65,14 @@ static void g_proc_context_class_init(GProcContextClass *klass) { klass->push_point = (push_drop_point_fc)_g_proc_context_push_drop_point; + g_signal_new("drop-point-pushed", + G_TYPE_PROC_CONTEXT, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GProcContextClass, drop_point_pushed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + } @@ -83,7 +91,9 @@ static void g_proc_context_class_init(GProcContextClass *klass) static void g_proc_context_init(GProcContext *ctx) { ctx->drop_points = NULL; + ctx->dp_allocated = 0; ctx->dp_count = 0; + g_mutex_init(&ctx->dp_access); ctx->extra_symbols = NULL; ctx->esyms_count = 0; @@ -106,9 +116,15 @@ static void g_proc_context_init(GProcContext *ctx) 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)); + if (ctx->dp_count >= ctx->dp_allocated) + { + ctx->dp_allocated += DP_ALLOC_BLOCK; + + ctx->drop_points = (virt_t *)realloc(ctx->drop_points, ctx->dp_allocated * sizeof(virt_t)); + + } - ctx->drop_points[ctx->dp_count - 1] = addr; + ctx->drop_points[ctx->dp_count++] = addr; } @@ -128,7 +144,13 @@ static void _g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) { - return G_PROC_CONTEXT_GET_CLASS(ctx)->push_point(ctx, addr); + g_mutex_lock(&ctx->dp_access); + + G_PROC_CONTEXT_GET_CLASS(ctx)->push_point(ctx, addr); + + g_mutex_unlock(&ctx->dp_access); + + g_signal_emit_by_name(ctx, "drop-point-pushed"); } @@ -147,7 +169,15 @@ void g_proc_context_push_drop_point(GProcContext *ctx, virt_t addr) bool g_proc_context_has_drop_points(const GProcContext *ctx) { - return ctx->dp_count > 0; + bool result; /* Etat à retourner */ + + g_mutex_lock(&ctx->dp_access); + + result = (ctx->dp_count > 0); + + g_mutex_unlock(&ctx->dp_access); + + return result; } @@ -172,9 +202,13 @@ bool g_proc_context_has_addr_as_drop_points(const GProcContext *ctx, virt_t addr result = false; + g_mutex_lock(&ctx->dp_access); + for (i = 0; i < ctx->dp_count && !result; i++) result = (ctx->drop_points[i] == addr); + g_mutex_unlock(&ctx->dp_access); + return result; } @@ -183,27 +217,38 @@ bool g_proc_context_has_addr_as_drop_points(const GProcContext *ctx, virt_t addr /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à compléter. * +* virt = adresse d'un point de départ de code à traiter. * * * * Description : Fournit une adresse virtuelle comme point de départ de code. * * * -* Retour : Adresse d'un point de départ de code à traiter. * +* Retour : true si une adresse a pu être dépilée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ -virt_t g_proc_context_pop_drop_point(GProcContext *ctx) +bool g_proc_context_pop_drop_point(GProcContext *ctx, virt_t *virt) { - virt_t result; /* Adresse à retourner */ + bool result; /* Bilan d'accès à retourner */ - assert(ctx->dp_count > 0); + g_mutex_lock(&ctx->dp_access); - result = ctx->drop_points[0]; + if (ctx->dp_count > 0) + { + result = true; + + *virt = ctx->drop_points[0]; + + if (ctx->dp_count > 1) + memmove(&ctx->drop_points[0], &ctx->drop_points[1], (ctx->dp_count - 1) * sizeof(virt_t)); - if (ctx->dp_count > 1) - memmove(&ctx->drop_points[0], &ctx->drop_points[1], (ctx->dp_count - 1) * sizeof(virt_t)); + ctx->dp_count--; + + } + else + result = false; - ctx->drop_points = (virt_t *)realloc(ctx->drop_points, --ctx->dp_count * sizeof(virt_t)); + g_mutex_unlock(&ctx->dp_access); return result; diff --git a/src/arch/context.h b/src/arch/context.h index 390d9f9..973b7ae 100644 --- a/src/arch/context.h +++ b/src/arch/context.h @@ -61,7 +61,7 @@ bool g_proc_context_has_drop_points(const GProcContext *); bool g_proc_context_has_addr_as_drop_points(const GProcContext *, virt_t); /* Fournit une adresse virtuelle comme point de départ de code. */ -virt_t g_proc_context_pop_drop_point(GProcContext *); +bool g_proc_context_pop_drop_point(GProcContext *, virt_t *); /* Empile une adresse de nouveau symbole à prendre en compte. */ void g_proc_context_push_new_symbol_at(GProcContext *, const vmpa2t *); diff --git a/src/common/bits.c b/src/common/bits.c index d451100..b08dcb4 100644 --- a/src/common/bits.c +++ b/src/common/bits.c @@ -25,6 +25,7 @@ #include +#include #include #include @@ -41,6 +42,7 @@ struct _bitfield_t void *tail; /* Limite du tableau de bits */ + GMutex mutex; /* Garantie d'atomicité */ unsigned long bits[0]; /* Mémoire d'accès associée */ }; @@ -94,6 +96,8 @@ static bitfield_t *_create_bit_field(size_t length, bool state, size_t extra) result->tail = ((char *)result) + base; + g_mutex_init(&result->mutex); + if (state) set_all_in_bit_field(result); else @@ -177,6 +181,8 @@ bitfield_t *create_bit_field_from(const bitfield_t *field) void delete_bit_field(bitfield_t *field) { + g_mutex_clear(&field->mutex); + free(field); } @@ -330,6 +336,68 @@ void set_in_bit_field(bitfield_t *field, size_t first, size_t count) /****************************************************************************** * * +* Paramètres : field = champ de bits à modifier. * +* first = indice du premier bit à traiter. * +* count = nombre de bits à marquer. * +* * +* Description : Bascule à 1 de façon atomique une partie d'un champ de bits. * +* * +* Retour : true si la zone traitée était entièrement vierge. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool set_atomic_in_bit_field(bitfield_t *field, size_t first, size_t count) +{ + bool result; /* Bilan à retourner */ + size_t start; /* Mot de départ */ + size_t end; /* Mot d'arrivée */ + size_t remaining; /* Nombre de bits restants */ + unsigned long oldval; /* Ancienne valeur présente */ + unsigned long mask; /* Nouvelle valeur à insérer */ + + start = first / (sizeof(unsigned long) * 8); + end = (first + count - 1) / (sizeof(unsigned long) * 8); + +#if 0 //sizeof(gsize) != sizeof(unsigned long) +# warning "Can not perform atomic operations on bit fields!" +#else + if (start == end) + { + remaining = first % (sizeof(unsigned long) * 8); + + assert(count > 0); + + mask = (1 << count) - 1; + mask <<= remaining; + + oldval = g_atomic_pointer_or(&field->bits[start], mask); + + result = ((oldval & mask) == 0); + + } + else +#endif + { + g_mutex_lock(&field->mutex); + + result = !test_in_bit_field(field, first, count); + + if (result) + set_in_bit_field(field, first, count); + + g_mutex_unlock(&field->mutex); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : dest = champ de bits à modifier. * * src = champ de bits à utiliser pour l'opération. * * * diff --git a/src/common/bits.h b/src/common/bits.h index 0e8ef65..074aac4 100644 --- a/src/common/bits.h +++ b/src/common/bits.h @@ -60,6 +60,9 @@ void set_all_in_bit_field(bitfield_t *); /* Bascule à 1 une partie d'un champ de bits. */ void set_in_bit_field(bitfield_t *, size_t, size_t); +/* Bascule à 1 de façon atomique une partie d'un champ de bits. */ +bool set_atomic_in_bit_field(bitfield_t *, size_t, size_t); + /* Réalise une opération ET logique entre deux champs de bits. */ void and_bit_field(bitfield_t *, const bitfield_t *); @@ -74,6 +77,7 @@ bool is_bit_field_equal_to(const bitfield_t *, const bitfield_t *); + unsigned long gfw(const bitfield_t *); @@ -104,4 +108,9 @@ bool test_in_mem_field(memfield_t *, const vmpa2t *); +#define set_atomic_in_mem_field(f, range) false + + + + #endif /* _COMMON_BITS_H */ diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c index ea520b9..3dc5d64 100644 --- a/src/format/elf/elf.c +++ b/src/format/elf/elf.c @@ -432,6 +432,12 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion * sh_flags = ELF_SHDR(format, section, sh_flags); + printf("[section % 2hu] 0x%08x -> %x -> %d\n", i, sh_flags, + sh_flags & SHF_ALLOC, (sh_flags & SHF_ALLOC) == 0); + + if ((sh_flags & SHF_ALLOC) == 0) + continue; + if (sh_flags & SHF_EXECINSTR) background = BPC_CODE; else if (sh_flags & SHF_WRITE) background = BPC_DATA; else background = BPC_DATA_RO; diff --git a/src/format/symbol.h b/src/format/symbol.h index 1368691..6f38020 100644 --- a/src/format/symbol.h +++ b/src/format/symbol.h @@ -51,6 +51,10 @@ typedef enum _SymbolType } SymbolType; +#define HAS_DATA_INSTR(type) (type == STP_DATA || type == STP_RO_STRING) + + + #define G_TYPE_BIN_SYMBOL g_binary_symbol_get_type() #define G_BIN_SYMBOL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_binary_symbol_get_type(), GBinSymbol)) #define G_IS_BIN_SYMBOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_binary_symbol_get_type())) -- cgit v0.11.2-87-g4458