2020-12-29 11:04:29 +03:00
/*
* Copyright ( c ) 2020 , the SerenityOS developers .
*
2021-04-22 11:24:48 +03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-12-29 11:04:29 +03:00
*/
# include <AK/MappedFile.h>
# include <AK/String.h>
# include <AK/StringBuilder.h>
# include <AK/StringView.h>
# include <LibCore/ArgsParser.h>
2021-03-22 08:58:28 +03:00
# include <LibCore/File.h>
# include <LibELF/DynamicLoader.h>
# include <LibELF/DynamicObject.h>
2020-12-29 11:04:29 +03:00
# include <LibELF/Image.h>
# include <LibELF/Validation.h>
# include <ctype.h>
2021-04-11 06:53:37 +03:00
# include <fcntl.h>
2020-12-29 11:04:29 +03:00
# include <stdio.h>
2021-03-12 19:29:37 +03:00
# include <unistd.h>
2020-12-29 11:04:29 +03:00
static const char * object_file_type_to_string ( Elf32_Half type )
{
switch ( type ) {
case ET_NONE :
return " None " ;
case ET_REL :
return " Relocatable " ;
case ET_EXEC :
return " Executable " ;
case ET_DYN :
return " Shared object " ;
case ET_CORE :
return " Core " ;
default :
return " (?) " ;
}
}
static const char * object_machine_type_to_string ( Elf32_Half type )
{
switch ( type ) {
case ET_NONE :
return " None " ;
case EM_M32 :
return " AT&T WE 32100 " ;
case EM_SPARC :
return " SPARC " ;
case EM_386 :
return " Intel 80386 " ;
case EM_68K :
return " Motorola 68000 " ;
case EM_88K :
return " Motorola 88000 " ;
case EM_486 :
return " Intel 80486 " ;
case EM_860 :
return " Intel 80860 " ;
case EM_MIPS :
return " MIPS R3000 Big-Endian only " ;
default :
return " (?) " ;
}
}
static const char * object_program_header_type_to_string ( Elf32_Word type )
{
switch ( type ) {
case PT_NULL :
return " NULL " ;
case PT_LOAD :
return " LOAD " ;
case PT_DYNAMIC :
return " DYNAMIC " ;
case PT_INTERP :
return " INTERP " ;
case PT_NOTE :
return " NOTE " ;
case PT_SHLIB :
return " SHLIB " ;
case PT_PHDR :
return " PHDR " ;
case PT_TLS :
return " TLS " ;
case PT_LOOS :
return " LOOS " ;
case PT_HIOS :
return " HIOS " ;
case PT_LOPROC :
return " LOPROC " ;
case PT_HIPROC :
return " HIPROC " ;
case PT_GNU_EH_FRAME :
return " GNU_EH_FRAME " ;
case PT_GNU_RELRO :
return " GNU_RELRO " ;
case PT_GNU_STACK :
return " GNU_STACK " ;
case PT_OPENBSD_RANDOMIZE :
return " OPENBSD_RANDOMIZE " ;
case PT_OPENBSD_WXNEEDED :
return " OPENBSD_WXNEEDED " ;
case PT_OPENBSD_BOOTDATA :
return " OPENBSD_BOOTDATA " ;
default :
return " (?) " ;
}
}
static const char * object_section_header_type_to_string ( Elf32_Word type )
{
switch ( type ) {
case SHT_NULL :
return " NULL " ;
case SHT_PROGBITS :
return " PROGBITS " ;
case SHT_SYMTAB :
return " SYMTAB " ;
case SHT_STRTAB :
return " STRTAB " ;
case SHT_RELA :
return " RELA " ;
case SHT_HASH :
return " HASH " ;
case SHT_DYNAMIC :
return " DYNAMIC " ;
case SHT_NOTE :
return " NOTE " ;
case SHT_NOBITS :
return " NOBITS " ;
case SHT_REL :
return " REL " ;
case SHT_SHLIB :
return " SHLIB " ;
case SHT_DYNSYM :
return " DYNSYM " ;
case SHT_NUM :
return " NUM " ;
case SHT_INIT_ARRAY :
return " INIT_ARRAY " ;
case SHT_FINI_ARRAY :
return " FINI_ARRAY " ;
case SHT_PREINIT_ARRAY :
return " PREINIT_ARRAY " ;
case SHT_GROUP :
return " GROUP " ;
case SHT_SYMTAB_SHNDX :
return " SYMTAB_SHNDX " ;
case SHT_LOOS :
return " SOOS " ;
case SHT_SUNW_dof :
return " SUNW_dof " ;
case SHT_GNU_LIBLIST :
return " GNU_LIBLIST " ;
case SHT_SUNW_move :
return " SUNW_move " ;
case SHT_SUNW_syminfo :
return " SUNW_syminfo " ;
case SHT_SUNW_verdef :
return " SUNW_verdef " ;
case SHT_SUNW_verneed :
return " SUNW_verneed " ;
case SHT_SUNW_versym : // or SHT_HIOS
return " SUNW_versym " ;
case SHT_LOPROC :
return " LOPROC " ;
case SHT_HIPROC :
return " HIPROC " ;
case SHT_LOUSER :
return " LOUSER " ;
case SHT_HIUSER :
return " HIUSER " ;
case SHT_GNU_HASH :
return " GNU_HASH " ;
default :
return " (?) " ;
}
}
static const char * object_symbol_type_to_string ( Elf32_Word type )
{
switch ( type ) {
case STT_NOTYPE :
return " NOTYPE " ;
case STT_OBJECT :
return " OBJECT " ;
case STT_FUNC :
return " FUNC " ;
case STT_SECTION :
return " SECTION " ;
case STT_FILE :
return " FILE " ;
case STT_TLS :
return " TLS " ;
case STT_LOPROC :
return " LOPROC " ;
case STT_HIPROC :
return " HIPROC " ;
default :
return " (?) " ;
}
}
static const char * object_symbol_binding_to_string ( Elf32_Word type )
{
switch ( type ) {
case STB_LOCAL :
return " LOCAL " ;
case STB_GLOBAL :
return " GLOBAL " ;
case STB_WEAK :
return " WEAK " ;
case STB_NUM :
return " NUM " ;
case STB_LOPROC :
return " LOPROC " ;
case STB_HIPROC :
return " HIPROC " ;
default :
return " (?) " ;
}
}
2021-03-14 13:58:44 +03:00
static const char * object_relocation_type_to_string ( Elf32_Word type )
{
switch ( type ) {
case R_386_NONE :
return " R_386_NONE " ;
case R_386_32 :
return " R_386_32 " ;
case R_386_PC32 :
return " R_386_PC32 " ;
case R_386_GOT32 :
return " R_386_GOT32 " ;
case R_386_PLT32 :
return " R_386_PLT32 " ;
case R_386_COPY :
return " R_386_COPY " ;
case R_386_GLOB_DAT :
return " R_386_GLOB_DAT " ;
case R_386_JMP_SLOT :
return " R_386_JMP_SLOT " ;
case R_386_RELATIVE :
return " R_386_RELATIVE " ;
case R_386_TLS_TPOFF :
return " R_386_TLS_TPOFF " ;
case R_386_TLS_TPOFF32 :
return " R_386_TLS_TPOFF32 " ;
default :
return " (?) " ;
}
}
2021-03-22 08:58:28 +03:00
static const char * object_tag_to_string ( Elf32_Sword dt_tag )
{
switch ( dt_tag ) {
case DT_NULL :
return " NULL " ; /* marks end of _DYNAMIC array */
case DT_NEEDED :
return " NEEDED " ; /* string table offset of needed lib */
case DT_PLTRELSZ :
return " PLTRELSZ " ; /* size of relocation entries in PLT */
case DT_PLTGOT :
return " PLTGOT " ; /* address PLT/GOT */
case DT_HASH :
return " HASH " ; /* address of symbol hash table */
case DT_STRTAB :
return " STRTAB " ; /* address of string table */
case DT_SYMTAB :
return " SYMTAB " ; /* address of symbol table */
case DT_RELA :
return " RELA " ; /* address of relocation table */
case DT_RELASZ :
return " RELASZ " ; /* size of relocation table */
case DT_RELAENT :
return " RELAENT " ; /* size of relocation entry */
case DT_STRSZ :
return " STRSZ " ; /* size of string table */
case DT_SYMENT :
return " SYMENT " ; /* size of symbol table entry */
case DT_INIT :
return " INIT " ; /* address of initialization func. */
case DT_FINI :
return " FINI " ; /* address of termination function */
case DT_SONAME :
return " SONAME " ; /* string table offset of shared obj */
case DT_RPATH :
return " RPATH " ; /* string table offset of library search path */
case DT_SYMBOLIC :
return " SYMBOLIC " ; /* start sym search in shared obj. */
case DT_REL :
return " REL " ; /* address of rel. tbl. w addends */
case DT_RELSZ :
return " RELSZ " ; /* size of DT_REL relocation table */
case DT_RELENT :
return " RELENT " ; /* size of DT_REL relocation entry */
case DT_PLTREL :
return " PLTREL " ; /* PLT referenced relocation entry */
case DT_DEBUG :
return " DEBUG " ; /* bugger */
case DT_TEXTREL :
return " TEXTREL " ; /* Allow rel. mod. to unwritable seg */
case DT_JMPREL :
return " JMPREL " ; /* add. of PLT's relocation entries */
case DT_BIND_NOW :
return " BIND_NOW " ; /* Bind now regardless of env setting */
case DT_INIT_ARRAY :
return " INIT_ARRAY " ; /* address of array of init func */
case DT_FINI_ARRAY :
return " FINI_ARRAY " ; /* address of array of term func */
case DT_INIT_ARRAYSZ :
return " INIT_ARRAYSZ " ; /* size of array of init func */
case DT_FINI_ARRAYSZ :
return " FINI_ARRAYSZ " ; /* size of array of term func */
case DT_RUNPATH :
return " RUNPATH " ; /* strtab offset of lib search path */
case DT_FLAGS :
return " FLAGS " ; /* Set of DF_* flags */
case DT_ENCODING :
return " ENCODING " ; /* further DT_* follow encoding rules */
case DT_PREINIT_ARRAY :
return " PREINIT_ARRAY " ; /* address of array of preinit func */
case DT_PREINIT_ARRAYSZ :
return " PREINIT_ARRAYSZ " ; /* size of array of preinit func */
case DT_LOOS :
return " LOOS " ; /* reserved range for OS */
case DT_HIOS :
return " HIOS " ; /* specific dynamic array tags */
case DT_LOPROC :
return " LOPROC " ; /* reserved range for processor */
case DT_HIPROC :
return " HIPROC " ; /* specific dynamic array tags */
case DT_GNU_HASH :
return " GNU_HASH " ; /* address of GNU hash table */
case DT_RELACOUNT :
return " RELACOUNT " ; /* if present, number of RELATIVE */
case DT_RELCOUNT :
return " RELCOUNT " ; /* relocs, which must come first */
case DT_FLAGS_1 :
return " FLAGS_1 " ;
default :
return " ?? " ;
}
}
2020-12-29 11:04:29 +03:00
int main ( int argc , char * * argv )
{
if ( pledge ( " stdio rpath " , nullptr ) < 0 ) {
perror ( " pledge " ) ;
return 1 ;
}
const char * path ;
static bool display_all = false ;
static bool display_elf_header = false ;
static bool display_program_headers = false ;
static bool display_section_headers = false ;
static bool display_headers = false ;
static bool display_symbol_table = false ;
static bool display_dynamic_symbol_table = false ;
static bool display_core_notes = false ;
static bool display_relocations = false ;
static bool display_unwind_info = false ;
static bool display_dynamic_section = false ;
2021-03-19 08:52:16 +03:00
static bool display_hardening = false ;
2020-12-29 11:04:29 +03:00
Core : : ArgsParser args_parser ;
args_parser . add_option ( display_all , " Display all " , " all " , ' a ' ) ;
args_parser . add_option ( display_elf_header , " Display ELF header " , " file-header " , ' h ' ) ;
args_parser . add_option ( display_program_headers , " Display program headers " , " program-headers " , ' l ' ) ;
args_parser . add_option ( display_section_headers , " Display section headers " , " section-headers " , ' S ' ) ;
2021-03-19 08:52:16 +03:00
args_parser . add_option ( display_headers , " Equivalent to: -h -l -S -s -r -d -n -u -c " , " headers " , ' e ' ) ;
2020-12-29 11:04:29 +03:00
args_parser . add_option ( display_symbol_table , " Display the symbol table " , " syms " , ' s ' ) ;
2021-03-22 08:58:28 +03:00
args_parser . add_option ( display_dynamic_symbol_table , " Display the dynamic symbol table " , " dyn-syms " , ' \0 ' ) ;
2021-03-14 13:58:44 +03:00
args_parser . add_option ( display_dynamic_section , " Display the dynamic section " , " dynamic " , ' d ' ) ;
args_parser . add_option ( display_core_notes , " Display core notes " , " notes " , ' n ' ) ;
args_parser . add_option ( display_relocations , " Display relocations " , " relocs " , ' r ' ) ;
args_parser . add_option ( display_unwind_info , " Display unwind info " , " unwind " , ' u ' ) ;
2021-03-19 08:52:16 +03:00
args_parser . add_option ( display_hardening , " Display security hardening info " , " checksec " , ' c ' ) ;
2020-12-29 11:04:29 +03:00
args_parser . add_positional_argument ( path , " ELF path " , " path " ) ;
args_parser . parse ( argc , argv ) ;
if ( argc < 3 ) {
args_parser . print_usage ( stderr , argv [ 0 ] ) ;
return - 1 ;
}
if ( display_headers ) {
display_elf_header = true ;
display_program_headers = true ;
display_section_headers = true ;
}
if ( display_all ) {
display_elf_header = true ;
display_program_headers = true ;
display_section_headers = true ;
2021-03-14 13:58:44 +03:00
display_core_notes = true ;
display_relocations = true ;
display_unwind_info = true ;
2020-12-29 11:04:29 +03:00
display_symbol_table = true ;
2021-03-19 08:52:16 +03:00
display_hardening = true ;
2020-12-29 11:04:29 +03:00
}
2021-01-10 17:55:54 +03:00
auto file_or_error = MappedFile : : map ( path ) ;
2020-12-29 11:04:29 +03:00
2021-01-10 17:55:54 +03:00
if ( file_or_error . is_error ( ) ) {
warnln ( " Unable to map file {}: {} " , path , file_or_error . error ( ) ) ;
2020-12-29 11:04:29 +03:00
return - 1 ;
}
2021-01-10 17:55:54 +03:00
auto elf_image_data = file_or_error . value ( ) - > bytes ( ) ;
2021-03-22 08:58:28 +03:00
ELF : : Image elf_image ( elf_image_data ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
if ( ! elf_image . is_valid ( ) ) {
2021-05-31 17:43:25 +03:00
warnln ( " File is not a valid ELF object " ) ;
2020-12-29 11:04:29 +03:00
return - 1 ;
}
String interpreter_path ;
2021-01-10 17:55:54 +03:00
if ( ! ELF : : validate_program_headers ( * ( const Elf32_Ehdr * ) elf_image_data . data ( ) , elf_image_data . size ( ) , ( const u8 * ) elf_image_data . data ( ) , elf_image_data . size ( ) , & interpreter_path ) ) {
2021-05-31 17:43:25 +03:00
warnln ( " Invalid ELF headers " ) ;
2020-12-29 11:04:29 +03:00
return - 1 ;
}
2021-03-22 08:58:28 +03:00
auto & header = * reinterpret_cast < const Elf32_Ehdr * > ( elf_image_data . data ( ) ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
RefPtr < ELF : : DynamicObject > object = nullptr ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
if ( interpreter_path . is_null ( ) ) {
interpreter_path = " /usr/lib/Loader.so " ;
2021-05-31 17:43:25 +03:00
warnln ( " Warning: Dynamic ELF object has no interpreter path. Using: {} " , interpreter_path ) ;
2021-03-22 08:58:28 +03:00
}
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
auto interpreter_file_or_error = MappedFile : : map ( interpreter_path ) ;
if ( interpreter_file_or_error . is_error ( ) ) {
warnln ( " Unable to map interpreter file {}: {} " , interpreter_path , interpreter_file_or_error . error ( ) ) ;
return - 1 ;
}
auto interpreter_image_data = interpreter_file_or_error . value ( ) - > bytes ( ) ;
ELF : : Image interpreter_image ( interpreter_image_data ) ;
if ( ! interpreter_image . is_valid ( ) ) {
2021-05-31 17:43:25 +03:00
warnln ( " ELF interpreter image is invalid " ) ;
2021-03-22 08:58:28 +03:00
return - 1 ;
}
int fd = open ( path , O_RDONLY ) ;
if ( fd < 0 ) {
2021-04-24 21:39:58 +03:00
outln ( " Unable to open file {} " , path ) ;
2021-03-22 08:58:28 +03:00
return 1 ;
}
2021-04-24 21:39:58 +03:00
auto result = ELF : : DynamicLoader : : try_create ( fd , path ) ;
if ( result . is_error ( ) ) {
outln ( " {} " , result . error ( ) . text ) ;
return 1 ;
}
auto & loader = result . value ( ) ;
if ( ! loader - > is_valid ( ) ) {
outln ( " {} is not a valid ELF dynamic shared object! " , path ) ;
2021-03-22 08:58:28 +03:00
return 1 ;
}
object = loader - > map ( ) ;
if ( ! object ) {
2021-04-24 21:39:58 +03:00
outln ( " Failed to map dynamic ELF object {} " , path ) ;
2021-03-22 08:58:28 +03:00
return 1 ;
}
}
2020-12-29 11:04:29 +03:00
if ( display_elf_header ) {
2021-05-31 17:43:25 +03:00
outln ( " ELF header: " ) ;
2020-12-29 11:04:29 +03:00
2021-05-31 17:43:25 +03:00
out ( " Magic: " ) ;
2021-04-21 23:53:05 +03:00
for ( char i : StringView { header . e_ident , sizeof ( header . e_ident ) } ) {
2021-03-22 08:58:28 +03:00
if ( isprint ( i ) ) {
2021-05-31 17:43:25 +03:00
out ( " {:c} " , i ) ;
2020-12-29 11:04:29 +03:00
} else {
2021-05-31 17:43:25 +03:00
out ( " {:02x} " , i ) ;
2020-12-29 11:04:29 +03:00
}
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
outln ( " Type: {} ({}) " , header . e_type , object_file_type_to_string ( header . e_type ) ) ;
outln ( " Machine: {} ({}) " , header . e_machine , object_machine_type_to_string ( header . e_machine ) ) ;
outln ( " Version: {:#x} " , header . e_version ) ;
outln ( " Entry point address: {:#x} " , header . e_entry ) ;
outln ( " Start of program headers: {} (bytes into file) " , header . e_phoff ) ;
outln ( " Start of section headers: {} (bytes into file) " , header . e_shoff ) ;
outln ( " Flags: {:#x} " , header . e_flags ) ;
outln ( " Size of this header: {} (bytes) " , header . e_ehsize ) ;
outln ( " Size of program headers: {} (bytes) " , header . e_phentsize ) ;
outln ( " Number of program headers: {} " , header . e_phnum ) ;
outln ( " Size of section headers: {} (bytes) " , header . e_shentsize ) ;
outln ( " Number of section headers: {} " , header . e_shnum ) ;
outln ( " Section header string table index: {} " , header . e_shstrndx ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_section_headers ) {
if ( ! display_all ) {
2021-05-31 17:43:25 +03:00
outln ( " There are {} section headers, starting at offset {:#x}: " , header . e_shnum , header . e_shoff ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-03-22 08:58:28 +03:00
if ( ! elf_image . section_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " There are no sections in this file. " ) ;
2020-12-29 11:04:29 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Section Headers: " ) ;
outln ( " Name Type Address Offset Size Flags " ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
elf_image . for_each_section ( [ ] ( const ELF : : Image : : Section & section ) {
2021-05-31 17:43:25 +03:00
out ( " {:19} " , section . name ( ) ) ;
out ( " {:15} " , object_section_header_type_to_string ( section . type ( ) ) ) ;
out ( " {:08x} " , section . address ( ) ) ;
out ( " {:08x} " , section . offset ( ) ) ;
out ( " {:08x} " , section . size ( ) ) ;
out ( " {} " , section . flags ( ) ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
} ) ;
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_program_headers ) {
if ( ! display_all ) {
2021-05-31 17:43:25 +03:00
outln ( " ELF file type is {} ({}) " , header . e_type , object_file_type_to_string ( header . e_type ) ) ;
outln ( " Entry point {:#x} \n " , header . e_entry ) ;
outln ( " There are {} program headers, starting at offset {} " , header . e_phnum , header . e_phoff ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-03-29 15:14:41 +03:00
if ( ! elf_image . program_header_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " There are no program headers in this file. " ) ;
2021-03-29 15:14:41 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Program Headers: " ) ;
outln ( " Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align " ) ;
2021-03-29 15:14:41 +03:00
elf_image . for_each_program_header ( [ ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-05-31 17:43:25 +03:00
out ( " " ) ;
out ( " {:14} " , object_program_header_type_to_string ( program_header . type ( ) ) ) ;
out ( " {:#08x} " , program_header . offset ( ) ) ;
out ( " {:p} " , program_header . vaddr ( ) . as_ptr ( ) ) ;
out ( " {:p} " , program_header . vaddr ( ) . as_ptr ( ) ) ; // FIXME: assumes PhysAddr = VirtAddr
out ( " {:#08x} " , program_header . size_in_image ( ) ) ;
out ( " {:#08x} " , program_header . size_in_memory ( ) ) ;
out ( " {:04x} " , program_header . flags ( ) ) ;
out ( " {:#08x} " , program_header . alignment ( ) ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
2021-03-29 15:14:41 +03:00
if ( program_header . type ( ) = = PT_INTERP )
2021-05-31 17:43:25 +03:00
outln ( " [Interpreter: {}] " , program_header . raw_data ( ) ) ;
2021-03-29 15:14:41 +03:00
} ) ;
}
2021-03-14 13:58:44 +03:00
// TODO: Display section to segment mapping
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_dynamic_section ) {
2021-03-14 13:58:44 +03:00
auto found_dynamic_section = false ;
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
elf_image . for_each_section ( [ & found_dynamic_section ] ( const ELF : : Image : : Section & section ) {
if ( section . name ( ) ! = ELF_DYNAMIC )
return IterationDecision : : Continue ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
found_dynamic_section = true ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( section . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Dynamic section '{}' at offset {:#08x} contains {} entries. " , section . name ( ) . to_string ( ) , section . offset ( ) , section . entry_count ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Dynamic section '{}' at offset {:#08x} contains zero entries. " , section . name ( ) . to_string ( ) , section . offset ( ) ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
return IterationDecision : : Break ;
} ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
Vector < String > libraries ;
object - > for_each_needed_library ( [ & libraries ] ( StringView entry ) {
2021-05-31 17:43:25 +03:00
libraries . append ( String : : formatted ( " {} " , entry ) ) ;
2021-03-22 08:58:28 +03:00
} ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
auto library_index = 0 ;
2021-05-31 17:43:25 +03:00
outln ( " Tag Type Name / Value " ) ;
2021-03-22 08:58:28 +03:00
object - > for_each_dynamic_entry ( [ & library_index , & libraries , & object ] ( const ELF : : DynamicObject : : DynamicEntry & entry ) {
2021-05-31 17:43:25 +03:00
out ( " {:#08x} " , entry . tag ( ) ) ;
out ( " {:17} " , object_tag_to_string ( entry . tag ( ) ) ) ;
2021-03-22 08:58:28 +03:00
if ( entry . tag ( ) = = DT_NEEDED ) {
2021-05-31 17:43:25 +03:00
outln ( " Shared library: {} " , libraries [ library_index ] ) ;
2021-03-22 08:58:28 +03:00
library_index + + ;
} else if ( entry . tag ( ) = = DT_RPATH ) {
2021-05-31 17:43:25 +03:00
outln ( " Library rpath: {} " , object - > rpath ( ) ) ;
2021-03-22 08:58:28 +03:00
} else if ( entry . tag ( ) = = DT_RUNPATH ) {
2021-05-31 17:43:25 +03:00
outln ( " Library runpath: {} " , object - > runpath ( ) ) ;
2021-03-22 08:58:28 +03:00
} else if ( entry . tag ( ) = = DT_SONAME ) {
2021-05-31 17:43:25 +03:00
outln ( " Library soname: {} " , object - > soname ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " {:#08x} " , entry . val ( ) ) ;
2021-03-22 08:58:28 +03:00
}
} ) ;
}
2021-03-14 13:58:44 +03:00
if ( ! found_dynamic_section )
2021-05-31 17:43:25 +03:00
outln ( " No dynamic section in this file. " ) ;
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_relocations ) {
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
if ( ! object - > relocation_section ( ) . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains zero entries: " , object - > relocation_section ( ) . name ( ) , object - > relocation_section ( ) . offset ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains {} entries: " , object - > relocation_section ( ) . name ( ) , object - > relocation_section ( ) . offset ( ) , object - > relocation_section ( ) . entry_count ( ) ) ;
outln ( " Offset Type Sym Value Sym Name " ) ;
2021-03-22 08:58:28 +03:00
object - > relocation_section ( ) . for_each_relocation ( [ ] ( const ELF : : DynamicObject : : Relocation & reloc ) {
2021-05-31 17:43:25 +03:00
out ( " {:#08x} " , reloc . offset ( ) ) ;
out ( " {:17} " , object_relocation_type_to_string ( reloc . type ( ) ) ) ;
out ( " {:#08x} " , reloc . symbol ( ) . value ( ) ) ;
out ( " {} " , reloc . symbol ( ) . name ( ) ) ;
outln ( ) ;
2021-03-22 08:58:28 +03:00
} ) ;
2021-03-14 13:58:44 +03:00
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( ! object - > plt_relocation_section ( ) . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains zero entries: " , object - > plt_relocation_section ( ) . name ( ) , object - > plt_relocation_section ( ) . offset ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains {} entries: " , object - > plt_relocation_section ( ) . name ( ) , object - > plt_relocation_section ( ) . offset ( ) , object - > plt_relocation_section ( ) . entry_count ( ) ) ;
outln ( " Offset Type Sym Value Sym Name " ) ;
2021-03-22 08:58:28 +03:00
object - > plt_relocation_section ( ) . for_each_relocation ( [ ] ( const ELF : : DynamicObject : : Relocation & reloc ) {
2021-05-31 17:43:25 +03:00
out ( " {:#08x} " , reloc . offset ( ) ) ;
out ( " {:17} " , object_relocation_type_to_string ( reloc . type ( ) ) ) ;
out ( " {:#08x} " , reloc . symbol ( ) . value ( ) ) ;
out ( " {} " , reloc . symbol ( ) . name ( ) ) ;
outln ( ) ;
2021-03-22 08:58:28 +03:00
} ) ;
}
} else {
2021-05-31 17:43:25 +03:00
outln ( " No relocations in this file. " ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_unwind_info ) {
// TODO: Unwind info
2021-05-31 17:43:25 +03:00
outln ( " Decoding of unwind sections for machine type {} is not supported. " , object_machine_type_to_string ( header . e_machine ) ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_core_notes ) {
2021-03-14 13:58:44 +03:00
auto found_notes = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_program_header ( [ & found_notes ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-03-14 13:58:44 +03:00
if ( program_header . type ( ) ! = PT_NOTE )
2021-05-16 12:36:52 +03:00
return ;
2021-03-14 13:58:44 +03:00
found_notes = true ;
2021-05-31 17:43:25 +03:00
outln ( " Displaying notes section '{}' at offset {:#08x} of length {:#08x}: " , object_program_header_type_to_string ( program_header . type ( ) ) , program_header . offset ( ) , program_header . size_in_image ( ) ) ;
2021-03-14 13:58:44 +03:00
// FIXME: Parse CORE notes. Notes are in JSON format on SerenityOS, but vary between systems.
2021-05-31 17:43:25 +03:00
outln ( " {} " , program_header . raw_data ( ) ) ;
2021-03-14 13:58:44 +03:00
} ) ;
if ( ! found_notes )
2021-05-31 17:43:25 +03:00
outln ( " No core notes in this file. " ) ;
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_dynamic_symbol_table | | display_symbol_table ) {
2021-03-14 13:58:44 +03:00
auto found_dynamic_symbol_table = false ;
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
elf_image . for_each_section ( [ & found_dynamic_symbol_table ] ( const ELF : : Image : : Section & section ) {
if ( section . name ( ) ! = ELF_DYNSYM )
return IterationDecision : : Continue ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
found_dynamic_symbol_table = true ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( ! section . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains zero entries. " , ELF_DYNSYM ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains {} entries. " , ELF_DYNSYM , section . entry_count ( ) ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
return IterationDecision : : Break ;
} ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( object - > symbol_count ( ) ) {
// FIXME: Add support for init/fini/start/main sections
2021-05-31 17:43:25 +03:00
outln ( " Num: Value Size Type Bind Name " ) ;
2021-03-22 08:58:28 +03:00
object - > for_each_symbol ( [ ] ( const ELF : : DynamicObject : : Symbol & sym ) {
2021-05-31 17:43:25 +03:00
out ( " {:>4}: " , sym . index ( ) ) ;
out ( " {:08x} " , sym . value ( ) ) ;
out ( " {:08x} " , sym . size ( ) ) ;
out ( " {:8} " , object_symbol_type_to_string ( sym . type ( ) ) ) ;
out ( " {:8} " , object_symbol_binding_to_string ( sym . bind ( ) ) ) ;
out ( " {} " , sym . name ( ) ) ;
outln ( ) ;
2021-03-22 08:58:28 +03:00
} ) ;
}
}
2021-03-14 13:58:44 +03:00
if ( ! found_dynamic_symbol_table )
2021-05-31 17:43:25 +03:00
outln ( " No dynamic symbol information for this file. " ) ;
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_symbol_table ) {
2021-03-22 08:58:28 +03:00
if ( elf_image . symbol_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains {} entries: " , ELF_SYMTAB , elf_image . symbol_count ( ) ) ;
outln ( " Num: Value Size Type Bind Name " ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
elf_image . for_each_symbol ( [ ] ( const ELF : : Image : : Symbol & sym ) {
2021-05-31 17:43:25 +03:00
out ( " {:>4}: " , sym . index ( ) ) ;
out ( " {:08x} " , sym . value ( ) ) ;
out ( " {:08x} " , sym . size ( ) ) ;
out ( " {:8} " , object_symbol_type_to_string ( sym . type ( ) ) ) ;
out ( " {:8} " , object_symbol_binding_to_string ( sym . bind ( ) ) ) ;
out ( " {} " , sym . name ( ) ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
} ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains zero entries. " , ELF_SYMTAB ) ;
2020-12-29 11:04:29 +03:00
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-03-19 08:52:16 +03:00
if ( display_hardening ) {
2021-05-31 17:43:25 +03:00
outln ( " Security Hardening: " ) ;
outln ( " RELRO Stack Canary NX PIE RPATH RUNPATH Symbols " ) ;
2021-03-19 08:52:16 +03:00
bool relro = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_program_header ( [ & relro ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-03-19 08:52:16 +03:00
if ( program_header . type ( ) = = PT_GNU_RELRO ) {
relro = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
2021-03-22 08:58:28 +03:00
bool full_relro = false ;
if ( relro ) {
object - > for_each_dynamic_entry ( [ & full_relro ] ( const ELF : : DynamicObject : : DynamicEntry & entry ) {
if ( entry . tag ( ) = = DT_BIND_NOW ) {
full_relro = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
if ( full_relro )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:13} \033 [0m " , " Full RELRO " ) ;
2021-03-22 08:58:28 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;33m{:13} \033 [0m " , " Partial RELRO " ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:13} \033 [0m " , " No RELRO " ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-19 08:52:16 +03:00
bool canary = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_symbol ( [ & canary ] ( const ELF : : Image : : Symbol & sym ) {
2021-03-19 08:52:16 +03:00
if ( sym . name ( ) = = " __stack_chk_fail " | | sym . name ( ) = = " __intel_security_cookie " ) {
canary = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
if ( canary )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " Canary found " ) ;
2021-03-19 08:52:16 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , " No canary " ) ;
2021-03-19 08:52:16 +03:00
bool nx = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_program_header ( [ & nx ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-03-19 08:52:16 +03:00
if ( program_header . type ( ) = = PT_GNU_STACK ) {
if ( program_header . flags ( ) & PF_X )
nx = false ;
else
nx = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
if ( nx )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " NX enabled " ) ;
2021-03-19 08:52:16 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , " NX disabled " ) ;
2021-03-19 08:52:16 +03:00
bool pie = false ;
if ( header . e_type = = ET_REL | | header . e_type = = ET_DYN )
pie = true ;
if ( pie )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " PIE enabled " ) ;
2021-03-22 08:58:28 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , " No PIE " ) ;
2021-03-22 08:58:28 +03:00
StringView rpath ;
if ( elf_image . is_dynamic ( ) )
rpath = object - > rpath ( ) ;
if ( rpath . is_empty ( ) )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " No RPATH " ) ;
2021-03-22 08:58:28 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , rpath ) ;
2021-03-22 08:58:28 +03:00
StringView runpath ;
if ( elf_image . is_dynamic ( ) )
runpath = object - > runpath ( ) ;
if ( runpath . is_empty ( ) )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " No RUNPATH " ) ;
2021-03-19 08:52:16 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , runpath ) ;
2021-03-19 08:52:16 +03:00
2021-05-31 17:43:25 +03:00
out ( " {} symbols " , elf_image . symbol_count ( ) ) ;
outln ( ) ;
2021-03-19 08:52:16 +03:00
}
2020-12-29 11:04:29 +03:00
return 0 ;
}