/* OpenIDA - Outil d'analyse de fichiers binaires * elf.c - support du format ELF * * Copyright (C) 2009 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 "elf.h" #include #include #include "elf-int.h" #include "section.h" #include "strings.h" #include "symbols.h" #include "../../panel/log.h" #ifndef _ # define _(str) (str) #endif /* Initialise la classe des formats d'exécutables ELF. */ static void g_elf_format_class_init(GElfFormatClass *); /* Initialise une instance de format d'exécutable ELF. */ static void g_elf_format_init(GElfFormat *); /* Procède à la lecture de l'en-tête d'un contenu binaire. */ static bool read_elf_header(const bin_t *, off_t, elf_header *, bool *, SourceEndian *); /* Indique le type d'architecture visée par le format. */ static FormatTargetMachine g_elf_format_get_target_machine(const GElfFormat *); /* Fournit l'adresse mémoire du point d'entrée du programme. */ static vmpa_t g_elf_format_get_entry_point(const GElfFormat *); /* Fournit les références aux zones binaires à analyser. */ static GBinPart **g_elf_format_get_parts(const GElfFormat *, size_t *); /****************************************************************************** * * * Paramètres : type = type de format recherché. * * content = contenu binaire à parcourir. * * length = taille du contenu en question. * * * * Description : Indique si le format peut être pris en charge ici. * * * * Retour : true si la réponse est positive, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool elf_is_matching(FormatType type, const bin_t *content, off_t length) { bool result; /* Bilan à faire connaître */ result = false; if (length >= 4) result = (memcmp(content, "\x7f\x45\x4c\x46" /* .ELF */, 4) == 0); return result; } /* Indique le type défini pour un format d'exécutable ELF. */ G_DEFINE_TYPE(GElfFormat, g_elf_format, G_TYPE_EXE_FORMAT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des formats d'exécutables ELF. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_elf_format_class_init(GElfFormatClass *klass) { } /****************************************************************************** * * * Paramètres : format = instance à initialiser. * * * * Description : Initialise une instance de format d'exécutable ELF. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_elf_format_init(GElfFormat *format) { GExeFormat *exe_format; exe_format = G_EXE_FORMAT(format); exe_format->get_machine = (get_target_machine_fc)g_elf_format_get_target_machine; exe_format->get_entry_point = (get_entry_point_fc)g_elf_format_get_entry_point; exe_format->get_parts = (get_parts_fc)g_elf_format_get_parts; } /****************************************************************************** * * * Paramètres : content = contenu binaire à parcourir. * * length = taille du contenu en question. * * header = en-tête à déterminer. [OUT] * * is_32b = indique si le format est en 32 ou 64 bits. [OUT] * * endian = boutisme reconnu dans le format. [OUT] * * * * Description : Procède à la lecture de l'en-tête d'un contenu binaire. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool read_elf_header(const bin_t *content, off_t length, elf_header *header, bool *is_32b, SourceEndian *endian) { bool result; /* Bilan à retourner */ off_t pos; /* Position de lecture */ result = (length >= EI_NIDENT); pos = 0; if (result) { memcpy(header->e_ident, content, EI_NIDENT); pos += EI_NIDENT; } /* Détermination de l'espace d'adressage */ if (result) switch (header->e_ident[EI_CLASS]) { case ELFCLASS32: *is_32b = true; break; case ELFDATA2MSB: *is_32b = false; break; default: result = false; break; } /* Détermination du boutisme */ if (result) switch (header->e_ident[EI_DATA]) { case ELFDATA2LSB: *endian = SRE_LITTLE; break; case ELFDATA2MSB: *endian = SRE_BIG; break; default: result = false; break; } if (result) result = read_u16(&header->e_type, content, &pos, length, *endian); if (result) result = read_u16(&header->e_machine, content, &pos, length, *endian); if (result) result = read_u32(&header->e_version, content, &pos, length, *endian); if (result) { if (*is_32b) result = read_u32(&header->e_entry.addr32, content, &pos, length, *endian); else result = read_u64(&header->e_entry.addr64, content, &pos, length, *endian); } if (result) { if (*is_32b) result = read_u32(&header->e_phoff.off32, content, &pos, length, *endian); else result = read_u64(&header->e_phoff.off64, content, &pos, length, *endian); } if (result) { if (*is_32b) result = read_u32(&header->e_shoff.off32, content, &pos, length, *endian); else result = read_u64(&header->e_shoff.off64, content, &pos, length, *endian); } if (result) result = read_u32(&header->e_flags, content, &pos, length, *endian); if (result) result = read_u16(&header->e_ehsize, content, &pos, length, *endian); if (result) result = read_u16(&header->e_phentsize, content, &pos, length, *endian); if (result) result = read_u16(&header->e_phnum, content, &pos, length, *endian); if (result) result = read_u16(&header->e_shentsize, content, &pos, length, *endian); if (result) result = read_u16(&header->e_shnum, content, &pos, length, *endian); if (result) result = read_u16(&header->e_shstrndx, content, &pos, length, *endian); return result; } /****************************************************************************** * * * Paramètres : content = contenu binaire à parcourir. * * length = taille du contenu en question. * * * * Description : Prend en charge un nouveau format ELF. * * * * Retour : Adresse de la structure mise en place ou NULL en cas d'échec.* * * * Remarques : - * * * ******************************************************************************/ GBinFormat *g_elf_format_new(const bin_t *content, off_t length) { GElfFormat *result; /* Structure à retourner */ result = g_object_new(G_TYPE_ELF_FORMAT, NULL); g_binary_format_set_content(G_BIN_FORMAT(result), content, length); if (!read_elf_header(content, length, &result->header, &result->is_32b, &result->endian)) { /* TODO */ return NULL; } /* Vérification des tailles d'entrée de table */ if (result->header.e_phentsize != ELF_SIZEOF_PHDR(result)) { log_variadic_message(LMT_BAD_BINARY, _("Corrupted program header size (%hu); fixed !"), result->header.e_phentsize); result->header.e_phentsize = ELF_SIZEOF_PHDR(result); } if (result->header.e_shentsize != ELF_SIZEOF_SHDR(result)) { log_variadic_message(LMT_BAD_BINARY, _("Corrupted section header size (%hu); fixed !"), result->header.e_shentsize); result->header.e_shentsize = ELF_SIZEOF_SHDR(result); } /* FIXME : à améliorer */ if ((result->header.e_shnum * result->header.e_shentsize) >= length) { log_variadic_message(LMT_BAD_BINARY, ("Suspicious section table (bigger than the binary !) ; reset !")); result->header.e_shnum = 0; } if (!load_elf_symbols(result)) { /* TODO */ return NULL; } if (!find_all_elf_strings(result)) { /* TODO */ return NULL; } return G_BIN_FORMAT(result); } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * * * Description : Indique le type d'architecture visée par le format. * * * * Retour : Identifiant de l'architecture ciblée par le format. * * * * Remarques : - * * * ******************************************************************************/ static FormatTargetMachine g_elf_format_get_target_machine(const GElfFormat *format) { FormatTargetMachine result; /* Identifiant à retourner */ switch (format->header.e_machine) { case EM_MIPS: result = FTM_MIPS; break; case EM_386: result = FTM_386; break; case EM_NONE: default: result = FTM_NONE; break; } return result; } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * * * Description : Fournit l'adresse mémoire du point d'entrée du programme. * * * * Retour : Adresse de mémoire. * * * * Remarques : - * * * ******************************************************************************/ static vmpa_t g_elf_format_get_entry_point(const GElfFormat *format) { return (format->is_32b ? format->header.e_entry.addr32 : format->header.e_entry.addr64); } /****************************************************************************** * * * Paramètres : format = informations chargées à consulter. * * count = quantité de zones listées. [OUT] * * * * Description : Fournit les références aux zones binaires à analyser. * * * * Retour : Zones binaires à analyser. * * * * Remarques : - * * * ******************************************************************************/ static GBinPart **g_elf_format_get_parts(const GElfFormat *format, size_t *count) { GBinPart **result; /* Tableau à retourner */ uint16_t i; /* Boucle de parcours */ elf_shdr section; /* En-tête de section ELF */ GBinPart *part; /* Partie à intégrer à la liste*/ result = NULL; *count = 0; /* Première tentative : les sections */ for (i = 0; i < format->header.e_shnum; i++) { if (!find_elf_section_by_index(format, i, §ion)) continue; if (ELF_SHDR(format, section, sh_flags) & SHF_EXECINSTR) { part = g_binary_part_new(); /* TODO : nom, droits/type */ g_binary_part_set_values(part, ELF_SHDR(format, section, sh_offset), ELF_SHDR(format, section, sh_size), ELF_SHDR(format, section, sh_addr)); result = (GBinPart **)realloc(result, ++(*count) * sizeof(GBinPart *)); result[*count - 1] = part; } } return result; }