/* 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. * * 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. */ 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 : - * * * ******************************************************************************/ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address) { bool result; /* Bilan à faire remonter */ GBinContent *content; /* Contenu binaire à lire */ char *data; /* Données copiées à traiter */ vmpa2t pos; /* Tête de lecture */ bool cut; /* Séparation nette ? */ off_t i; /* Boucle de parcours */ off_t end; /* Position de fin de chaîne */ GArchInstruction *instr; /* Instruction décodée */ 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 */ content = g_binary_format_get_content(G_BIN_FORMAT(format)); data = (char *)malloc(size * sizeof(char)); init_vmpa(&pos, start, address); if (!g_binary_content_read_raw(content, &pos, size, (bin_t *)data)) 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 (isspace(data[end]) && (end + 1) < size) end++; if (data[end] == '\0' && (end + 1) < size) end++; init_vmpa(&pos, start + i, address + i); instr = g_raw_instruction_new_array(G_BIN_FORMAT(format)->content, MDS_8_BITS, end - i, &pos, format->endian); g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true); ADD_STR_AS_SYM(format, symbol, instr); /* Jointure avec la chaîne précédente ? */ if (cut) { init_vmpa(&pos, start + i, address + i); label = create_string_label(G_BIN_FORMAT(format), &pos, &data[i], 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)); free(data); return result; }