summaryrefslogtreecommitdiff
path: root/plugins/elf/strings.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-06-21 20:43:23 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-06-21 20:43:48 (GMT)
commit27f44a381ed8c317a16df450ec00ed87bbb9a4b3 (patch)
tree12fac37958fac2eadf5d457834b5fa84ad2fd2eb /plugins/elf/strings.c
parentf12dc45c8b5139c0415a240c23bbc980f252a866 (diff)
Loaded strings from ELF files using all threads.
Diffstat (limited to 'plugins/elf/strings.c')
-rw-r--r--plugins/elf/strings.c259
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, &sections[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, &sections[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;