/* 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)];
}