123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- /*
- * Copyright (c) 2020, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/MappedFile.h>
- #include <AK/String.h>
- #include <AK/StringBuilder.h>
- #include <AK/StringView.h>
- #include <LibCore/ArgsParser.h>
- #include <LibCore/File.h>
- #include <LibELF/DynamicLoader.h>
- #include <LibELF/DynamicObject.h>
- #include <LibELF/Image.h>
- #include <LibELF/Validation.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <unistd.h>
- static const char* object_file_type_to_string(ElfW(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(ElfW(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";
- case EM_X86_64:
- return "Advanced Micro Devices X86-64";
- default:
- return "(?)";
- }
- }
- static const char* object_program_header_type_to_string(ElfW(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(ElfW(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(ElfW(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(ElfW(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 "(?)";
- }
- }
- static const char* object_relocation_type_to_string(ElfW(Word) type)
- {
- switch (type) {
- #if ARCH(I386)
- 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";
- #else
- case R_X86_64_NONE:
- return "R_X86_64_NONE";
- case R_X86_64_64:
- return "R_X86_64";
- case R_X86_64_GLOB_DAT:
- return "R_x86_64_GLOB_DAT";
- case R_X86_64_JUMP_SLOT:
- return "R_X86_64_JUMP_SLOT";
- case R_X86_64_RELATIVE:
- return "R_X86_64_RELATIVE";
- case R_X86_64_TPOFF64:
- return "R_X86_64_TPOFF64";
- #endif
- default:
- return "(?)";
- }
- }
- 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;
- static bool display_hardening = false;
- 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');
- args_parser.add_option(display_headers, "Equivalent to: -h -l -S -s -r -d -n -u -c", "headers", 'e');
- args_parser.add_option(display_symbol_table, "Display the symbol table", "syms", 's');
- args_parser.add_option(display_dynamic_symbol_table, "Display the dynamic symbol table", "dyn-syms", '\0');
- 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');
- args_parser.add_option(display_hardening, "Display security hardening info", "checksec", 'c');
- 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;
- display_dynamic_symbol_table = true;
- display_dynamic_section = true;
- display_core_notes = true;
- display_relocations = true;
- display_unwind_info = true;
- display_symbol_table = true;
- display_hardening = true;
- }
- auto file_or_error = MappedFile::map(path);
- if (file_or_error.is_error()) {
- warnln("Unable to map file {}: {}", path, file_or_error.error());
- return -1;
- }
- auto elf_image_data = file_or_error.value()->bytes();
- ELF::Image elf_image(elf_image_data);
- if (!elf_image.is_valid()) {
- warnln("File is not a valid ELF object");
- return -1;
- }
- String interpreter_path;
- if (!ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) {
- warnln("Invalid ELF headers");
- return -1;
- }
- auto& header = *reinterpret_cast<const ElfW(Ehdr)*>(elf_image_data.data());
- RefPtr<ELF::DynamicObject> object = nullptr;
- if (elf_image.is_dynamic()) {
- if (interpreter_path.is_null()) {
- interpreter_path = "/usr/lib/Loader.so";
- warnln("Warning: Dynamic ELF object has no interpreter path. Using: {}", interpreter_path);
- }
- 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()) {
- warnln("ELF interpreter image is invalid");
- return -1;
- }
- int fd = open(path, O_RDONLY);
- if (fd < 0) {
- outln("Unable to open file {}", path);
- return 1;
- }
- 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);
- return 1;
- }
- object = loader->map();
- if (!object) {
- outln("Failed to map dynamic ELF object {}", path);
- return 1;
- }
- }
- if (display_elf_header) {
- outln("ELF header:");
- out(" Magic: ");
- for (char i : StringView { header.e_ident, sizeof(header.e_ident) }) {
- if (isprint(i)) {
- out("{:c} ", i);
- } else {
- out("{:02x} ", i);
- }
- }
- 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();
- }
- #if ARCH(I386)
- auto addr_padding = "";
- #else
- auto addr_padding = " ";
- #endif
- if (display_section_headers) {
- if (!display_all) {
- outln("There are {} section headers, starting at offset {:#x}:", header.e_shnum, header.e_shoff);
- outln();
- }
- if (!elf_image.section_count()) {
- outln("There are no sections in this file.");
- } else {
- outln("Section Headers:");
- outln(" Name Type Address{} Offset{} Size{} Flags", addr_padding, addr_padding, addr_padding);
- elf_image.for_each_section([](const ELF::Image::Section& section) {
- out(" {:19} ", section.name());
- out("{:15} ", object_section_header_type_to_string(section.type()));
- out("{:p} ", section.address());
- out("{:p} ", section.offset());
- out("{:p} ", section.size());
- out("{}", section.flags());
- outln();
- });
- }
- outln();
- }
- if (display_program_headers) {
- if (!display_all) {
- 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();
- }
- if (!elf_image.program_header_count()) {
- outln("There are no program headers in this file.");
- } else {
- outln("Program Headers:");
- outln(" Type Offset{} VirtAddr{} PhysAddr{} FileSiz{} MemSiz{} Flg Align",
- addr_padding, addr_padding, addr_padding, addr_padding, addr_padding);
- elf_image.for_each_program_header([](const ELF::Image::ProgramHeader& program_header) {
- out(" ");
- out("{:14} ", object_program_header_type_to_string(program_header.type()));
- out("{:p} ", program_header.offset());
- out("{:p} ", program_header.vaddr().as_ptr());
- out("{:p} ", program_header.vaddr().as_ptr()); // FIXME: assumes PhysAddr = VirtAddr
- out("{:p} ", program_header.size_in_image());
- out("{:p} ", program_header.size_in_memory());
- out("{:04x} ", program_header.flags());
- out("{:p}", program_header.alignment());
- outln();
- if (program_header.type() == PT_INTERP)
- outln(" [Interpreter: {}]", program_header.raw_data());
- });
- }
- // TODO: Display section to segment mapping
- outln();
- }
- if (display_dynamic_section) {
- auto found_dynamic_section = false;
- 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;
- found_dynamic_section = true;
- if (section.entry_count()) {
- outln("Dynamic section '{}' at offset {:#08x} contains {} entries.", section.name().to_string(), section.offset(), section.entry_count());
- } else {
- outln("Dynamic section '{}' at offset {:#08x} contains zero entries.", section.name().to_string(), section.offset());
- }
- return IterationDecision::Break;
- });
- Vector<String> libraries;
- object->for_each_needed_library([&libraries](StringView entry) {
- libraries.append(String::formatted("{}", entry));
- });
- auto library_index = 0;
- outln(" Tag Type Name / Value");
- object->for_each_dynamic_entry([&library_index, &libraries, &object](const ELF::DynamicObject::DynamicEntry& entry) {
- out(" {:#08x} ", entry.tag());
- out("{:17} ", ELF::DynamicObject::name_for_dtag(entry.tag()));
- if (entry.tag() == DT_NEEDED) {
- outln("Shared library: {}", libraries[library_index]);
- library_index++;
- } else if (entry.tag() == DT_RPATH) {
- outln("Library rpath: {}", object->rpath());
- } else if (entry.tag() == DT_RUNPATH) {
- outln("Library runpath: {}", object->runpath());
- } else if (entry.tag() == DT_SONAME) {
- outln("Library soname: {}", object->soname());
- } else {
- outln("{:#08x}", entry.val());
- }
- });
- }
- if (!found_dynamic_section)
- outln("No dynamic section in this file.");
- outln();
- }
- if (display_relocations) {
- if (elf_image.is_dynamic()) {
- if (!object->relocation_section().entry_count()) {
- outln("Relocation section '{}' at offset {:#08x} contains zero entries:", object->relocation_section().name(), object->relocation_section().offset());
- } else {
- 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", addr_padding, addr_padding);
- object->relocation_section().for_each_relocation([](const ELF::DynamicObject::Relocation& reloc) {
- out(" {:p} ", reloc.offset());
- out(" {:18} ", object_relocation_type_to_string(reloc.type()));
- out(" {:p} ", reloc.symbol().value());
- out(" {}", reloc.symbol().name());
- outln();
- });
- }
- outln();
- if (!object->plt_relocation_section().entry_count()) {
- outln("Relocation section '{}' at offset {:#08x} contains zero entries:", object->plt_relocation_section().name(), object->plt_relocation_section().offset());
- } else {
- 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", addr_padding, addr_padding);
- object->plt_relocation_section().for_each_relocation([](const ELF::DynamicObject::Relocation& reloc) {
- out(" {:p} ", reloc.offset());
- out(" {:18} ", object_relocation_type_to_string(reloc.type()));
- out(" {:p} ", reloc.symbol().value());
- out(" {}", reloc.symbol().name());
- outln();
- });
- }
- } else {
- outln("No relocations in this file.");
- }
- outln();
- }
- if (display_unwind_info) {
- // TODO: Unwind info
- outln("Decoding of unwind sections for machine type {} is not supported.", object_machine_type_to_string(header.e_machine));
- outln();
- }
- if (display_core_notes) {
- auto found_notes = false;
- elf_image.for_each_program_header([&found_notes](const ELF::Image::ProgramHeader& program_header) {
- if (program_header.type() != PT_NOTE)
- return;
- found_notes = true;
- 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());
- // FIXME: Parse CORE notes. Notes are in JSON format on SerenityOS, but vary between systems.
- outln("{}", program_header.raw_data());
- });
- if (!found_notes)
- outln("No core notes in this file.");
- outln();
- }
- if (display_dynamic_symbol_table || display_symbol_table) {
- auto found_dynamic_symbol_table = false;
- 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;
- found_dynamic_symbol_table = true;
- if (!section.entry_count()) {
- outln("Symbol table '{}' contains zero entries.", ELF_DYNSYM);
- } else {
- outln("Symbol table '{}' contains {} entries.", ELF_DYNSYM, section.entry_count());
- }
- return IterationDecision::Break;
- });
- if (object->symbol_count()) {
- // FIXME: Add support for init/fini/start/main sections
- outln(" Num: Value{} Size{} Type Bind Name", addr_padding, addr_padding);
- object->for_each_symbol([](const ELF::DynamicObject::Symbol& sym) {
- out(" {:>4}: ", sym.index());
- out("{:p} ", sym.value());
- out("{:p} ", sym.size());
- out("{:8} ", object_symbol_type_to_string(sym.type()));
- out("{:8} ", object_symbol_binding_to_string(sym.bind()));
- out("{}", sym.name());
- outln();
- });
- }
- }
- if (!found_dynamic_symbol_table)
- outln("No dynamic symbol information for this file.");
- outln();
- }
- if (display_symbol_table) {
- if (elf_image.symbol_count()) {
- outln("Symbol table '{}' contains {} entries:", ELF_SYMTAB, elf_image.symbol_count());
- outln(" Num: Value{} Size{} Type Bind Name", addr_padding, addr_padding);
- elf_image.for_each_symbol([](const ELF::Image::Symbol& sym) {
- out(" {:>4}: ", sym.index());
- out("{:p} ", sym.value());
- out("{:p} ", sym.size());
- out("{:8} ", object_symbol_type_to_string(sym.type()));
- out("{:8} ", object_symbol_binding_to_string(sym.bind()));
- out("{}", sym.name());
- outln();
- });
- } else {
- outln("Symbol table '{}' contains zero entries.", ELF_SYMTAB);
- }
- outln();
- }
- if (display_hardening) {
- outln("Security Hardening:");
- outln("RELRO Stack Canary NX PIE RPATH RUNPATH Symbols ");
- bool relro = false;
- elf_image.for_each_program_header([&relro](const ELF::Image::ProgramHeader& program_header) {
- if (program_header.type() == PT_GNU_RELRO) {
- relro = true;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- 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)
- out("\033[0;32m{:13}\033[0m ", "Full RELRO");
- else
- out("\033[0;33m{:13}\033[0m ", "Partial RELRO");
- } else {
- out("\033[0;31m{:13}\033[0m ", "No RELRO");
- }
- bool canary = false;
- elf_image.for_each_symbol([&canary](const ELF::Image::Symbol& sym) {
- if (sym.name() == "__stack_chk_fail" || sym.name() == "__intel_security_cookie") {
- canary = true;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- if (canary)
- out("\033[0;32m{:12}\033[0m ", "Canary found");
- else
- out("\033[0;31m{:12}\033[0m ", "No canary");
- bool nx = false;
- elf_image.for_each_program_header([&nx](const ELF::Image::ProgramHeader& program_header) {
- 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)
- out("\033[0;32m{:12}\033[0m ", "NX enabled");
- else
- out("\033[0;31m{:12}\033[0m ", "NX disabled");
- bool pie = false;
- if (header.e_type == ET_REL || header.e_type == ET_DYN)
- pie = true;
- if (pie)
- out("\033[0;32m{:12}\033[0m ", "PIE enabled");
- else
- out("\033[0;31m{:12}\033[0m ", "No PIE");
- StringView rpath;
- if (elf_image.is_dynamic())
- rpath = object->rpath();
- if (rpath.is_empty())
- out("\033[0;32m{:12}\033[0m ", "No RPATH");
- else
- out("\033[0;31m{:12}\033[0m ", rpath);
- StringView runpath;
- if (elf_image.is_dynamic())
- runpath = object->runpath();
- if (runpath.is_empty())
- out("\033[0;32m{:12}\033[0m ", "No RUNPATH");
- else
- out("\033[0;31m{:12}\033[0m ", runpath);
- out("{} symbols", elf_image.symbol_count());
- outln();
- }
- return 0;
- }
|