/* Chrysalide - Outil d'analyse de fichiers binaires
* symbols.c - gestion des symboles d'un ELF
*
* Copyright (C) 2008-2013 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 "symbols.h"
#include
#include
#include
#include "elf-int.h"
#include "helper_x86.h"
#include "section.h"
#include "../mangling/demangler.h"
#include "../../arch/raw.h"
#include "../../common/extstr.h"
#include "../../core/params.h"
#include "../../gui/panels/log.h"
/* Récupère la désignation d'un symbole donné. */
const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t);
/* ------------------------ CHARGEMENT DE SYMBOLES DU FORMAT ------------------------ */
/* Charge tous les symboles de l'en-tête ELF. */
static bool annotate_elf_header(GElfFormat *);
/* Charge tous les symboles liés aux en-têtes de programme ELF. */
static bool annotate_elf_program_header_table(GElfFormat *);
/* Charge tous les symboles liés aux en-têtes de section ELF. */
static bool annotate_elf_section_header_table(GElfFormat *);
/* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */
/* Charge tous les symboles internes possibles. */
static bool load_elf_internal_symbols(GElfFormat *);
/* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */
/* Retrouve un élément donné dans la section dynamique. */
static bool find_elf_dynamic_item(const GElfFormat *, const elf_shdr *, int32_t, elf_dyn *);
/* Charge tous les éléments dynamiques externes possibles. */
static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *);
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* *
* Description : Charge en mémoire la liste humaine des symboles. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool load_elf_symbols(GElfFormat *format)
{
bool result; /* Bilan à retourner */
elf_shdr *sections; /* Groupe de sections trouvées */
size_t count; /* Quantité de données */
result = true;
annotate_elf_header(format);
annotate_elf_program_header_table(format);
annotate_elf_section_header_table(format);
/* Symboles internes */
result = load_elf_internal_symbols(format);
/* Symboles externes */
if (find_elf_sections_by_type(format, SHT_DYNAMIC, §ions, &count))
{
log_variadic_message(LMT_INFO, _("Binary is dynamically linked"));
result &= load_elf_external_symbols(format, §ions[0]);
free(sections);
}
else log_variadic_message(LMT_INFO, _("Binary is statically linked"));
/* Symboles internes */
//result &= load_elf_internal_symbols(format);
return result;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à consulter. *
* sym = section comprenant les symboles à venir lire. *
* str = section de chaînes de caractères pour les noms. *
* index = indice de l'entrée à venir lire. *
* *
* Description : Récupère la désignation d'un symbole donné. *
* *
* Retour : Nom du symbole trouvé, ou NULL si erreur ou non adapté. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const elf_shdr *str, off_t index)
{
const char *result; /* Résultat à retourner */
off_t sym_start; /* Début de section */
off_t sym_size; /* Taille de section */
off_t str_start; /* Début de section */
off_t str_size; /* Taille de section */
off_t offset; /* Emplacement à venir lire */
elf_sym symbol; /* Symbole aux infos visées */
result = NULL;
get_elf_section_content(format, sym, &sym_start, &sym_size, NULL);
get_elf_section_content(format, str, &str_start, &str_size, NULL);
offset = sym_start + index * ELF_SIZEOF_SYM(format);
if ((offset + ELF_SIZEOF_SYM(format)) > (sym_start + sym_size)) return NULL;
if (read_elf_symbol(format, &offset, &symbol))
result = extract_name_from_elf_string_section(format, str, ELF_SYM(format, symbol, st_name));
return result;
}
/* ---------------------------------------------------------------------------------- */
/* CHARGEMENT DE SYMBOLES DU FORMAT */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* *
* Description : Charge tous les symboles de l'en-tête ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool annotate_elf_header(GElfFormat *format)
{
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
vmpa2t *pos; /* Localisation des symboles */
const char *text; /* Texte constant à insérer */
GArchInstruction *instr; /* Instruction décodée */
GArchOperand *operand; /* Opérande à venir modifier */
GDbComment *comment; /* Définition de commentaire */
GBinSymbol *symbol; /* Symbole à intégrer */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
pos = make_vmpa(0, 0x123);
/* ELFMAG (0) */
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 4, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 1, IOD_CHAR);
SET_IMM_DISPLAY(instr, operand, 2, IOD_CHAR);
SET_IMM_DISPLAY(instr, operand, 3, IOD_CHAR);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("ELF magic number"));
/* EI_CLASS (4) */
switch (format->header.hdr32.e_ident[EI_CLASS])
{
case EV_NONE:
text = _("File class: invalid");
break;
case ELFCLASS32:
text = _("File class: 32-bit objects");
break;
case ELFCLASS64:
text = _("File class: 64-bit objects");
break;
default:
text = _("File class: unknown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* EI_DATA (5) */
switch (format->header.hdr32.e_ident[EI_DATA])
{
case ELFDATANONE:
text = _("Data encoding: invalid");
break;
case ELFDATA2LSB:
text = _("Data encoding: 2's complement, little endian");
break;
case ELFDATA2MSB:
text = _("Data encoding: 2's complement, big endian");
break;
default:
text = _("Data encoding: unknown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* EI_VERSION (6) */
switch (format->header.hdr32.e_ident[EI_VERSION])
{
case EV_NONE:
text = _("File version: invalid");
break;
case EV_CURRENT:
text = _("File version: current");
break;
default:
text = _("File version: unknown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* EI_OSABI (7) */
switch (format->header.hdr32.e_ident[EI_OSABI])
{
case ELFOSABI_SYSV:
text = _("OS ABI: UNIX System V");
break;
case ELFOSABI_HPUX:
text = _("OS ABI: HP-UX");
break;
case ELFOSABI_NETBSD:
text = _("OS ABI: NetBSD");
break;
case ELFOSABI_GNU:
text = _("OS ABI: object uses GNU ELF extensions");
break;
case ELFOSABI_SOLARIS:
text = _("OS ABI: Sun Solaris");
break;
case ELFOSABI_AIX:
text = _("OS ABI: IBM AIX");
break;
case ELFOSABI_IRIX:
text = _("OS ABI: SGI Irix");
break;
case ELFOSABI_FREEBSD:
text = _("OS ABI: FreeBSD");
break;
case ELFOSABI_TRU64:
text = _("OS ABI: Compaq TRU64 UNIX");
break;
case ELFOSABI_MODESTO:
text = _("OS ABI: Novell Modesto");
break;
case ELFOSABI_OPENBSD:
text = _("OS ABI: OpenBSD");
break;
case ELFOSABI_ARM_AEABI:
text = _("OS ABI: ARM EABI");
break;
case ELFOSABI_ARM:
text = _("OS ABI: ARM");
break;
case ELFOSABI_STANDALONE:
text = _("OS ABI: standalone (embedded) application");
break;
default:
text = _("OS ABI: unknown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* EI_ABIVERSION (8) */
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("ABI version"));
/* Padding */
instr = g_raw_instruction_new_array(content, MDS_8_BITS, 7, pos, length, format->endian);
g_raw_instruction_mark_as_padding(G_RAW_INSTRUCTION(instr), true);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Padding"));
/* Champ "e_type" */
switch (format->header.hdr32.e_ident[EI_DATA])
{
case ET_NONE:
text = _("Object file type: no file type");
break;
case ET_REL:
text = _("Object file type: relocatable file");
break;
case ET_EXEC:
text = _("Object file type: executable file");
break;
case ET_DYN:
text = _("Object file type: shared object file");
break;
case ET_CORE:
text = _("Object file type: core file");
break;
case ET_LOOS ... ET_HIOS:
text = _("Object file type: OS-specific");
break;
case ET_LOPROC ... ET_HIPROC:
text = _("Object file type: processor-specific");
break;
default:
text = _("Object file type: unkown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* Champ "e_machine" */
switch (format->header.hdr32.e_machine)
{
case EM_NONE: text = _("Architecture: No machine"); break;
case EM_M32: text = _("Architecture: AT&T WE 32100"); break;
case EM_SPARC: text = _("Architecture: SUN SPARC"); break;
case EM_386: text = _("Architecture: Intel 80386"); break;
case EM_68K: text = _("Architecture: Motorola m68k family"); break;
case EM_88K: text = _("Architecture: Motorola m88k family"); break;
case EM_860: text = _("Architecture: Intel 80860"); break;
case EM_MIPS: text = _("Architecture: MIPS R3000 big-endian"); break;
case EM_S370: text = _("Architecture: IBM System/370"); break;
case EM_MIPS_RS3_LE:text = _("Architecture: MIPS R3000 little-endian"); break;
case EM_PARISC: text = _("Architecture: HPPA"); break;
case EM_VPP500: text = _("Architecture: Fujitsu VPP500"); break;
case EM_SPARC32PLUS:text = _("Architecture: Sun's \"v8plus\""); break;
case EM_960: text = _("Architecture: Intel 80960"); break;
case EM_PPC: text = _("Architecture: PowerPC"); break;
case EM_PPC64: text = _("Architecture: PowerPC 64-bit"); break;
case EM_S390: text = _("Architecture: IBM S390"); break;
case EM_V800: text = _("Architecture: NEC V800 series"); break;
case EM_FR20: text = _("Architecture: Fujitsu FR20"); break;
case EM_RH32: text = _("Architecture: TRW RH-32"); break;
case EM_RCE: text = _("Architecture: Motorola RCE"); break;
case EM_ARM: text = _("Architecture: ARM"); break;
case EM_FAKE_ALPHA: text = _("Architecture: Digital Alpha"); break;
case EM_SH: text = _("Architecture: Hitachi SH"); break;
case EM_SPARCV9: text = _("Architecture: SPARC v9 64-bit"); break;
case EM_TRICORE: text = _("Architecture: Siemens Tricore"); break;
case EM_ARC: text = _("Architecture: Argonaut RISC Core"); break;
case EM_H8_300: text = _("Architecture: Hitachi H8/300"); break;
case EM_H8_300H: text = _("Architecture: Hitachi H8/300H"); break;
case EM_H8S: text = _("Architecture: Hitachi H8S"); break;
case EM_H8_500: text = _("Architecture: Hitachi H8/500"); break;
case EM_IA_64: text = _("Architecture: Intel Merced"); break;
case EM_MIPS_X: text = _("Architecture: Stanford MIPS-X"); break;
case EM_COLDFIRE: text = _("Architecture: Motorola Coldfire"); break;
case EM_68HC12: text = _("Architecture: Motorola M68HC12"); break;
case EM_MMA: text = _("Architecture: Fujitsu MMA Multimedia Accelerator"); break;
case EM_PCP: text = _("Architecture: Siemens PCP"); break;
case EM_NCPU: text = _("Architecture: Sony nCPU embeeded RISC"); break;
case EM_NDR1: text = _("Architecture: Denso NDR1 microprocessor"); break;
case EM_STARCORE: text = _("Architecture: Motorola Start*Core processor"); break;
case EM_ME16: text = _("Architecture: Toyota ME16 processor"); break;
case EM_ST100: text = _("Architecture: STMicroelectronic ST100 processor"); break;
case EM_TINYJ: text = _("Architecture: Advanced Logic Corp. Tinyj emb.fam"); break;
case EM_X86_64: text = _("Architecture: AMD x86-64 architecture"); break;
case EM_PDSP: text = _("Architecture: Sony DSP Processor"); break;
case EM_FX66: text = _("Architecture: Siemens FX66 microcontroller"); break;
case EM_ST9PLUS: text = _("Architecture: STMicroelectronics ST9+ 8/16 mc"); break;
case EM_ST7: text = _("Architecture: STmicroelectronics ST7 8 bit mc"); break;
case EM_68HC16: text = _("Architecture: Motorola MC68HC16 microcontroller"); break;
case EM_68HC11: text = _("Architecture: Motorola MC68HC11 microcontroller"); break;
case EM_68HC08: text = _("Architecture: Motorola MC68HC08 microcontroller"); break;
case EM_68HC05: text = _("Architecture: Motorola MC68HC05 microcontroller"); break;
case EM_SVX: text = _("Architecture: Silicon Graphics SVx"); break;
case EM_ST19: text = _("Architecture: STMicroelectronics ST19 8 bit mc"); break;
case EM_VAX: text = _("Architecture: Digital VAX"); break;
case EM_CRIS: text = _("Architecture: Axis Communications 32-bit embedded processor"); break;
case EM_JAVELIN: text = _("Architecture: Infineon Technologies 32-bit embedded processor"); break;
case EM_FIREPATH: text = _("Architecture: Element 14 64-bit DSP Processor"); break;
case EM_ZSP: text = _("Architecture: LSI Logic 16-bit DSP Processor"); break;
case EM_MMIX: text = _("Architecture: Donald Knuth's educational 64-bit processor"); break;
case EM_HUANY: text = _("Architecture: Harvard University machine-independent object files"); break;
case EM_PRISM: text = _("Architecture: SiTera Prism"); break;
case EM_AVR: text = _("Architecture: Atmel AVR 8-bit microcontroller"); break;
case EM_FR30: text = _("Architecture: Fujitsu FR30"); break;
case EM_D10V: text = _("Architecture: Mitsubishi D10V"); break;
case EM_D30V: text = _("Architecture: Mitsubishi D30V"); break;
case EM_V850: text = _("Architecture: NEC v850"); break;
case EM_M32R: text = _("Architecture: Mitsubishi M32R"); break;
case EM_MN10300: text = _("Architecture: Matsushita MN10300"); break;
case EM_MN10200: text = _("Architecture: Matsushita MN10200"); break;
case EM_PJ: text = _("Architecture: picoJava"); break;
case EM_OPENRISC: text = _("Architecture: OpenRISC 32-bit embedded processor"); break;
case EM_ARC_A5: text = _("Architecture: ARC Cores Tangent-A5"); break;
case EM_XTENSA: text = _("Architecture: Tensilica Xtensa Architecture"); break;
case EM_AARCH64: text = _("Architecture: ARM AARCH64"); break;
case EM_TILEPRO: text = _("Architecture: Tilera TILEPro"); break;
case EM_MICROBLAZE: text = _("Architecture: Xilinx MicroBlaze"); break;
case EM_TILEGX: text = _("Architecture: Tilera TILE-Gx"); break;
default: text = _("Architecture: unknown"); break;
}
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* Champ "e_version" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Object file version"));
if (format->header.hdr32.e_ident[EI_CLASS] == ELFCLASS32)
{
/* Champ "e_entry" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry point virtual address"));
/* Champ "e_phoff" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table file offset"));
/* Champ "e_shoff" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table file offset"));
}
else if (format->header.hdr32.e_ident[EI_CLASS] == ELFCLASS64)
{
/* Champ "e_entry" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry point virtual address"));
/* Champ "e_phoff" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table file offset"));
/* Champ "e_shoff" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table file offset"));
}
else return false;
/* Champ "e_flags" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
//SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Processor-specific flags"));
/* Champ "e_ehsize" */
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("ELF header size in bytes"));
/* Champ "e_phentsize" */
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table entry size"));
/* Champ "e_phnum" */
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table entry count"));
/* Champ "e_shentsize" */
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table entry size"));
/* Champ "e_shnum" */
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table entry count"));
/* Champ "e_shstrndx" */
instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header string table index"));
return true;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* *
* Description : Charge tous les symboles liés aux en-têtes de programme ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool annotate_elf_program_header_table(GElfFormat *format)
{
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
off_t offset; /* Tête de lecture du bbinaire */
vmpa2t *pos; /* Localisation des symboles */
uint16_t e_phnum; /* Nombre d'éléments 'Program' */
uint16_t i; /* Boucle de parcours */
elf_phdr phdr; /* En-tête de programme ELF */
ImmOperandDisplay disp; /* Afficahge de valeur */
const char *text; /* Texte constant à insérer */
GArchInstruction *instr; /* Instruction décodée */
GArchOperand *operand; /* Opérande à venir modifier */
GDbComment *comment; /* Définition de commentaire */
GBinSymbol *symbol; /* Symbole à intégrer */
char *dtext; /* Texte dynamique à créer */
bool filled; /* Suivi de mise en place */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
offset = ELF_HDR(format, format->header, e_phoff);
pos = make_vmpa(offset, 0x5500);
e_phnum = ELF_HDR(format, format->header, e_phnum);
for (i = 0; i < e_phnum; i++)
{
if (!read_elf_program_header(format, &offset, &phdr))
break;
/* Champ "p_type" */
disp = IOD_DEC;
switch (ELF_PHDR(format, phdr, p_type))
{
case PT_NULL:
text = _("Segment type: unused");
break;
case PT_LOAD:
text = _("Segment type: loadable program segment");
break;
case PT_DYNAMIC:
text = _("Segment type: dynamic linking information");
break;
case PT_INTERP:
text = _("Segment type: program interpreter");
break;
case PT_NOTE:
text = _("Segment type: auxiliary information");
break;
case PT_SHLIB:
text = _("Segment type: reserved");
break;
case PT_PHDR:
text = _("Segment type: entry for header table itself");
break;
case PT_TLS:
text = _("Segment type: thread-local storage segment");
break;
case PT_LOOS ... PT_HIOS:
disp = IOD_HEX;
switch (ELF_PHDR(format, phdr, p_type))
{
case PT_GNU_EH_FRAME:
text = _("Segment type: GCC .eh_frame_hdr segment");
break;
case PT_GNU_STACK:
text = _("Segment type: indicates stack executability");
break;
case PT_GNU_RELRO:
text = _("Segment type: read-only after relocation");
break;
case PT_LOSUNW ... PT_HISUNW:
switch (ELF_PHDR(format, phdr, p_type))
{
case PT_SUNWSTACK:
text = _("Segment type: Sun Stack segment");
break;
default:
text = _("Segment type: Sun specific segment");
break;
}
break;
default:
text = _("Segment type: OS-specific");
break;
}
break;
case PT_LOPROC ... PT_HIPROC:
disp = IOD_HEX;
text = _("Segment type: processor-specific");
break;
default:
disp = IOD_HEX;
text = _("Segment type: unknown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, disp);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
if (format->is_32b)
{
/* Champ "p_offset" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment file offset"));
/* Champ "p_vaddr" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment virtual address"));
/* Champ "p_paddr" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment physical address"));
/* Champ "p_filesz" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in file"));
/* Champ "p_memsz" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in memory"));
/* Champ "p_flags" */
dtext = strdup(_("Segment flags: "));
filled = false;
if (ELF_PHDR(format, phdr, p_flags) & PF_R)
{
dtext = stradd(dtext, "R");
filled = true;
}
if (ELF_PHDR(format, phdr, p_flags) & PF_W)
{
dtext = stradd(dtext, "W");
filled = true;
}
if (ELF_PHDR(format, phdr, p_flags) & PF_X)
{
dtext = stradd(dtext, "X");
filled = true;
}
if (ELF_PHDR(format, phdr, p_flags) & PF_MASKOS)
/* TODO */;
if (ELF_PHDR(format, phdr, p_flags) & PF_MASKPROC)
/* TODO */;
if (!filled)
dtext = stradd(dtext, _("none"));
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
free(dtext);
/* Champ "p_align" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment alignment"));
}
else
{
/* Champ "p_flags" */
dtext = strdup(_("Segment flags: "));
filled = false;
if (ELF_PHDR(format, phdr, p_flags) & PF_R)
{
dtext = stradd(dtext, "R");
filled = true;
}
if (ELF_PHDR(format, phdr, p_flags) & PF_W)
{
dtext = stradd(dtext, "W");
filled = true;
}
if (ELF_PHDR(format, phdr, p_flags) & PF_X)
{
dtext = stradd(dtext, "X");
filled = true;
}
if (ELF_PHDR(format, phdr, p_flags) & PF_MASKOS)
/* TODO */;
if (ELF_PHDR(format, phdr, p_flags) & PF_MASKPROC)
/* TODO */;
if (!filled)
dtext = stradd(dtext, _("none"));
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
free(dtext);
/* Champ "p_offset" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment file offset"));
/* Champ "p_vaddr" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment virtual address"));
/* Champ "p_paddr" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment physical address"));
/* Champ "p_filesz" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in file"));
/* Champ "p_memsz" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in memory"));
/* Champ "p_align" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment alignment"));
}
}
return true;
}
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* *
* Description : Charge tous les symboles liés aux en-têtes de section ELF. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool annotate_elf_section_header_table(GElfFormat *format)
{
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
off_t offset; /* Tête de lecture du bbinaire */
elf_shdr strings; /* Section des descriptions */
vmpa2t *pos; /* Localisation des symboles */
uint16_t e_shnum; /* Nombre d'éléments 'Program' */
uint16_t i; /* Boucle de parcours */
elf_shdr shdr; /* En-tête de programme ELF */
const char *secname; /* Nom d'une section analysée */
ImmOperandDisplay disp; /* Afficahge de valeur */
const char *text; /* Texte constant à insérer */
GArchInstruction *instr; /* Instruction décodée */
GArchOperand *operand; /* Opérande à venir modifier */
GDbComment *comment; /* Définition de commentaire */
GBinSymbol *symbol; /* Symbole à intégrer */
char *dtext; /* Texte dynamique à créer */
bool filled; /* Suivi de mise en place */
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
if (!find_elf_section_by_index(format, ELF_HDR(format, format->header, e_shstrndx), &strings))
return false;
offset = ELF_HDR(format, format->header, e_shoff);
pos = make_vmpa(offset, 0x9900);
e_shnum = ELF_HDR(format, format->header, e_shnum);
for (i = 0; i < e_shnum; i++)
{
if (!read_elf_section_header(format, get_phy_addr(pos), &shdr))
break;
/* Champ "sh_name" */
secname = extract_name_from_elf_string_section(format, &strings,
ELF_SHDR(format, shdr, sh_name));
if (secname == NULL)
dtext = strdup(_("Section name: "));
else
{
dtext = strdup(_("Section name: '"));
dtext = stradd(dtext, secname);
dtext = stradd(dtext, "'");
}
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
free(dtext);
/* Champ "sh_type" */
disp = IOD_DEC;
switch (ELF_SHDR(format, shdr, sh_type))
{
case SHT_NULL:
text = _("Section type: unused");
break;
case SHT_PROGBITS:
text = _("Section type: program data");
break;
case SHT_SYMTAB:
text = _("Section type: symbol table");
break;
case SHT_STRTAB:
text = _("Section type: string table");
break;
case SHT_RELA:
text = _("Section type: relocation entries with addends");
break;
case SHT_HASH:
text = _("Section type: symbol hash table");
break;
case SHT_DYNAMIC:
text = _("Section type: dynamic linking information");
break;
case SHT_NOTE:
text = _("Section type: notes");
break;
case SHT_NOBITS:
text = _("Section type: program space with no data (bss)");
break;
case SHT_REL:
text = _("Section type: relocation entries, no addends");
break;
case SHT_SHLIB:
text = _("Section type: reserved");
break;
case SHT_DYNSYM:
text = _("Section type: dynamic linker symbol table");
break;
case SHT_INIT_ARRAY:
text = _("Section type: array of constructors");
break;
case SHT_FINI_ARRAY:
text = _("Section type: array of destructors");
break;
case SHT_PREINIT_ARRAY:
text = _("Section type: array of pre-constructors");
break;
case SHT_GROUP:
text = _("Section type: section group");
break;
case SHT_SYMTAB_SHNDX:
text = _("Section type: extended section indeces");
break;
case SHT_LOOS ... SHT_HIOS:
disp = IOD_HEX;
switch (ELF_SHDR(format, shdr, sh_type))
{
case SHT_GNU_ATTRIBUTES:
text = _("Section type: object attributes");
break;
case SHT_GNU_HASH:
text = _("Section type: GNU-style hash table");
break;
case SHT_GNU_LIBLIST:
text = _("Section type: prelink library list");
break;
case SHT_CHECKSUM:
text = _("Section type: checksum for DSO content");
break;
case SHT_LOSUNW ... SHT_HISUNW:
switch (ELF_SHDR(format, shdr, sh_type))
{
case SHT_SUNW_move:
text = _("Section type: SHT_SUNW_move");
break;
case SHT_SUNW_COMDAT:
text = _("Section type: SHT_SUNW_COMDAT");
break;
case SHT_SUNW_syminfo:
text = _("Section type: SHT_SUNW_syminfo");
break;
case SHT_GNU_verdef:
text = _("Section type: version definition section");
break;
case SHT_GNU_verneed:
text = _("Section type: version needs section");
break;
case SHT_GNU_versym:
text = _("Section type: version symbol table");
break;
default:
text = _("Section type: Sun-specific");
break;
}
break;
default:
text = _("Section type: OS-specific");
break;
}
break;
case SHT_LOPROC ... SHT_HIPROC:
disp = IOD_HEX;
text = _("Section type: processor-specific");
break;
case SHT_LOUSER ... SHT_HIUSER:
disp = IOD_HEX;
text = _("Section type: application-specific");
break;
default:
disp = IOD_HEX;
text = _("Section type: unknown");
break;
}
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, disp);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
/* Champ "sh_flags"... */
dtext = strdup(_("Section flags: "));
filled = false;
if (ELF_SHDR(format, shdr, sh_type) & SHF_WRITE)
{
dtext = stradd(dtext, "W");
filled = true;
}
if (ELF_SHDR(format, shdr, sh_type) & SHF_ALLOC)
{
dtext = stradd(dtext, "A");
filled = true;
}
if (ELF_SHDR(format, shdr, sh_type) & SHF_EXECINSTR)
{
dtext = stradd(dtext, "X");
filled = true;
}
if (ELF_SHDR(format, shdr, sh_type) & SHF_MERGE)
{
dtext = stradd(dtext, "M");
filled = true;
}
if (ELF_SHDR(format, shdr, sh_type) & SHF_LINK_ORDER)
{
dtext = stradd(dtext, "L");
filled = true;
}
if (ELF_SHDR(format, shdr, sh_type) & SHF_TLS)
{
dtext = stradd(dtext, "T");
filled = true;
}
if (!filled)
dtext = stradd(dtext, _("none"));
if (format->is_32b)
{
/* Champ "sh_flags" (suite) */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
free(dtext);
/* Champ "sh_addr" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section virtual addr at execution"));
/* Champ "sh_offset" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section file offset"));
/* Champ "sh_size" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section size in bytes"));
}
else
{
/* Champ "sh_flags" (suite) */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
free(dtext);
/* Champ "sh_addr" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section virtual addr at execution"));
/* Champ "sh_offset" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section file offset"));
/* Champ "sh_size" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section size in bytes"));
}
/* Champ "sh_link" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Link to another section"));
/* Champ "sh_info" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Additional section information"));
if (format->is_32b)
{
/* Champ "sh_addralign" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section alignment"));
/* Champ "sh_entsize" */
instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry size if section holds table"));
}
else
{
/* Champ "sh_addralign" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section alignment"));
/* Champ "sh_entsize" */
instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry size if section holds table"));
}
}
return true;
}
/* ---------------------------------------------------------------------------------- */
/* DETAIL DES SYMBOLES INTERNES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
* *
* Description : Charge tous les symboles internes possibles. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool load_elf_internal_symbols(GElfFormat *format)
{
bool result; /* Bilan à retourner */
bool no_name; /* Choix de construction de nom*/
elf_shdr *sections; /* Groupe de sections trouvées */
size_t count; /* Quantité de données */
size_t i; /* Boucle de parcours */
result = true;
/* Charge tous les symboles définis dans une section */
bool add_all_symbols_from_section(GElfFormat *format, const elf_shdr *section, bool use_virt)
{
elf_shdr strtab; /* Section .strtab trouvée */
bool has_strtab; /* Présence de cette section */
off_t start; /* Début de la zone à traiter */
off_t size; /* Taille de cette même zone */
off_t iter; /* Boucle de parcours */
elf_sym sym; /* Symbole aux infos visées */
vmpa2t addr; /* Localisation d'une routine */
mrange_t range; /* Couverture mémoire associée */
const char *name; /* Nom du symbole trouvé */
char alt_name[5 + VMPA_MAX_LEN]; /* Nom abstrait de substitution*/
GBinRoutine *routine; /* Nouvelle routine trouvée */
GBinSymbol *symbol; /* Nouveau symbole construit */
has_strtab = find_elf_section_by_index(format, ELF_SHDR(format, *section, sh_link), &strtab);
get_elf_section_content(format, section, &start, &size, NULL);
for (iter = start; iter < (start + size); )
{
result = read_elf_symbol(format, &iter, &sym);
if (!result) break;
if (ELF_SYM(format, sym, st_value) == 0) continue;
/* Résolution précise d'adresse */
/* TODO */
init_vmpa(&addr, ELF_SYM(format, sym, st_value), VMPA_NO_VIRTUAL);
init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
/* Première ébauche de nom */
if (!has_strtab) name = NULL;
else name = get_elf_symbol_name(format, section, &strtab,
((iter - start) / ELF_SIZEOF_SYM(format)) - 1);
/* Traitements particuliers */
switch (ELF_ST_TYPE(format, sym))
{
case STT_OBJECT:
/* Création d'un nom unique ? */
if (name != NULL)
{
strcpy(alt_name, "obj_");
if (use_virt)
vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
else
vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
}
/* TODO */
symbol = NULL;
break;
case STT_FUNC:
/* Création d'un nom unique ? */
if (name != NULL)
{
strcpy(alt_name, "func_");
if (use_virt)
vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
else
vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
}
/* Routine */
routine = try_to_demangle_routine(name);
g_binary_routine_set_range(routine, &range);
/* Symbole uniquement */
symbol = g_binary_symbol_new(STP_ROUTINE, name, ~0);
g_binary_symbol_attach_routine(symbol, routine);
break;
default:
symbol = NULL;
break;
}
if (symbol != NULL)
g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);
}
return true;
}
if (!g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &no_name))
return false;
if (find_elf_sections_by_type(format, SHT_DYNSYM, §ions, &count))
for (i = 0; i < count && result; i++)
result = add_all_symbols_from_section(format, §ions[i], no_name);
if (find_elf_sections_by_type(format, SHT_SYMTAB, §ions, &count))
for (i = 0; i < count && result; i++)
result = add_all_symbols_from_section(format, §ions[i], no_name);
return result;
}
/* ---------------------------------------------------------------------------------- */
/* DETAIL DES SYMBOLES EXTERNES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* dynamic = section de type SHT_DYNAMIC. *
* type = sorte d'élément recherché. *
* item = élément retrouvé dans la section. [OUT] *
* *
* Description : Retrouve un élément donné dans la section dynamique. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *section, int32_t type, elf_dyn *item)
{
bool result; /* Bilan à retourner */
const bin_t *content; /* Contenu binaire à lire */
off_t length; /* Taille totale du contenu */
off_t pos; /* Position de lecture */
off_t tmp; /* Position écrasable */
int32_t tag32; /* Type de l'entrée (32 bits) */
int64_t tag64; /* Type de l'entrée (64 bits) */
result = true;
content = G_BIN_FORMAT(format)->content;
length = G_BIN_FORMAT(format)->length;
for (pos = ELF_SHDR(format, *section, sh_offset);
pos < length/* FIXME !! + xploit */ && result;
pos += ELF_SIZEOF_DYN(format))
{
tmp = pos;
if (format->is_32b)
{
result = read_s32(&tag32, content, &tmp, length, format->endian);
if (tag32 == type) break;
}
else
{
result = read_s64(&tag64, content, &tmp, length, format->endian);
if (tag64 == type) break;
}
}
result &= (pos < length);
if (result)
{
if (format->is_32b)
{
result = read_s32(&item->dyn32.d_tag, content, &pos, length, format->endian);
result &= read_s32(&item->dyn32.d_un.d_val, content, &pos, length, format->endian);
}
else
{
result = read_s64(&item->dyn64.d_tag, content, &pos, length, format->endian);
result &= read_s64(&item->dyn64.d_un.d_val, content, &pos, length, format->endian);
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : format = informations chargées à consulter. *
* dynamic = section de type SHT_DYNAMIC. *
* *
* Description : Charge tous les éléments dynamiques externes possibles. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool load_elf_external_symbols(GElfFormat *format, const elf_shdr *section)
{
bool result; /* Bilan à retourner */
elf_dyn item; /* Elément dynamique */
elf_shdr relxxx; /* Section .rel.xxx trouvée */
elf_shdr dynsym; /* Section .dynsym trouvée */
elf_shdr dynstr; /* Section .dynstr trouvée */
elf_shdr plt; /* Section .plt trouvée */
result = true;
/* Section .rel.plt */
if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
{
result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);
if (result)
result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_link), &dynsym);
if (result)
result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);
if (result)
switch (g_exe_format_get_target_machine(G_EXE_FORMAT(format)))
{
case FTM_386:
result = load_elf_x86_relocated_symbols(format, &relxxx, &dynsym, &dynstr);
break;
default:
break;
}
}
/* Entrées équivalentes dans le binaire */
if (find_elf_dynamic_item(format, section, DT_SYMTAB, &item))
{
result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &dynsym);
if (result)
result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);
if (result)
switch (g_exe_format_get_target_machine(G_EXE_FORMAT(format)))
{
case FTM_MIPS:
//result = find_elf_mips_dynamic_symbols(format, &dynsym, &dynstr);
break;
case FTM_386:
if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
{
result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);
printf("VMA :: 0x%08llx\n", ELF_DYN(format, item, d_un.d_ptr));
if (result)
result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_info), &plt);
if (result)
result = find_elf_x86_dynamic_symbols(format, &plt, &relxxx, &dynsym, &dynstr);
}
break;
default:
break;
}
}
return result;
}