/* OpenIDA - Outil d'analyse de fichiers binaires * symbol.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 "symbol.h" #include #include #include #include #include "elf-int.h" #include "helper_mips.h" #include "section.h" /* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */ /* Charge en mémoire la liste des symboles dynamiques. */ bool load_elf_relocation_table(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *, const off_t *, const off_t *); /* Récupère les informations d'un symbole dynamique donné. */ char *get_elf_dynamic_symbol_info(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *, const off_t *); /* Charge en mémoire la liste humaine des symboles (32 bits). */ bool load_elf_symbol_table_32(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *); /* Charge en mémoire la liste humaine des symboles (64 bits). */ bool load_elf_symbol_table_64(elf_format *, const off_t *, const off_t *, const off_t *, const off_t *); /****************************************************************************** * * * 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(elf_format *format) { bool result; /* Bilan à retourner */ Elf_Shdr *sections; /* Groupe de sections trouvées */ size_t count; /* Quantité de données */ size_t i; /* Boucle de parcours */ Elf_Shdr section; /* Section trouvée ou non */ 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 rel_start; /* Début de section */ off_t rel_size; /* Taille de section */ bool test; /* Bilan d'une recherche */ off_t dyn_start; /* Début de section */ off_t dyn_size; /* Taille de section */ result = true; /* Table des symboles */ find_elf_section_by_type(format, SHT_SYMTAB, §ions, &count); for (i = 0; i < count; i++) { /* Section ".symtab" */ get_elf_section_content(format, §ions[i], &sym_start, &sym_size, NULL); /* Section ".strtab" */ result &= find_elf_section_by_index(format, ELF_SHDR(format, §ions[i], sh_link), §ion); get_elf_section_content(format, §ion, &str_start, &str_size, NULL); if (result) { result = load_elf_symbol_table_32(format, &sym_start, &sym_size, &str_start, &str_size); } } /* Relocalisations */ /* TODO : fixme ! */ find_elf_section_by_type(format, SHT_REL, §ions, &count); for (i = 0; i < count; i++) { /* Section ".rel.xxx" */ get_elf_section_content(format, §ions[i], &rel_start, &rel_size, NULL); /* Section ".dynsym" */ result &= find_elf_section_by_index(format, ELF_SHDR(format, §ions[i], sh_link), §ion); get_elf_section_content(format, §ion, &dyn_start, &dyn_size, NULL); /* Section ".dynstr" */ result &= find_elf_section_by_index(format, ELF_SHDR(format, §ion, sh_link), §ion); get_elf_section_content(format, §ion, &str_start, &str_size, NULL); /* Récupération (première partie) */ if (result) { result = load_elf_relocation_table(format, &rel_start, &rel_size, &dyn_start, &dyn_size, &str_start, &str_size); } } free(sections); /* TODO : fixme ! */ /* Liaison dynamique (si elle existe) */ test = find_elf_section_by_name(format, ".dynsym", §ion); if (!test) { test = find_elf_section_by_type(format, SHT_HASH, §ions, &count); if (test) test = find_elf_section_by_index(format, ELF_SHDR(format, §ions[0], sh_link), §ion); } if (test) { get_elf_section_content(format, §ion, &dyn_start, &dyn_size, NULL); result &= find_elf_section_by_index(format, ELF_SHDR(format, §ion, sh_link), §ion); } if (result) { get_elf_section_content(format, §ion, &str_start, &str_size, NULL); switch (get_elf_target_machine(format)) { case FTM_MIPS: result = g_elf_format_find_mips_dynamic_symbols(format, dyn_start, dyn_size, str_start, str_size); break; case FTM_386: result = g_elf_format_find_x86_dynamic_symbols(format, dyn_start, dyn_size, str_start, str_size); break; default: break; } } return result; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * sym_start = début de la zone à traiter. * * sym_size = taille de la zone à traiter. * * str_start = début de la zone de chaîne de caractères. * * str_size = taille de la zone de chaînes de caractères. * * * * Description : Charge en mémoire la liste humaine des symboles (32 bits). * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool load_elf_symbol_table_32(elf_format *format, const off_t *sym_start, const off_t *sym_size, const off_t *str_start, const off_t *str_size) { off_t iter; /* Boucle de parcours */ Elf32_Sym symbol; /* Symbole ELF lu */ GBinRoutine *routine; /* Nouvelle routine trouvée */ if (*sym_size % sizeof(Elf32_Sym) != 0) return false; for (iter = *sym_start; iter < (*sym_start + *sym_size); iter += sizeof(Elf32_Sym)) { memcpy(&symbol, &EXE_FORMAT(format)->content[iter], sizeof(Elf32_Sym)); if (!(ELF32_ST_TYPE(symbol.st_info) == STT_FUNC)) continue; if (symbol.st_value == 0) continue; /* Sécurité anti-débordements */ if (symbol.st_name >= *str_size) continue; /* Si le symbole possède un nom... */ if (strlen(&EXE_FORMAT(format)->content[*str_start + symbol.st_name]) > 0) { routine = g_binary_routine_new(); g_binary_routine_set_name(routine, strdup(&EXE_FORMAT(format)->content[*str_start + symbol.st_name])); g_binary_routine_set_address(routine, symbol.st_value); g_binary_routine_set_size(routine, symbol.st_size); format->routines = (GBinRoutine **)realloc(format->routines, ++format->routines_count * sizeof(GBinRoutine *)); format->routines[format->routines_count - 1] = routine; } } return true; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * sym_start = début de la zone à traiter. * * sym_size = taille de la zone à traiter. * * str_start = début de la zone de chaîne de caractères. * * str_size = taille de la zone de chaînes de caractères. * * * * Description : Charge en mémoire la liste humaine des symboles (64 bits). * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool load_elf_symbol_table_64(elf_format *format, const off_t *sym_start, const off_t *sym_size, const off_t *str_start, const off_t *str_size) { off_t iter; /* Boucle de parcours */ Elf64_Sym symbol; /* Symbole ELF lu */ if (*sym_size % sizeof(Elf64_Sym) != 0) return false; for (iter = *sym_start; iter < (*sym_start + *sym_size); iter += sizeof(Elf64_Sym)) { memcpy(&symbol, &EXE_FORMAT(format)->content[iter], sizeof(Elf64_Sym)); if (!(ELF64_ST_TYPE(symbol.st_info) == STT_FUNC || (ELF64_ST_TYPE(symbol.st_info) == STT_NOTYPE && ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL))) continue; if (symbol.st_value == 0) continue; /* Sécurité anti-débordements */ if (symbol.st_name >= *str_size) continue; /* Si le symbole possède un nom... */ if (strlen(&EXE_FORMAT(format)->content[*str_start + symbol.st_name]) > 0) { format->symbols = (elf_symbol *)realloc(format->symbols, ++format->sym_count * sizeof(elf_symbol)); format->symbols[format->sym_count - 1].name = &EXE_FORMAT(format)->content[*str_start + symbol.st_name]; format->symbols[format->sym_count - 1].address = symbol.st_value; } } return true; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * comments = liste des commentaires à insérer. [OUT] * * offsets = liste des indices des commentaires. [OUT] * * count = taille des listes construites. [OUT] * * * * Description : Récupère tous les commentaires à insérer dans le code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void get_elf_symbol_comments(const elf_format *format, char ***comments, uint64_t **offsets, size_t *count) { size_t i; /* Boucle de parcours */ size_t len; /* Longueur d'une désignation */ if (format->sym_count > 0) { *comments = (char **)calloc(*count + format->sym_count, sizeof(char *)); *offsets = (uint64_t *)calloc(*count + format->sym_count, sizeof(uint64_t)); for (i = 0; i < format->sym_count; i++) { len = strlen(format->symbols[i].name); (*comments)[i] = (char *)calloc(len + 9, sizeof(char)); snprintf((*comments)[i], len + 9, "<%s>", format->symbols[i].name); (*offsets)[i] = format->symbols[i].address; } *count += format->sym_count; } } /* ---------------------------------------------------------------------------------- */ /* DETAIL DES SYMBOLES EXTERNES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * plt_start = début de la zone à traiter. * * plt_size = taille de la zone à traiter. * * dyn_start = début des informations dynamiques associées. * * dyn_size = taille de la zone associée. * * str_start = début de la zone de chaîne de caractères. * * str_size = taille de la zone de chaînes de caractères. * * * * Description : Charge en mémoire la liste des symboles dynamiques. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool load_elf_relocation_table(elf_format *format, const off_t *plt_start, const off_t *plt_size, const off_t *dyn_start, const off_t *dyn_size, const off_t *str_start, const off_t *str_size) { off_t iter; /* Boucle de parcours */ Elf_Rel reloc; /* Infos de relocalisation */ off_t index; /* Indice de la portion visée */ char *name; /* Nom du symbole trouvé */ for (iter = *plt_start; iter < (*plt_start + *plt_size); iter += ELF_SIZEOF_REL(format)) { memcpy(&reloc, &EXE_FORMAT(format)->content[iter], ELF_SIZEOF_REL(format)); switch (format->header.e_machine) { case EM_386: switch (ELF32_R_TYPE(ELF_REL_TYPE(format, reloc))) { case R_386_JMP_SLOT: index = ELF_REL_SYM(format, reloc); name = get_elf_dynamic_symbol_info(format, dyn_start, dyn_size, &index, str_start, str_size); if (name != NULL) { format->relocations = (elf_symbol *)realloc(format->relocations, ++format->rel_count * sizeof(elf_symbol)); format->relocations[format->rel_count - 1].name = name; format->relocations[format->rel_count - 1].address = ELF_REL(format, reloc, r_offset); } break; default: printf("Relocation not supported (%lld) !\n", ELF_REL_TYPE(format, reloc)); break; } break; default: printf("Machine not recognized !\n"); return false; break; } } return true; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * dyn_start = début des informations dynamiques associées. * * dyn_size = taille de la zone associée. * * index = indice de l'entrée à venir lire. * * str_start = début de la zone de chaîne de caractères. * * str_size = taille de la zone de chaînes de caractères. * * * * Description : Récupère les informations d'un symbole dynamique donné. * * * * Retour : Nom du symbole trouvé, ou NULL si erreur ou non adapté. * * * * Remarques : - * * * ******************************************************************************/ char *get_elf_dynamic_symbol_info(elf_format *format, const off_t *dyn_start, const off_t *dyn_size, const off_t *index, const off_t *str_start, const off_t *str_size) { off_t offset; /* Emplacement à venir lire */ Elf_Sym symbol; /* Symbole aux infos visées */ offset = *dyn_start + *index * ELF_SIZEOF_SYM(format); if ((offset + ELF_SIZEOF_SYM(format)) > (*dyn_start + *dyn_size)) return NULL; memcpy(&symbol, &EXE_FORMAT(format)->content[offset], ELF_SIZEOF_SYM(format)); if (ELF_SYM(format, symbol, st_name) >= *str_size) return NULL; return (char *)&EXE_FORMAT(format)->content[*str_start + ELF_SYM(format, symbol, st_name)]; }