/* 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 . */ #include "symbols.h" #include #include #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, §ions, &count)) { log_variadic_message(LMT_INFO, _("Binary is dynamically linked")); result &= load_elf_external_symbols(format, §ions[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; }