summaryrefslogtreecommitdiff
path: root/src/format/elf/symbols.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/format/elf/symbols.c')
-rw-r--r--src/format/elf/symbols.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/src/format/elf/symbols.c b/src/format/elf/symbols.c
new file mode 100644
index 0000000..97b6ff2
--- /dev/null
+++ b/src/format/elf/symbols.c
@@ -0,0 +1,418 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * symbols.c - gestion des symboles d'un ELF
+ *
+ * Copyright (C) 2008 Cyrille Bagard
+ *
+ * This file is part of OpenIDA.
+ *
+ * OpenIDA 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.
+ *
+ * OpenIDA 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 "symbols.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "elf-int.h"
+#include "helper_x86.h"
+#include "section.h"
+#include "../../panel/log.h"
+
+
+
+
+
+#define _(str) str
+
+
+
+
+/* Récupère la désignation d'un symbole donné. */
+const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t);
+
+
+
+/* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */
+
+
+/* Charge tous les symboles internes possibles. */
+static bool load_elf_internal_symbols(GElfFormat *);
+
+
+
+/* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */
+
+
+/* Retrouve un élément donné dans la section dynamique. */
+static bool find_elf_dynamic_item(const GElfFormat *, const elf_shdr *, int32_t, elf_dyn *);
+
+/* Charge tous les éléments dynamiques externes possibles. */
+static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *);
+
+
+
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à compléter. *
+* *
+* Description : Charge en mémoire la liste humaine des symboles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_elf_symbols(GElfFormat *format)
+{
+ bool result; /* Bilan à retourner */
+ elf_shdr *sections; /* Groupe de sections trouvées */
+ size_t count; /* Quantité de données */
+
+ result = true;
+
+ /* Symboles externes */
+
+ if (find_elf_sections_by_type(format, SHT_DYNAMIC, &sections, &count))
+ {
+ log_variadic_message(LMT_INFO, _("Binary is dynamically linked"));
+
+ result &= load_elf_external_symbols(format, &sections[0]);
+
+ free(sections);
+
+ }
+ else log_variadic_message(LMT_INFO, _("Binary is statically linked"));
+
+ /* Symboles internes */
+ result &= load_elf_internal_symbols(format);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à consulter. *
+* sym = section comprenant les symboles à venir lire. *
+* str = section de chaînes de caractères pour les noms. *
+* index = indice de l'entrée à venir lire. *
+* *
+* Description : Récupère la désignation d'un symbole donné. *
+* *
+* Retour : Nom du symbole trouvé, ou NULL si erreur ou non adapté. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const elf_shdr *str, off_t index)
+{
+ const char *result; /* Résultat à retourner */
+ off_t sym_start; /* Début de section */
+ off_t sym_size; /* Taille de section */
+ off_t str_start; /* Début de section */
+ off_t str_size; /* Taille de section */
+ off_t offset; /* Emplacement à venir lire */
+ elf_sym symbol; /* Symbole aux infos visées */
+
+ result = NULL;
+
+ get_elf_section_content(format, sym, &sym_start, &sym_size, NULL);
+ get_elf_section_content(format, str, &str_start, &str_size, NULL);
+
+ offset = sym_start + index * ELF_SIZEOF_SYM(format);
+ if ((offset + ELF_SIZEOF_SYM(format)) > (sym_start + sym_size)) return NULL;
+
+ if (read_elf_symbol(format, &offset, &symbol))
+ result = extract_name_from_elf_string_section(format, str, ELF_SYM(format, symbol, st_name));
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DETAIL DES SYMBOLES INTERNES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à compléter. *
+* *
+* Description : Charge tous les symboles internes possibles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool load_elf_internal_symbols(GElfFormat *format)
+{
+ bool result; /* Bilan à retourner */
+ elf_shdr *symtabs; /* Groupe de sections trouvées */
+ size_t count; /* Quantité de données */
+ size_t i; /* Boucle de parcours */
+ elf_shdr strtab; /* Section .strtab trouvée */
+ bool has_strtab; /* Présence de cette section */
+ off_t sym_start; /* Début de la zone à traiter */
+ off_t sym_size; /* Taille de cette même zone */
+ off_t iter; /* Boucle de parcours */
+ const char *name; /* Nom du symbole trouvé */
+ elf_sym sym; /* Symbole aux infos visées */
+ GBinRoutine *routine; /* Nouvelle routine trouvée */
+ GBinSymbol *symbol; /* Nouveau symbole construit */
+
+ result = true;
+
+ if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtabs, &count))
+ for (i = 0; i < count && result; i++)
+ {
+ has_strtab = find_elf_section_by_index(format, ELF_SHDR(format, symtabs[i], sh_link), &strtab);
+
+ get_elf_section_content(format, &symtabs[i], &sym_start, &sym_size, NULL);
+
+ for (iter = sym_start; iter < (sym_start + sym_size); )
+ {
+ result = read_elf_symbol(format, &iter, &sym);
+ if (!result) break;
+
+ if (ELF_SYM(format, sym, st_value) == 0) continue;
+
+ if (!(ELF_ST_TYPE(format, sym) == STT_FUNC)) continue;
+
+ if (!has_strtab) name = NULL;
+ else name = get_elf_symbol_name(format, &symtabs[i], &strtab,
+ ((iter - sym_start) / ELF_SIZEOF_SYM(format)) - 1);
+
+ if (name == NULL)
+ {
+ /* FIXME */
+ name = "unknown";
+ }
+
+ /* Routine */
+
+ routine = g_binary_routine_new();
+
+ g_binary_routine_set_name(routine, strdup(name));
+ g_binary_routine_set_address(routine, ELF_SYM(format, sym, st_value));
+ g_binary_routine_set_size(routine, ELF_SYM(format, sym, st_size));
+
+ g_binary_format_add_routine(G_BIN_FORMAT(format), routine);
+
+ /* Symbole uniquement */
+
+ symbol = g_binary_symbol_new(STP_FUNCTION, name, ELF_SYM(format, sym, st_value));
+
+ g_binary_symbol_attach_routine(symbol, routine);
+
+ g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);
+
+ }
+
+
+ }
+
+ return true;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DETAIL DES SYMBOLES EXTERNES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : format = informations chargées à consulter. *
+* dynamic = section de type SHT_DYNAMIC. *
+* type = sorte d'élément recherché. *
+* item = élément retrouvé dans la section. [OUT] *
+* *
+* Description : Retrouve un élément donné dans la section dynamique. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *section, int32_t type, elf_dyn *item)
+{
+ bool result; /* Bilan à retourner */
+ const bin_t *content; /* Contenu binaire à lire */
+ off_t length; /* Taille totale du contenu */
+ off_t pos; /* Position de lecture */
+ off_t tmp; /* Position écrasable */
+ int32_t tag32; /* Type de l'entrée (32 bits) */
+ int64_t tag64; /* Type de l'entrée (64 bits) */
+
+ result = true;
+
+ content = G_BIN_FORMAT(format)->content;
+ length = G_BIN_FORMAT(format)->length;
+
+ for (pos = ELF_SHDR(format, *section, sh_offset);
+ pos < length/* FIXME !! + xploit */ && result;
+ pos += ELF_SIZEOF_DYN(format))
+ {
+ tmp = pos;
+
+ if (format->is_32b)
+ {
+ result = read_s32(&tag32, content, &tmp, length, format->endian);
+ if (tag32 == type) break;
+ }
+ else
+ {
+ result = read_s64(&tag64, content, &tmp, length, format->endian);
+ if (tag64 == type) break;
+ }
+
+ }
+
+ result &= (pos < length);
+
+ if (result)
+ {
+ if (format->is_32b)
+ {
+ result = read_s32(&item->dyn32.d_tag, content, &pos, length, format->endian);
+ result &= read_s32(&item->dyn32.d_un.d_val, content, &pos, length, format->endian);
+ }
+ else
+ {
+ result = read_s64(&item->dyn64.d_tag, content, &pos, length, format->endian);
+ result &= read_s64(&item->dyn64.d_un.d_val, content, &pos, length, format->endian);
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = informations chargées à consulter. *
+* dynamic = section de type SHT_DYNAMIC. *
+* *
+* Description : Charge tous les éléments dynamiques externes possibles. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool load_elf_external_symbols(GElfFormat *format, const elf_shdr *section)
+{
+ bool result; /* Bilan à retourner */
+
+ elf_dyn item; /* Elément dynamique */
+ elf_shdr relxxx; /* Section .rel.xxx trouvée */
+ elf_shdr dynsym; /* Section .dynsym trouvée */
+ elf_shdr dynstr; /* Section .dynstr trouvée */
+ elf_shdr plt; /* Section .plt trouvée */
+
+ result = true;
+
+
+
+
+
+
+ /* Section .rel.plt */
+ if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
+ {
+ result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);
+
+ if (result)
+ result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_link), &dynsym);
+
+ if (result)
+ result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);
+
+ if (result)
+ switch (g_exe_format_get_target_machine(G_EXE_FORMAT(format)))
+ {
+ case FTM_386:
+ result = load_elf_x86_relocated_symbols(format, &relxxx, &dynsym, &dynstr);
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ /* Entrées équivalentes dans le binaire */
+ if (find_elf_dynamic_item(format, section, DT_SYMTAB, &item))
+ {
+ result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &dynsym);
+
+ if (result)
+ result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);
+
+ if (result)
+ switch (g_exe_format_get_target_machine(G_EXE_FORMAT(format)))
+ {
+ case FTM_MIPS:
+ //result = find_elf_mips_dynamic_symbols(format, &dynsym, &dynstr);
+ break;
+
+ case FTM_386:
+
+ if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
+ {
+ result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);
+
+ if (result)
+ result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_info), &plt);
+
+ if (result)
+ result = find_elf_x86_dynamic_symbols(format, &plt);
+
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ return result;
+
+}