/* OpenIDA - Outil d'analyse de fichiers binaires
* strings.c - recherche des chaînes contenues dans 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 "strings.h"
#include
#include
#include
#include "elf-int.h"
#include "section.h"
/* Enregistre toutes les chaînes de caractères trouvées. */
bool parse_elf_string_data(elf_format *, const off_t, const off_t, uint64_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(elf_format *format)
{
off_t str_start; /* Début de section */
off_t str_size; /* Taille de section */
uint64_t str_vaddr; /* 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 */
off_t offset; /* Position physique */
Elf_Phdr phdr; /* En-tête de programme ELF */
/* Données en lecture seule */
if (find_elf_section_content_by_name(format, ".rodata", &str_start, &str_size, &str_vaddr))
parse_elf_string_data(format, str_start, str_size, str_vaddr);
else
{
find_elf_section_by_type(format, SHT_PROGBITS, §ions, &count);
for (i = 0; i < count; i++)
if (ELF_SHDR(format, §ions[i], sh_flags) == SHF_ALLOC
|| (ELF_SHDR(format, §ions[i], sh_flags) & SHF_STRINGS))
{
get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_vaddr);
parse_elf_string_data(format, str_start, str_size, str_vaddr);
}
}
/* Chaîne de caractères déclarées */
find_elf_section_by_type(format, SHT_STRTAB, §ions, &count);
for (i = 0; i < count; i++)
{
get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_vaddr);
parse_elf_string_data(format, str_start, str_size, str_vaddr);
}
/* En désespoir de cause, on se rabbat sur les parties de programme directement */
if (format->str_count == 0 && format->header.e_shnum == 0 /* FIXME : cond. à garder ? */)
for (i = 0; i < format->header.e_phnum; i++)
{
offset = format->header.e_phoff + format->header.e_phentsize * i;
if ((offset + format->header.e_phentsize) >= EXE_FORMAT(format)->length) continue;
memcpy(&phdr, &EXE_FORMAT(format)->content[offset], format->header.e_phentsize);
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. *
* vaddress = adresse virtuelle du début de la section. *
* *
* Description : Enregistre toutes les chaînes de caractères trouvées. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool parse_elf_string_data(elf_format *format, const off_t start, const off_t size, uint64_t vaddress)
{
off_t i; /* Boucle de parcours */
off_t end; /* Position de fin de chaîne */
if (vaddress == 0) return false;
for (i = start; i < (start + size); i++)
if (isprint(EXE_FORMAT(format)->content[i]))
{
for (end = i + 1; end < (start + size); end++)
if (!isprint(EXE_FORMAT(format)->content[end])) break;
format->strings = (elf_string *)realloc(format->strings, ++format->str_count * sizeof(elf_string));
format->strings[format->str_count - 1].value = strndup((const char *)&EXE_FORMAT(format)->content[i], end - i);
format->strings[format->str_count - 1].len = end - i;
format->strings[format->str_count - 1].vaddress = vaddress + i - start;
i = end;
}
return true;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* label = étiquette allouée du symbole si trouvé. [OUT] *
* vaddress = adresse à cibler, puis décallage final. [OUT] *
* *
* Description : Recherche une chaîne correspondant à une adresse. *
* *
* Retour : true si l'opération a été un succès, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool resolve_elf_strings(const elf_format *format, char **label, uint64_t *vaddress)
{
bool result; /* Bilan de recherche remonté */
size_t real_start; /* Début de chaîne effective */
size_t i; /* Boucle de parcours */
result = false;
for (i = 0; i < format->str_count && !result; i++)
if (format->strings[i].vaddress <= *vaddress
&& *vaddress < (format->strings[i].vaddress + format->strings[i].len))
{
real_start = *vaddress - format->strings[i].vaddress;
*label = strndup(&format->strings[i].value[real_start],
format->strings[i].len - real_start);
result = true;
}
return result;
}