/* Chrysalide - Outil d'analyse de fichiers binaires
* section.c - annotation des en-têtes de section de binaires ELF
*
* Copyright (C) 2015-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 "section.h"
#include
#include
#include
#include
#include
#include
#include
/* Définition des champs */
static field_desc_switch _elf_section_types[] = {
{ .fixed = SHT_NULL, .desc = __("Section type: unused") },
{ .fixed = SHT_PROGBITS, .desc = __("Section type: program data") },
{ .fixed = SHT_SYMTAB, .desc = __("Section type: symbol table") },
{ .fixed = SHT_STRTAB, .desc = __("Section type: string table") },
{ .fixed = SHT_RELA, .desc = __("Section type: relocation entries with addends") },
{ .fixed = SHT_HASH, .desc = __("Section type: symbol hash table") },
{ .fixed = SHT_DYNAMIC, .desc = __("Section type: dynamic linking information") },
{ .fixed = SHT_NOTE, .desc = __("Section type: notes") },
{ .fixed = SHT_NOBITS, .desc = __("Section type: program space with no data (bss)") },
{ .fixed = SHT_REL, .desc = __("Section type: relocation entries, no addends") },
{ .fixed = SHT_SHLIB, .desc = __("Section type: reserved") },
{ .fixed = SHT_DYNSYM, .desc = __("Section type: dynamic linker symbol table") },
{ .fixed = SHT_INIT_ARRAY, .desc = __("Section type: array of constructors") },
{ .fixed = SHT_FINI_ARRAY, .desc = __("Section type: array of destructors") },
{ .fixed = SHT_PREINIT_ARRAY, .desc = __("Section type: array of pre-constructors") },
{ .fixed = SHT_GROUP, .desc = __("Section type: section group") },
{ .fixed = SHT_SYMTAB_SHNDX, .desc = __("Section type: extended section indeces") },
{ .fixed = SHT_GNU_ATTRIBUTES, .desc = __("Section type: object attributes") },
{ .fixed = SHT_GNU_HASH, .desc = __("Section type: GNU-style hash table") },
{ .fixed = SHT_GNU_LIBLIST, .desc = __("Section type: prelink library list") },
{ .fixed = SHT_CHECKSUM, .desc = __("Section type: checksum for DSO content") },
{ .fixed = SHT_SUNW_move, .desc = __("Section type: SHT_SUNW_move") },
{ .fixed = SHT_SUNW_COMDAT, .desc = __("Section type: SHT_SUNW_COMDAT") },
{ .fixed = SHT_SUNW_syminfo, .desc = __("Section type: SHT_SUNW_syminfo") },
{ .fixed = SHT_GNU_verdef, .desc = __("Section type: version definition section") },
{ .fixed = SHT_GNU_verneed, .desc = __("Section type: version needs section") },
{ .fixed = SHT_GNU_versym, .desc = __("Section type: version symbol table") },
{ .lower = SHT_LOSUNW, .upper = SHT_HISUNW, .desc = __("Section type: Sun-specific") },
{ .lower = SHT_LOOS, .upper = SHT_HIOS, .desc = __("Section type: OS-specific") },
{ .lower = SHT_LOPROC, .upper = SHT_HIPROC, .desc = __("Section type: processor-specific") },
{ .lower = SHT_LOUSER, .upper = SHT_HIUSER, .desc = __("Section type: application-specific") }
};
static fmt_field_def _elf_sh_type[] = {
{
.name = "sh_type",
.size = MDS_32_BITS,
.repeat = 1,
SWITCH_COMMENT(_elf_section_types, __("Section type: unknown"))
}
};
static fmt_field_def _elf_shdr_32b[] = {
{
.name = "sh_addr",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Section virtual addr at execution"))
},
{
.name = "sh_offset",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Section file offset"))
},
{
.name = "sh_size",
.size = MDS_32_BITS,
.repeat = 1,
DISPLAY_RULES(IOD_DEC),
PLAIN_COMMENT(__("Section size in bytes"))
},
{
.name = "sh_link",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Link to another section"))
},
{
.name = "sh_info",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Additional section information"))
},
{
.name = "sh_addralign",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Section alignment"))
},
{
.name = "sh_entsize",
.size = MDS_32_BITS,
.repeat = 1,
DISPLAY_RULES(IOD_DEC),
PLAIN_COMMENT(__("Entry size if section holds table"))
}
};
static fmt_field_def _elf_shdr_64b[] = {
{
.name = "sh_addr",
.size = MDS_64_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Section virtual addr at execution"))
},
{
.name = "sh_offset",
.size = MDS_64_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Section file offset"))
},
{
.name = "sh_size",
.size = MDS_64_BITS,
.repeat = 1,
DISPLAY_RULES(IOD_DEC),
PLAIN_COMMENT(__("Section size in bytes"))
},
{
.name = "sh_link",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Link to another section"))
},
{
.name = "sh_info",
.size = MDS_32_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Additional section information"))
},
{
.name = "sh_addralign",
.size = MDS_64_BITS,
.repeat = 1,
PLAIN_COMMENT(__("Section alignment"))
},
{
.name = "sh_entsize",
.size = MDS_64_BITS,
.repeat = 1,
DISPLAY_RULES(IOD_DEC),
PLAIN_COMMENT(__("Entry size if section holds table"))
}
};
/* Charge tous les symboles liés à un en-tête de section ELF. */
static bool annotate_elf_section_header(GElfFormat *, GPreloadInfo *, SourceEndian, const elf_shdr *, vmpa2t *);
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* info = informations à constituer en avance de phase. *
* endian = boutisme présentement utilisé. *
* strings = section renvoyant vers des chaînes de caractères. *
* pos = tête de lecture à déplacer. [OUT] *
* *
* Description : Charge tous les symboles liés à un en-tête de section ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool annotate_elf_section_header(GElfFormat *format, GPreloadInfo *info, SourceEndian endian, const elf_shdr *strings, vmpa2t *pos)
{
bool result; /* Bilan à retourner */
elf_shdr shdr; /* En-tête de programme ELF */
fmt_field_def name_field; /* Définition du nom de section*/
const char *secname; /* Nom d'une section analysée */
comment_part nparts[2]; /* Mise en place des parties */
fmt_field_def flags_field; /* Définition des drapeaux */
char *rights; /* Reconstruction dynamique */
comment_part fparts[2]; /* Mise en place des parties */
GBinFormat *bformat; /* Autre version du format */
result = read_elf_section_header(format, get_phy_addr(pos), &shdr);
if (!result)
goto aesh_exit;
/* Préparation de la partie nominative */
memset(&name_field, 0, sizeof(name_field));
name_field.name = "sh_name";
name_field.size = MDS_32_BITS;
name_field.repeat = 1;
name_field.has_display_rules = true;
name_field.disp_rules = (ImmOperandDisplay []) { IOD_DEC };
name_field.disp_count = 1;
secname = extract_name_from_elf_string_section(format, strings,
ELF_SHDR(format, shdr, sh_name));
if (secname == NULL)
{
name_field.ctype = FCT_PLAIN;
name_field.comment.plain = __("Section name: ");
}
else
{
nparts[0].is_static = true;
nparts[0].static_text = __("Segment name: ");
nparts[1].is_static = true;
nparts[1].avoid_i18n = true;
nparts[1].static_text = secname;
name_field.ctype = FCT_MULTI;
name_field.comment.parts = nparts;
name_field.comment.pcount = ARRAY_SIZE(nparts);
}
/* Préparation de la partie des drapeaux */
memset(&flags_field, 0, sizeof(flags_field));
flags_field.name = "sh_flags";
flags_field.repeat = 1;
rights = NULL;
if (ELF_SHDR(format, shdr, sh_type) & SHF_WRITE)
rights = stradd(rights, "W");
if (ELF_SHDR(format, shdr, sh_type) & SHF_ALLOC)
rights = stradd(rights, "A");
if (ELF_SHDR(format, shdr, sh_type) & SHF_EXECINSTR)
rights = stradd(rights, "X");
if (ELF_SHDR(format, shdr, sh_type) & SHF_MERGE)
rights = stradd(rights, "M");
if (ELF_SHDR(format, shdr, sh_type) & SHF_LINK_ORDER)
rights = stradd(rights, "L");
if (ELF_SHDR(format, shdr, sh_type) & SHF_TLS)
rights = stradd(rights, "T");
if (rights == NULL)
{
flags_field.ctype = FCT_PLAIN;
flags_field.comment.plain = __("Section flags: none");
}
else
{
fparts[0].is_static = true;
fparts[0].static_text = __("Section flags: ");
fparts[1].is_static = false;
fparts[1].dynamic_text = rights;
flags_field.ctype = FCT_MULTI;
flags_field.comment.parts = fparts;
flags_field.comment.pcount = ARRAY_SIZE(fparts);
}
/* Interprétation générale */
bformat = G_BIN_FORMAT(format);
result = parse_field_definitions(&name_field, 1, bformat, info, pos, NULL);
if (result)
result = parse_field_definitions(PARSING_DEFS(_elf_sh_type), bformat, info, pos, NULL);
if (format->is_32b)
{
if (result)
{
flags_field.size = MDS_32_BITS;
result = parse_field_definitions(&flags_field, 1, bformat, info, pos, NULL);
}
if (result)
result = parse_field_definitions(PARSING_DEFS(_elf_shdr_32b), bformat, info, pos, NULL);
}
else
{
if (result)
{
flags_field.size = MDS_64_BITS;
result = parse_field_definitions(&flags_field, 1, bformat, info, pos, NULL);
}
if (result)
result = parse_field_definitions(PARSING_DEFS(_elf_shdr_64b), bformat, info, pos, NULL);
}
aesh_exit:
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* info = informations à constituer en avance de phase. *
* status = barre de statut à tenir informée. *
* *
* Description : Charge tous les symboles liés aux en-têtes de section ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool annotate_elf_section_header_table(GElfFormat *format, GPreloadInfo *info, GtkStatusStack *status)
{
bool result; /* Bilan à retourner */
const elf_header *header; /* En-tête principale */
SourceEndian endian; /* Boutisme utilisé */
elf_shdr strings; /* Section des descriptions */
off_t offset; /* Tête de lecture du binaire */
vmpa2t pos; /* Localisation des symboles */
uint16_t e_shnum; /* Nombre d'éléments 'Program' */
activity_id_t msg; /* Message de progression */
uint16_t i; /* Boucle de parcours */
result = true;
header = g_elf_format_get_header(format);
endian = g_binary_format_get_endianness(G_BIN_FORMAT(format));
if (!find_elf_section_by_index(format, ELF_HDR(format, *header, e_shstrndx), &strings))
return false;
offset = ELF_HDR(format, *header, e_shoff);
if (!g_exe_format_translate_offset_into_vmpa(G_EXE_FORMAT(format), offset, &pos))
init_vmpa(&pos, offset, VMPA_NO_VIRTUAL);
e_shnum = ELF_HDR(format, *header, e_shnum);
msg = gtk_status_stack_add_activity(status, _("Writing annotations for all Elf section headers..."), e_shnum);
for (i = 0; i < e_shnum && result; i++)
{
result = annotate_elf_section_header(format, info, endian, &strings, &pos);
gtk_status_stack_update_activity_value(status, msg, 1);
}
gtk_status_stack_remove_activity(status, msg);
return result;
}