/* Chrysalide - Outil d'analyse de fichiers binaires
* strings.c - recherche des chaînes contenues dans un ELF
*
* Copyright (C) 2008-2012 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* 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
#include "elf-int.h"
#include "section.h"
/* Enregistre toutes les chaînes de caractères trouvées. */
bool parse_elf_string_data(GElfFormat *, off_t, off_t, vmpa_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(GElfFormat *format)
{
bool got_string; /* Indique un remplissage */
off_t str_start; /* Début de section */
off_t str_size; /* Taille de section */
vmpa_t str_addr; /* 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 #1 */
off_t length; /* Taille totale du contenu */
off_t iter; /* Boucle de parcours #2 */
elf_phdr phdr; /* En-tête de programme ELF */
got_string = false;
/* Données en lecture seule */
if (find_elf_section_content_by_name(format, ".rodata", &str_start, &str_size, &str_addr))
got_string |= parse_elf_string_data(format, str_start, str_size, str_addr);
else
{
if (find_elf_sections_by_type(format, SHT_PROGBITS, §ions, &count))
{
for (i = 0; i < count; i++)
if (ELF_SHDR(format, sections[i], sh_flags) == SHF_ALLOC
|| (ELF_SHDR(format, sections[i], sh_flags) & SHF_STRINGS))
{
get_elf_section_content(format, §ions[i], &str_start, &str_size, &str_addr);
got_string |= parse_elf_string_data(format, str_start, str_size, str_addr);
}
free(sections);
}
}
/* Chaîne de caractères déclarées */
if (find_elf_sections_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_addr);
got_string |= parse_elf_string_data(format, str_start, str_size, str_addr);
}
free(sections);
}
/* En désespoir de cause, on se rabbat sur les parties de programme directement */
if (!got_string)
{
length = G_BIN_FORMAT(format)->length;
length = MIN(length, ELF_HDR(format, format->header, e_phnum) * ELF_SIZEOF_PHDR(format));
for (iter = ELF_HDR(format, format->header, e_phoff); iter < length; )
{
if (!read_elf_program_header(format, &iter, &phdr))
continue;
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. *
* address = adresse virtuelle du début de la section. *
* *
* Description : Enregistre toutes les chaînes de caractères trouvées. *
* *
* Retour : true si des chaînes ont été ajoutées, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool parse_elf_string_data(GElfFormat *format, off_t start, off_t size, vmpa_t address)
{
bool result; /* Bilan à faire remonter */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
off_t i; /* Boucle de parcours */
off_t end; /* Position de fin de chaîne */
GBinSymbol *symbol; /* Nouveau symbole construit */
if (address == 0) return false;
result = false;
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
length = MIN(length, start + size);
for (i = start; i < length; i++)
if (isprint(content[i]))
{
for (end = i + 1; end < length; end++)
if (!isprint(content[end])) break;
symbol = g_binary_symbol_new(STP_STRING, NULL, address + i - start);
g_binary_symbol_set_alt_name(symbol, strndup((const char *)&content[i], end - i));
///// reactiver g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);
i = end;
result = true;
}
return result;
}