diff options
Diffstat (limited to 'plugins/elf/strings.c')
-rw-r--r-- | plugins/elf/strings.c | 259 |
1 files changed, 202 insertions, 57 deletions
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 <assert.h> #include <ctype.h> #include <malloc.h> -#include <string.h> #include <sys/param.h> +#include <i18n.h> + + #include <arch/raw.h> +#include <core/global.h> +#include <core/nproc.h> #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; |