summaryrefslogtreecommitdiff
path: root/plugins/elf/strings.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2017-10-01 17:32:12 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2017-10-01 17:32:12 (GMT)
commit208abfe4182c0dafc230e0377b3efcc6c24be0f9 (patch)
tree4e084364b0a211ee36a5e8e55b70367f01d720d5 /plugins/elf/strings.c
parent593aee561015251dfd042dc5e00388f63232c45f (diff)
Defined the ELF support as plugin.
Diffstat (limited to 'plugins/elf/strings.c')
-rw-r--r--plugins/elf/strings.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/plugins/elf/strings.c b/plugins/elf/strings.c
new file mode 100644
index 0000000..3bec414
--- /dev/null
+++ b/plugins/elf/strings.c
@@ -0,0 +1,250 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * strings.c - recherche des chaînes contenues dans un ELF
+ *
+ * Copyright (C) 2008-2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "strings.h"
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/param.h>
+
+
+#include <arch/raw.h>
+
+
+#include "elf-int.h"
+#include "section.h"
+
+
+
+/* Enregistre toutes les chaînes de caractères trouvées. */
+static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à analyser. *
+* *
+* Description : Charge en mémoire toutes les chaînes trouvées. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool find_all_elf_strings(GElfFormat *format)
+{
+ bool got_string; /* Indique un remplissage */
+ phys_t str_start; /* Début de section */
+ phys_t str_size; /* Taille de section */
+ virt_t str_addr; /* Adresse virtuelle associée */
+ elf_shdr *sections; /* Groupe de sections trouvées */
+ size_t count; /* Quantité de données */
+ size_t i; /* Boucle de parcours #1 */
+ phys_t max; /* Borne à ne pas dépasser */
+ phys_t iter; /* Boucle de parcours #2 */
+ elf_phdr phdr; /* En-tête de programme ELF */
+
+ 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);
+
+ else
+ {
+ if (find_elf_sections_by_type(format, SHT_PROGBITS, &sections, &count))
+ {
+ for (i = 0; i < count; i++)
+ if (ELF_SHDR(format, sections[i], sh_flags) == SHF_ALLOC
+ || (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);
+ }
+
+ free(sections);
+
+ }
+
+ }
+
+ /* Chaîne de caractères déclarées */
+
+ if (find_elf_sections_by_type(format, SHT_STRTAB, &sections, &count))
+ {
+ 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);
+ }
+
+ free(sections);
+
+ }
+
+ /* En désespoir de cause, on se rabbat sur les parties de programme directement */
+
+ if (!got_string)
+ {
+ max = ELF_HDR(format, format->header, e_phoff)
+ + ELF_HDR(format, format->header, e_phnum) * ELF_SIZEOF_PHDR(format);
+
+ for (iter = ELF_HDR(format, format->header, e_phoff); iter < max; iter += ELF_SIZEOF_PHDR(format))
+ {
+ if (!read_elf_program_header(format, iter, &phdr))
+ continue;
+
+ if (ELF_PHDR(format, phdr, p_flags) & PF_R
+ && !(ELF_PHDR(format, phdr, p_flags) & PF_X))
+ parse_elf_string_data(format,
+ ELF_PHDR(format, phdr, p_offset),
+ ELF_PHDR(format, phdr, p_filesz),
+ ELF_PHDR(format, phdr, p_vaddr));
+
+ }
+
+ }
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à compléter. *
+* start = début de la zone à parcourir. *
+* size = taille de l'espace à parcourir. *
+* address = adresse virtuelle du début de la section. *
+* *
+* 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. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address)
+{
+ bool result; /* Bilan à faire remonter */
+ GBinFormat *base; /* Autre version du format */
+ GBinContent *content; /* Contenu binaire à lire */
+ 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 */
+ 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 */
+ 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_binary_content_get_raw_access(content, &pos, size);
+
+ if (data == NULL)
+ goto pesd_error;
+
+ /* Boucle de parcours */
+
+ cut = true;
+
+ for (i = 0; i < size; i++)
+ if (isprint(data[i]))
+ {
+ for (end = i + 1; end < size; end++)
+ if (!isprint(data[end])) break;
+
+ if (end < size && isspace(data[end]))
+ end++;
+
+ if (end < size && data[end] == '\0')
+ end++;
+
+ init_vmpa(&pos, start + i, address + i);
+
+ 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);
+
+ if (inserted)
+ {
+ range = g_arch_instruction_get_range(instr);
+
+ 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 (cut)
+ {
+ label = create_string_label(base, get_mrange_addr(range), end - i);
+
+ g_binary_symbol_set_alt_label(symbol, label);
+
+ free(label);
+
+ }
+
+ }
+
+ /* Conclusion */
+
+ cut = (data[end - 1] == '\0');
+
+ i = end - 1;
+ result = true;
+
+ }
+ else cut = true;
+
+ pesd_error:
+
+ g_object_unref(G_OBJECT(content));
+
+ return result;
+
+}