From 27f44a381ed8c317a16df450ec00ed87bbb9a4b3 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 21 Jun 2018 22:43:23 +0200 Subject: Loaded strings from ELF files using all threads. --- plugins/elf/format.c | 2 +- plugins/elf/loading.c | 150 +++++++++++++++++++++++++++++ plugins/elf/loading.h | 9 ++ plugins/elf/strings.c | 259 +++++++++++++++++++++++++++++++++++++++----------- plugins/elf/strings.h | 8 +- plugins/elf/symbols.h | 1 - 6 files changed, 368 insertions(+), 61 deletions(-) diff --git a/plugins/elf/format.c b/plugins/elf/format.c index 3394ba2..8c0f0fc 100644 --- a/plugins/elf/format.c +++ b/plugins/elf/format.c @@ -392,7 +392,7 @@ static bool g_elf_format_analyze(GElfFormat *format, wgroup_id_t gid, GtkStatusS if (!load_elf_symbols(format, gid, status)) goto gefa_error; - if (!find_all_elf_strings(format)) + if (!find_all_elf_strings(format, gid, status)) goto gefa_error; if (!g_executable_format_complete_loading(exe, status)) diff --git a/plugins/elf/loading.c b/plugins/elf/loading.c index 0bb6f2b..eb992b9 100644 --- a/plugins/elf/loading.c +++ b/plugins/elf/loading.c @@ -49,6 +49,10 @@ struct _GElfLoading phys_t str_start; /* Chaînes à disposition */ + /** + * Gestion des informations de contexte. + */ + union { struct @@ -73,9 +77,23 @@ struct _GElfLoading }; + struct + { + phys_t global_start; /* Départ global dans la zone */ + phys_t global_end; /* Fin globale dans la zone */ + virt_t global_addr; /* Adresse virtuelle initiale */ + + GBinContent *content; /* Contenu binaire à lire */ + const bin_t *data; /* Contenu complet et original */ + + }; }; + /** + * Gestion du mode de parcours. + */ + union { struct @@ -195,6 +213,9 @@ static void g_elf_loading_init(GElfLoading *loading) static void g_elf_loading_dispose(GElfLoading *loading) { + if (loading->kind == 2) + g_object_unref(G_OBJECT(loading->content)); + G_OBJECT_CLASS(g_elf_loading_parent_class)->dispose(G_OBJECT(loading)); } @@ -361,6 +382,64 @@ GElfLoading *g_elf_loading_new_for_applying(GElfFormat *format, sym_iter_t *iter /****************************************************************************** * * +* Paramètres : format = ensemble d'instructions désassemblées. * +* begin = point de départ de la zone à traiter. * +* end = point d'arrivée exclu du parcours. * +* gb_start = position de départ pour l'ensemble des données. * +* gb_end = position finale dans l'ensemble des données. * +* addr = adresse virtuelle de la position initiale. * +* id = identifiant du message affiché à l'utilisateur. * +* callback = routine de traitements particuliers. * +* * +* Description : Crée une tâche de chargement de chaînes pour ELF différée. * +* * +* Retour : Tâche créée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GElfLoading *g_elf_loading_new_for_strings(GElfFormat *format, phys_t begin, phys_t end, phys_t gb_start, phys_t gb_end, virt_t addr, activity_id_t id, elf_loading_cb callback) +{ + GElfLoading *result; /* Tâche à retourner */ + vmpa2t pos; /* Tête de lecture */ + + result = g_object_new(G_TYPE_ELF_LOADING, NULL); + + result->format = format; + + result->global_start = gb_start; + result->global_end = gb_end; + result->global_addr = addr; + + result->content = g_binary_format_get_content(G_BIN_FORMAT(format)); + + init_vmpa(&pos, gb_start, addr); + + result->data = g_binary_content_get_raw_access(result->content, &pos, gb_end - gb_start); + if (result->data == NULL) goto no_data; + + result->begin = begin; + result->end = end; + result->callback_0 = callback; + + result->kind = 2; + + result->id = id; + + return result; + + no_data: + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + + +/****************************************************************************** +* * * Paramètres : loading = traitements différés à mener. * * status = barre de statut à tenir informée. * * * @@ -435,6 +514,24 @@ static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status) loading->status = (processed == loading->rel_count); break; + case 2: + + for (iter = loading->begin; iter < loading->end; ) + { + old = iter; + + loading->status |= loading->callback_0(loading, format, &iter); + + gtk_status_stack_update_activity_value(status, loading->id, iter - old); + + } + + break; + + default: + assert(false); + break; + } } @@ -656,3 +753,56 @@ char *g_elf_loading_build_plt_name(const GElfLoading *loading, uint64_t index) return result; } + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à mener. * +* content = gestionnaire de contenu utilisé. [OUT] * +* first = première position traitée par la tâche. [OUT] * +* offset = décalage pour les données. [OUT] * +* final = première position dans les données à exclure. [OUT]* +* * +* Description : Donne les informations utiles à la recherche de chaînes. * +* * +* Retour : Données brutes à analyser. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const bin_t *g_elf_loading_get_info_for_strings(const GElfLoading *loading, GBinContent **content, phys_t *first, phys_t *offset, phys_t *final) +{ + const bin_t *result; /* Données à communiquer */ + + result = loading->data; + + *content = loading->content; + *first = loading->begin; + *offset = loading->global_start; + *final = loading->global_end; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement pour ELF à poursuivre. * +* iter = point de départ dans la zone de données traitée. * +* pos = emplacement construit à la demande. [OUT] * +* * +* Description : Détermine l'adresse de départ d'une chaîne avec une position.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_elf_loading_compute_string_address(const GElfLoading *loading, const phys_t *iter, vmpa2t *pos) +{ + init_vmpa(pos, *iter, loading->global_addr + (*iter - loading->global_start)); + +} diff --git a/plugins/elf/loading.h b/plugins/elf/loading.h index dcf22e2..e1407f5 100644 --- a/plugins/elf/loading.h +++ b/plugins/elf/loading.h @@ -67,6 +67,9 @@ GElfLoading *g_elf_loading_new_for_relocations(GElfFormat *, phys_t, phys_t, elf /* Crée une tâche de chargement pour ELF différée. */ GElfLoading *g_elf_loading_new_for_applying(GElfFormat *, sym_iter_t *, phys_t, elf_rel *, size_t, phys_t, uint32_t, activity_id_t, elf_applying_cb); +/* Crée une tâche de chargement de chaînes pour ELF différée. */ +GElfLoading *g_elf_loading_new_for_strings(GElfFormat *, phys_t, phys_t, phys_t, phys_t, virt_t, activity_id_t, elf_loading_cb); + /* Fournit le bilan des traitements différés. */ bool g_elf_loading_get_status(const GElfLoading *); @@ -82,6 +85,12 @@ bool g_elf_loading_search_for_relocation(const GElfLoading *, const uint64_t *, /* Construit la désignation adaptée à un symbole importé. */ char *g_elf_loading_build_plt_name(const GElfLoading *, uint64_t); +/* Donne les informations utiles à la recherche de chaînes. */ +const bin_t *g_elf_loading_get_info_for_strings(const GElfLoading *, GBinContent **, phys_t *, phys_t *, phys_t *); + +/* Détermine l'adresse de départ d'une chaîne avec une position. */ +void g_elf_loading_compute_string_address(const GElfLoading *, const phys_t *, vmpa2t *); + #endif /* _PLUGINS_ELF_LOADING_H */ diff --git a/plugins/elf/strings.c b/plugins/elf/strings.c index 6f4edac..cc40db1 100644 --- a/plugins/elf/strings.c +++ b/plugins/elf/strings.c @@ -27,26 +27,47 @@ #include #include #include -#include #include +#include + + #include +#include +#include #include "elf-int.h" +#include "loading.h" #include "section.h" +/** + * Petit complément, sur la base de : + * http://www.cplusplus.com/reference/cctype/ + * + * On veut identifier '\t', '\f','\v','\n','\r', mais sans les caractères + * de contrôle, ni les espaces. + */ + +#define isctrledspace(c) (isspace(c) && c != ' ') + + +/* Lance les vagues de chargement des chaînes de caractères. */ +static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t, GWorkQueue *, wgroup_id_t, GtkStatusStack *, activity_id_t); + /* Enregistre toutes les chaînes de caractères trouvées. */ -static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t); +static bool do_elf_string_loading(GElfLoading *, GElfFormat *, phys_t *); /****************************************************************************** * * * Paramètres : format = description de l'exécutable à analyser. * +* gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * * * * Description : Charge en mémoire toutes les chaînes trouvées. * * * @@ -56,8 +77,10 @@ static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t); * * ******************************************************************************/ -bool find_all_elf_strings(GElfFormat *format) +bool find_all_elf_strings(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status) { + activity_id_t msg; /* Message de progression */ + GWorkQueue *queue; /* Gestionnaire de différés */ bool got_string; /* Indique un remplissage */ phys_t str_start; /* Début de section */ phys_t str_size; /* Taille de section */ @@ -69,12 +92,17 @@ bool find_all_elf_strings(GElfFormat *format) phys_t iter; /* Boucle de parcours #2 */ elf_phdr phdr; /* En-tête de programme ELF */ + msg = gtk_status_stack_add_activity(status, _("Finding all existing strings..."), 0); + + queue = get_work_queue(); + got_string = false; /* Données en lecture seule */ if (find_elf_section_content_by_name(format, ".rodata", &str_start, &str_size, &str_addr)) - got_string |= parse_elf_string_data(format, str_start, str_size, str_addr); + got_string |= parse_elf_string_data(format, str_start, str_size, str_addr, + queue, gid, status, msg); else { @@ -85,7 +113,8 @@ bool find_all_elf_strings(GElfFormat *format) || (ELF_SHDR(format, sections[i], sh_flags) & SHF_STRINGS)) { get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_addr); - got_string |= parse_elf_string_data(format, str_start, str_size, str_addr); + got_string |= parse_elf_string_data(format, str_start, str_size, str_addr, + queue, gid, status, msg); } free(sections); @@ -101,7 +130,8 @@ bool find_all_elf_strings(GElfFormat *format) for (i = 0; i < count; i++) { get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_addr); - got_string |= parse_elf_string_data(format, str_start, str_size, str_addr); + got_string |= parse_elf_string_data(format, str_start, str_size, str_addr, + queue, gid, status, msg); } free(sections); @@ -112,6 +142,8 @@ bool find_all_elf_strings(GElfFormat *format) if (!got_string) { + assert(false); + max = ELF_HDR(format, format->header, e_phoff) + ELF_HDR(format, format->header, e_phnum) * ELF_SIZEOF_PHDR(format); @@ -125,12 +157,15 @@ bool find_all_elf_strings(GElfFormat *format) parse_elf_string_data(format, ELF_PHDR(format, phdr, p_offset), ELF_PHDR(format, phdr, p_filesz), - ELF_PHDR(format, phdr, p_vaddr)); + ELF_PHDR(format, phdr, p_vaddr), + queue, gid, status, msg); } } + gtk_status_stack_remove_activity(status, msg); + return true; } @@ -142,108 +177,218 @@ bool find_all_elf_strings(GElfFormat *format) * start = début de la zone à parcourir. * * size = taille de l'espace à parcourir. * * address = adresse virtuelle du début de la section. * +* wq = espace de travail dédié. * +* gid = groupe de travail impliqué. * +* status = barre de statut à tenir informée. * +* msg = identifiant du message de progression. * +* * +* Description : Lance les vagues de chargement des chaînes de caractères. * +* * +* Retour : true si des chaînes ont été ajoutées, ou false. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address, GWorkQueue *wq, wgroup_id_t gid, GtkStatusStack *status, activity_id_t msg) +{ + bool result; /* Bilan à retourner */ + phys_t final; /* Position finale à atteindre */ + guint runs_count; /* Qté d'exécutions parallèles */ + phys_t run_size; /* Volume réparti par exécution*/ + guint i; /* Boucle de parcours */ + phys_t begin; /* Début de zone de traitement */ + phys_t end; /* Fin d'un zone de traitement */ + GElfLoading **loadings; /* Tâches de chargement lancées*/ + + result = false; + + if (address > 0) + { + final = start + size; + + runs_count = get_max_online_threads(); + + run_size = size / runs_count; + + gtk_status_stack_extend_activity(status, msg, size); + + loadings = (GElfLoading **)malloc(runs_count * sizeof(GElfLoading *)); + + for (i = 0; i < runs_count; i++) + { + begin = start + i * run_size; + + if ((i + 1) == runs_count) + end = final; + else + end = begin + run_size; + + loadings[i] = g_elf_loading_new_for_strings(format, begin, end, start, start + size, address, + msg, do_elf_string_loading); + + if (loadings[i] != NULL) + { + g_object_ref(G_OBJECT(loadings[i])); + g_work_queue_schedule_work(wq, G_DELAYED_WORK(loadings[i]), gid); + } + + } + + g_work_queue_wait_for_completion(wq, gid); + + for (i = 0; i < runs_count; i++) + { + if (loadings[i] == NULL) + continue; + + result |= g_elf_loading_get_status(loadings[i]); + + g_object_unref(G_OBJECT(loadings[i])); + + } + + free(loadings); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : loading = chargement de chaînes de caractères en cours. * +* format = format ELF à compléter. * +* iter = tête de lecture évoluant avec le temps. [OUT] * * * * Description : Enregistre toutes les chaînes de caractères trouvées. * * * -* Retour : true si des chaînes ont été ajoutées sans erreur, ou false. * +* Retour : true si au moins une chaîne a été insérée. * * * * Remarques : - * * * ******************************************************************************/ -static bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address) +static bool do_elf_string_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter) { - bool result; /* Bilan à faire remonter */ + bool result; /* Bilan à retourner */ GBinFormat *base; /* Autre version du format */ GBinContent *content; /* Contenu binaire à lire */ + phys_t first; /* Première position traitée */ + phys_t offset; /* Décalage pour les données */ + phys_t final; /* Point global de fin de zone */ const bin_t *data; /* Contenu complet et original */ - vmpa2t pos; /* Tête de lecture */ - bool cut; /* Séparation nette ? */ - phys_t i; /* Boucle de parcours */ phys_t end; /* Position de fin de chaîne */ + vmpa2t pos; /* Tête de lecture */ GArchInstruction *instr; /* Instruction décodée */ bool inserted; /* Bilan d'une insertion */ const mrange_t *range; /* Espace occupé par une chaîne*/ GBinSymbol *symbol; /* Symbole à intégrer */ + bool cut; /* Coupure par étiquette ? */ char *label; /* Désignation de la chaîne */ - if (address == 0) - return false; - result = false; /* Préparation des accès */ base = G_BIN_FORMAT(format); - content = g_binary_format_get_content(base); - - init_vmpa(&pos, start, address); + data = g_elf_loading_get_info_for_strings(loading, &content, &first, &offset, &final); - data = g_binary_content_get_raw_access(content, &pos, size); + /* Analyse des données */ - if (data == NULL) - goto pesd_error; + if (isprint(data[*iter - offset]) || isctrledspace(data[*iter - offset])) + { + for (end = *iter; end < final; end++) + if (!isprint(data[end - offset])) break; - /* Boucle de parcours */ + for (; end < final; end++) + if (!isctrledspace(data[end - offset])) break; - cut = true; + if (end < final && data[end - offset] == '\0') + end++; - for (i = 0; i < size; i++) - if (isprint(data[i])) + if ((first - offset) > 0 && *iter == first) { - for (end = i + 1; end < size; end++) - if (!isprint(data[end])) break; + /** + * Si une tâche précédente si termine par un caratère valable, + * elle va étendre sa chaîne jusqu'à intégrer notre chaîne initiale. + * + * Rien ne sert donc de poursuivre, on saute ici cette première chaîne. + */ + + if (isprint(data[first - 1 - offset])) + { + /** + * Le seul truc, c'est que l'autre chaîne peut se terminer par isctrledspace(), + * et que la notre peut commencer par le même type de caractères. + * + * Donc la chaîne qui déborde peut ne pas couvrir entièrement notre chaîne. + * + * On repositionne donc notre fin à la fin de la chaîne précédente. + */ - if (end < size && isspace(data[end])) - end++; + for (end = *iter; end < final; end++) + if (!isprint(data[end - offset])) break; - if (end < size && data[end] == '\0') - end++; + for (; end < final; end++) + if (!isctrledspace(data[end - offset])) break; - init_vmpa(&pos, start + i, address + i); + goto skip_first; - instr = g_raw_instruction_new_array(content, MDS_8_BITS, end - i, &pos, format->endian); - assert(instr != NULL); + } - g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true); + } - inserted = g_preload_info_add_instruction(base->info, instr); + g_elf_loading_compute_string_address(loading, iter, &pos); - if (inserted) - { - range = g_arch_instruction_get_range(instr); + instr = g_raw_instruction_new_array(content, MDS_8_BITS, end - *iter, &pos, format->endian); + assert(instr != NULL); - symbol = g_binary_symbol_new(range, STP_RO_STRING); - g_binary_format_add_symbol(base, symbol); + g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true); - /* Jointure avec la chaîne précédente ? */ + inserted = g_preload_info_add_instruction(base->info, instr); - if (cut) - { - label = create_string_label(base, get_mrange_addr(range), end - i); + result |= inserted; - g_binary_symbol_set_alt_label(symbol, label); + if (inserted) + { + range = g_arch_instruction_get_range(instr); - free(label); + symbol = g_binary_symbol_new(range, STP_RO_STRING); + g_binary_format_add_symbol(base, symbol); - } + /* Jointure avec la chaîne précédente ? */ - } + if ((first - offset) == 0) + cut = true; + else + cut = (data[*iter - offset - 1] == '\0'); - /* Conclusion */ + if (cut) + { + label = create_string_label(base, get_mrange_addr(range), end - *iter); - cut = (data[end - 1] == '\0'); + g_binary_symbol_set_alt_label(symbol, label); - i = end - 1; - result = true; + free(label); + + } } - else cut = true; - pesd_error: + /* Conclusion */ + + skip_first: - g_object_unref(G_OBJECT(content)); + *iter = end; + + } + + else + (*iter)++; return result; diff --git a/plugins/elf/strings.h b/plugins/elf/strings.h index 0dfe11e..8fc2b3e 100644 --- a/plugins/elf/strings.h +++ b/plugins/elf/strings.h @@ -28,9 +28,13 @@ #include "format.h" +#include +#include -/*Charge en mémoire toutes les chaînes trouvées. */ -bool find_all_elf_strings(GElfFormat *); + + +/* Charge en mémoire toutes les chaînes trouvées. */ +bool find_all_elf_strings(GElfFormat *, wgroup_id_t , GtkStatusStack *); diff --git a/plugins/elf/symbols.h b/plugins/elf/symbols.h index f51e504..1b963da 100644 --- a/plugins/elf/symbols.h +++ b/plugins/elf/symbols.h @@ -28,7 +28,6 @@ #include "format.h" -#include #include #include -- cgit v0.11.2-87-g4458