/* Chrysalide - Outil d'analyse de fichiers binaires
* elf-int.c - structures internes du format ELF
*
* Copyright (C) 2017-2018 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 Chrysalide. 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 GBinContent *content; /* Contenu binaire à lire */
vmpa2t pos; /* Position de lecture */
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, 0, VMPA_NO_VIRTUAL);
result = g_binary_content_read_raw(content, &pos, EI_NIDENT, (bin_t *)header->hdr32.e_ident);
/* 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 &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_type);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_machine);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr32.e_version);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr32.e_entry);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr32.e_phoff);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr32.e_shoff);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr32.e_flags);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_ehsize);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_phentsize);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_phnum);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_shentsize);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_shnum);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr32.e_shstrndx);
}
else
{
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_type);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_machine);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr64.e_version);
result &= g_binary_content_read_u64(content, &pos, *endian, &header->hdr64.e_entry);
result &= g_binary_content_read_u64(content, &pos, *endian, &header->hdr64.e_phoff);
result &= g_binary_content_read_u64(content, &pos, *endian, &header->hdr64.e_shoff);
result &= g_binary_content_read_u32(content, &pos, *endian, &header->hdr64.e_flags);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_ehsize);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_phentsize);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_phnum);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_shentsize);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_shnum);
result &= g_binary_content_read_u16(content, &pos, *endian, &header->hdr64.e_shstrndx);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* phys = position de début de lecture. *
* 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, phys_t phys, elf_phdr *header)
{
bool result; /* Bilan à retourner */
const GBinContent *content; /* Contenu binaire à lire */
vmpa2t pos; /* Position de lecture */
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, phys, VMPA_NO_VIRTUAL);
if (format->is_32b)
{
result = g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_type);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_offset);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_vaddr);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_paddr);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_filesz);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_memsz);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_flags);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr32.p_align);
}
else
{
result = g_binary_content_read_u32(content, &pos, format->endian, &header->phdr64.p_type);
result &= g_binary_content_read_u32(content, &pos, format->endian, &header->phdr64.p_flags);
result &= g_binary_content_read_u64(content, &pos, format->endian, &header->phdr64.p_offset);
result &= g_binary_content_read_u64(content, &pos, format->endian, &header->phdr64.p_vaddr);
result &= g_binary_content_read_u64(content, &pos, format->endian, &header->phdr64.p_paddr);
result &= g_binary_content_read_u64(content, &pos, format->endian, &header->phdr64.p_filesz);
result &= g_binary_content_read_u64(content, &pos, format->endian, &header->phdr64.p_memsz);
result &= g_binary_content_read_u64(content, &pos, format->endian, &header->phdr64.p_align);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* phys = position de début 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, phys_t phys, elf_shdr *section)
{
bool result; /* Bilan à retourner */
const GBinContent *content; /* Contenu binaire à lire */
vmpa2t pos; /* Position de lecture */
elf32_shdr *shdr32; /* Version 32 bits */
elf64_shdr *shdr64; /* Version 32 bits */
result = true;
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, phys, VMPA_NO_VIRTUAL);
if (format->is_32b)
{
shdr32 = §ion->shdr32;
result = g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_name);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_type);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_flags);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_addr);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_offset);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_size);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_link);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_info);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_addralign);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr32->sh_entsize);
}
else
{
shdr64 = §ion->shdr64;
result = g_binary_content_read_u32(content, &pos, format->endian, &shdr64->sh_name);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr64->sh_type);
result &= g_binary_content_read_u64(content, &pos, format->endian, &shdr64->sh_flags);
result &= g_binary_content_read_u64(content, &pos, format->endian, &shdr64->sh_addr);
result &= g_binary_content_read_u64(content, &pos, format->endian, &shdr64->sh_offset);
result &= g_binary_content_read_u64(content, &pos, format->endian, &shdr64->sh_size);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr64->sh_link);
result &= g_binary_content_read_u32(content, &pos, format->endian, &shdr64->sh_info);
result &= g_binary_content_read_u64(content, &pos, format->endian, &shdr64->sh_addralign);
result &= g_binary_content_read_u64(content, &pos, format->endian, &shdr64->sh_entsize);
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* phys = position de début de lecture. *
* 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, phys_t phys, elf_dyn *dyn)
{
bool result; /* Bilan à retourner */
const GBinContent *content; /* Contenu binaire à lire */
vmpa2t pos; /* Position de lecture */
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, phys, VMPA_NO_VIRTUAL);
if (format->is_32b)
{
result = g_binary_content_read_s32(content, &pos, format->endian, &dyn->dyn32.d_tag);
result &= g_binary_content_read_u32(content, &pos, format->endian, &dyn->dyn32.d_un.d_val);
}
else
{
result = g_binary_content_read_s64(content, &pos, format->endian, &dyn->dyn64.d_tag);
result &= g_binary_content_read_u64(content, &pos, format->endian, &dyn->dyn64.d_un.d_val);
}
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, phys_t *phys, elf_sym *sym)
{
bool result; /* Bilan à retourner */
const GBinContent *content; /* Contenu binaire à lire */
vmpa2t pos; /* Position de lecture */
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, *phys, VMPA_NO_VIRTUAL);
if (format->is_32b)
{
result = g_binary_content_read_u32(content, &pos, format->endian, &sym->sym32.st_name);
result &= g_binary_content_read_u32(content, &pos, format->endian, &sym->sym32.st_value);
result &= g_binary_content_read_u32(content, &pos, format->endian, &sym->sym32.st_size);
result &= g_binary_content_read_u8(content, &pos, &sym->sym32.st_info);
result &= g_binary_content_read_u8(content, &pos, &sym->sym32.st_other);
result &= g_binary_content_read_u16(content, &pos, format->endian, &sym->sym32.st_shndx);
}
else
{
result = g_binary_content_read_u32(content, &pos, format->endian, &sym->sym64.st_name);
result &= g_binary_content_read_u8(content, &pos, &sym->sym64.st_info);
result &= g_binary_content_read_u8(content, &pos, &sym->sym64.st_other);
result &= g_binary_content_read_u16(content, &pos, format->endian, &sym->sym64.st_shndx);
result &= g_binary_content_read_u64(content, &pos, format->endian, &sym->sym64.st_value);
result &= g_binary_content_read_u64(content, &pos, format->endian, &sym->sym64.st_size);
}
if (result)
*phys = get_phy_addr(&pos);
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* phys = 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, phys_t *phys, elf_rel *reloc)
{
bool result; /* Bilan à retourner */
const GBinContent *content; /* Contenu binaire à lire */
vmpa2t pos; /* Position de lecture */
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, *phys, VMPA_NO_VIRTUAL);
if (format->is_32b)
{
result = g_binary_content_read_u32(content, &pos, format->endian, &reloc->rel32.r_offset);
result &= g_binary_content_read_u32(content, &pos, format->endian, &reloc->rel32.r_info);
}
else
{
result = g_binary_content_read_u64(content, &pos, format->endian, &reloc->rel64.r_offset);
result &= g_binary_content_read_u64(content, &pos, format->endian, &reloc->rel64.r_info);
}
if (result)
*phys = get_phy_addr(&pos);
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* content = contenu binaire mis à disposition ou NULL. *
* pos = position de début de lecture. [OUT] *
* note = structure lue à retourner. [OUT] *
* *
* Description : Procède à la lecture d'une note ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool read_elf_note(const GElfFormat *format, GBinContent *content, phys_t *phys, elf_note *note)
{
bool result; /* Bilan à retourner */
vmpa2t pos; /* Position de lecture */
if (content == NULL)
content = G_KNOWN_FORMAT(format)->content;
init_vmpa(&pos, *phys, VMPA_NO_VIRTUAL);
result = g_binary_content_read_u32(content, &pos, format->endian, ¬e->namesz);
result &= g_binary_content_read_u32(content, &pos, format->endian, ¬e->descsz);
result &= g_binary_content_read_u32(content, &pos, format->endian, ¬e->type);
if (result && note->namesz > 0)
{
align_vmpa(&pos, 4);
note->name = (const char *)g_binary_content_get_raw_access(content, &pos, note->namesz);
result &= (note->name != NULL);
}
else note->name = NULL;
if (result && note->descsz > 0)
{
align_vmpa(&pos, 4);
note->desc = (const void *)g_binary_content_get_raw_access(content, &pos, note->descsz);
result &= (note->desc != NULL);
}
else note->desc = NULL;
return result;
}