/* Chrysalide - Outil d'analyse de fichiers binaires
* strings.c - recherche des chaînes contenues dans un ELF
*
* Copyright (C) 2008-2017 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide 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.
*
* Chrysalide 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"
#include "../../arch/raw.h"
/* Enregistre toutes les chaînes de caractères trouvées. */
static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_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 */
phys_t str_start; /* Début de section */
phys_t str_size; /* Taille de section */
virt_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 */
phys_t max; /* Borne à ne pas dépasser */
phys_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)
{
max = ELF_HDR(format, format->header, e_phoff)
+ ELF_HDR(format, format->header, e_phnum) * ELF_SIZEOF_PHDR(format);
for (iter = ELF_HDR(format, format->header, e_phoff); iter < max; iter += ELF_SIZEOF_PHDR(format))
{
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 sans erreur, ou false. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address)
{
bool result; /* Bilan à faire remonter */
GBinFormat *base; /* Autre version du format */
GBinContent *content; /* Contenu binaire à lire */
const bin_t *data; /* Contenu complet et original */
vmpa2t pos; /* Tête de lecture */
bool cut; /* Séparation nette ? */
phys_t i; /* Boucle de parcours */
phys_t end; /* Position de fin de chaîne */
GArchInstruction *instr; /* Instruction décodée */
const mrange_t *range; /* Espace occupé par une chaîne*/
GBinSymbol *symbol; /* Symbole à intégrer */
char *label; /* Désignation de la chaîne */
if (address == 0)
return false;
result = false;
/* Préparation des accès */
base = G_BIN_FORMAT(format);
content = g_binary_format_get_content(base);
init_vmpa(&pos, start, address);
data = g_binary_content_get_raw_access(content, &pos, size);
if (data == NULL)
goto pesd_error;
/* Boucle de parcours */
cut = true;
for (i = 0; i < size; i++)
if (isprint(data[i]))
{
for (end = i + 1; end < size; end++)
if (!isprint(data[end])) break;
if (end < size && isspace(data[end]))
end++;
if (end < size && data[end] == '\0')
end++;
init_vmpa(&pos, start + i, address + i);
instr = g_raw_instruction_new_array(content, MDS_8_BITS, end - i, &pos, format->endian);
g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true);
g_preload_info_add_instruction(base->info, instr);
range = g_arch_instruction_get_range(instr);
symbol = g_binary_symbol_new(range, STP_RO_STRING);
g_binary_format_add_symbol(base, symbol);
/* Jointure avec la chaîne précédente ? */
if (cut)
{
label = create_string_label(base, get_mrange_addr(range), end - i);
g_binary_symbol_set_alt_label(symbol, label);
free(label);
}
/* Conclusion */
cut = (data[end - 1] == '\0');
i = end - 1;
result = true;
}
else cut = true;
pesd_error:
g_object_unref(G_OBJECT(content));
return result;
}