/* Chrysalide - Outil d'analyse de fichiers binaires
* elf-int.c - structures internes du format ELF
*
* Copyright (C) 2009-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 "elf-int.h"
#include
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* 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 ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_header(GElfFormat *format, elf_header *header, bool *is_32b, SourceEndian *endian)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
off_t pos; /* Position de lecture */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
result = (length >= EI_NIDENT);
pos = 0;
if (result)
{
memcpy(header->hdr32.e_ident, content, EI_NIDENT);
pos += EI_NIDENT;
}
/* Détermination de l'espace d'adressage */
if (result)
switch (header->hdr32.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->hdr32.e_ident[EI_DATA])
{
case ELFDATA2LSB:
*endian = SRE_LITTLE;
break;
case ELFDATA2MSB:
*endian = SRE_BIG;
break;
default:
result = false;
break;
}
if (*is_32b)
{
result &= read_u16(&header->hdr32.e_type, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_machine, content, &pos, length, *endian);
result &= read_u32(&header->hdr32.e_version, content, &pos, length, *endian);
result &= read_u32(&header->hdr32.e_entry, content, &pos, length, *endian);
result &= read_u32(&header->hdr32.e_phoff, content, &pos, length, *endian);
result &= read_u32(&header->hdr32.e_shoff, content, &pos, length, *endian);
result &= read_u32(&header->hdr32.e_flags, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_ehsize, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_phentsize, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_phnum, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_shentsize, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_shnum, content, &pos, length, *endian);
result &= read_u16(&header->hdr32.e_shstrndx, content, &pos, length, *endian);
}
else
{
result &= read_u16(&header->hdr64.e_type, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_machine, content, &pos, length, *endian);
result &= read_u32(&header->hdr64.e_version, content, &pos, length, *endian);
result &= read_u64(&header->hdr64.e_entry, content, &pos, length, *endian);
result &= read_u64(&header->hdr64.e_phoff, content, &pos, length, *endian);
result &= read_u64(&header->hdr64.e_shoff, content, &pos, length, *endian);
result &= read_u32(&header->hdr64.e_flags, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_ehsize, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_phentsize, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_phnum, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_shentsize, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_shnum, content, &pos, length, *endian);
result &= read_u16(&header->hdr64.e_shstrndx, content, &pos, length, *endian);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* pos = position de début de lecture. [OUT] *
* header = structure lue à retourner. [OUT] *
* *
* Description : Procède à la lecture d'une en-tête de programme ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_program_header(const GElfFormat *format, off_t *pos, elf_phdr *header)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
if (format->is_32b)
{
result = read_u32(&header->phdr32.p_type, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_offset, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_vaddr, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_paddr, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_filesz, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_memsz, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_flags, content, pos, length, format->endian);
result &= read_u32(&header->phdr32.p_align, content, pos, length, format->endian);
}
else
{
result = read_u32(&header->phdr64.p_type, content, pos, length, format->endian);
result &= read_u32(&header->phdr64.p_flags, content, pos, length, format->endian);
result &= read_u64(&header->phdr64.p_offset, content, pos, length, format->endian);
result &= read_u64(&header->phdr64.p_vaddr, content, pos, length, format->endian);
result &= read_u64(&header->phdr64.p_paddr, content, pos, length, format->endian);
result &= read_u64(&header->phdr64.p_filesz, content, pos, length, format->endian);
result &= read_u64(&header->phdr64.p_memsz, content, pos, length, format->endian);
result &= read_u64(&header->phdr64.p_align, content, pos, length, format->endian);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* pos = position de la tête de lecture. *
* section = section lue. [OUT] *
* *
* Description : Procède à la lecture d'une en-tête de section ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_section_header(const GElfFormat *format, off_t pos, elf_shdr *section)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
elf32_shdr *shdr32; /* Version 32 bits */
elf64_shdr *shdr64; /* Version 32 bits */
result = true;
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
if (format->is_32b)
{
shdr32 = §ion->shdr32;
result = read_u32(&shdr32->sh_name, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_type, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_flags, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_addr, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_offset, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_size, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_link, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_info, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_addralign, content, &pos, length, format->endian);
result &= read_u32(&shdr32->sh_entsize, content, &pos, length, format->endian);
}
else
{
shdr64 = §ion->shdr64;
result = read_u32(&shdr64->sh_name, content, &pos, length, format->endian);
result &= read_u32(&shdr64->sh_type, content, &pos, length, format->endian);
result &= read_u64(&shdr64->sh_flags, content, &pos, length, format->endian);
result &= read_u64(&shdr64->sh_addr, content, &pos, length, format->endian);
result &= read_u64(&shdr64->sh_offset, content, &pos, length, format->endian);
result &= read_u64(&shdr64->sh_size, content, &pos, length, format->endian);
result &= read_u32(&shdr64->sh_link, content, &pos, length, format->endian);
result &= read_u32(&shdr64->sh_info, content, &pos, length, format->endian);
result &= read_u64(&shdr64->sh_addralign, content, &pos, length, format->endian);
result &= read_u64(&shdr64->sh_entsize, content, &pos, length, format->endian);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* pos = position de début de lecture. [OUT] *
* dyn = structure lue à retourner. [OUT] *
* *
* Description : Procède à la lecture d'une entrée de type 'DYNAMIC' ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_dynamic_entry(const GElfFormat *format, off_t *pos, elf_dyn *dyn)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
if (format->is_32b)
{
result = read_s32(&dyn->dyn32.d_tag, content, pos, length, format->endian);
result &= read_u32(&dyn->dyn32.d_un.d_val, content, pos, length, format->endian);
}
else
{
result = read_s64(&dyn->dyn64.d_tag, content, pos, length, format->endian);
result &= read_u64(&dyn->dyn64.d_un.d_val, content, pos, length, format->endian);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* pos = position de début de lecture. [OUT] *
* sym = structure lue à retourner. [OUT] *
* *
* Description : Procède à la lecture d'un symbole ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_symbol(const GElfFormat *format, off_t *pos, elf_sym *sym)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
if (format->is_32b)
{
result = read_u32(&sym->sym32.st_name, content, pos, length, format->endian);
result &= read_u32(&sym->sym32.st_value, content, pos, length, format->endian);
result &= read_u32(&sym->sym32.st_size, content, pos, length, format->endian);
result &= read_u8(&sym->sym32.st_info, content, pos, length, format->endian);
result &= read_u8(&sym->sym32.st_other, content, pos, length, format->endian);
result &= read_u16(&sym->sym32.st_shndx, content, pos, length, format->endian);
}
else
{
result = read_u32(&sym->sym64.st_name, content, pos, length, format->endian);
result &= read_u8(&sym->sym64.st_info, content, pos, length, format->endian);
result &= read_u8(&sym->sym64.st_other, content, pos, length, format->endian);
result &= read_u16(&sym->sym64.st_shndx, content, pos, length, format->endian);
result &= read_u64(&sym->sym64.st_value, content, pos, length, format->endian);
result &= read_u64(&sym->sym64.st_size, content, pos, length, format->endian);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* pos = position de début de lecture. [OUT] *
* reloc = structure lue à retourner. [OUT] *
* *
* Description : Procède à la lecture d'une relocalisation ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_relocation(const GElfFormat *format, off_t *pos, elf_rel *reloc)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
if (format->is_32b)
{
result = read_u32(&reloc->rel32.r_offset, content, pos, length, format->endian);
result &= read_u32(&reloc->rel32.r_info, content, pos, length, format->endian);
}
else
{
result = read_u64(&reloc->rel64.r_offset, content, pos, length, format->endian);
result &= read_u64(&reloc->rel64.r_info, content, pos, length, format->endian);
}
return result;
}