summaryrefslogtreecommitdiff
path: root/plugins/elf
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
parentf12dc45c8b5139c0415a240c23bbc980f252a866 (diff)
Loaded strings from ELF files using all threads.
Diffstat (limited to 'plugins/elf')
-rw-r--r--plugins/elf/format.c2
-rw-r--r--plugins/elf/loading.c150
-rw-r--r--plugins/elf/loading.h9
-rw-r--r--plugins/elf/strings.c259
-rw-r--r--plugins/elf/strings.h8
-rw-r--r--plugins/elf/symbols.h1
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 <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;
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 <glibext/delayed.h>
+#include <gtkext/gtkstatusstack.h>
-/*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 <arch/processor.h>
#include <glibext/delayed.h>
#include <gtkext/gtkstatusstack.h>