/* Copyright 2017 - 2022 R. Thomas * Copyright 2017 - 2022 Quarkslab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIEF_ELF_BINARY_H_ #define LIEF_ELF_BINARY_H_ #include #include #include "LIEF/visibility.h" #include "LIEF/errors.hpp" #include "LIEF/iterators.hpp" #include "LIEF/Abstract/Binary.hpp" #include "LIEF/ELF/Header.hpp" namespace LIEF { //! Namespace related to the LIEF's ELF module namespace ELF { namespace DataHandler { class Handler; } class Builder; class DynamicEntry; class ExeLayout; class GnuHash; class Layout; class Note; class ObjectFileLayout; class Parser; class Relocation; class Section; class Segment; class Symbol; class SymbolVersion; class SymbolVersionDefinition; class SymbolVersionRequirement; class SysvHash; struct sizing_info_t; //! Class which represents an ELF binary class LIEF_API Binary : public LIEF::Binary { friend class Parser; friend class Builder; friend class ExeLayout; friend class Layout; friend class ObjectFileLayout; public: using string_list_t = std::vector; using overlay_t = std::vector; //! Internal container for storing notes using notes_t = std::vector>; //! Iterator which outputs Note& object using it_notes = ref_iterator; //! Iterator which outputs const Note& object using it_const_notes = const_ref_iterator; //! Internal container for storing SymbolVersionRequirement using symbols_version_requirement_t = std::vector>; //! Iterator which outputs SymbolVersionRequirement& object using it_symbols_version_requirement = ref_iterator; //! Iterator which outputs const SymbolVersionRequirement& object using it_const_symbols_version_requirement = const_ref_iterator; //! Internal container for storing SymbolVersionDefinition using symbols_version_definition_t = std::vector>; //! Iterator which outputs SymbolVersionDefinition& object using it_symbols_version_definition = ref_iterator; //! Iterator which outputs const SymbolVersionDefinition& object using it_const_symbols_version_definition = const_ref_iterator; //! Internal container for storing ELF's Segment using segments_t = std::vector>; //! Iterator which outputs Segment& object using it_segments = ref_iterator; //! Iterator which outputs const Segment& object using it_const_segments = const_ref_iterator; //! Internal container for storing ELF's DynamicEntry using dynamic_entries_t = std::vector>; //! Iterator which outputs DynamicEntry& object using it_dynamic_entries = ref_iterator; //! Iterator which outputs const DynamicEntry& object using it_const_dynamic_entries = const_ref_iterator; //! Internal container for storing ELF's SymbolVersion using symbols_version_t = std::vector>; //! Iterator which outputs SymbolVersion& object using it_symbols_version = ref_iterator; //! Iterator which outputs const SymbolVersion& object using it_const_symbols_version = const_ref_iterator; //! Internal container for storing ELF's Relocation using relocations_t = std::vector>; //! Iterator which outputs plt/got Relocation& object using it_pltgot_relocations = filter_iterator; //! Iterator which outputs plt/got const Relocation& object using it_const_pltgot_relocations = const_filter_iterator; //! Iterator which outputs dynamic Relocation& object (not related to the PLT/GOT mechanism) using it_dynamic_relocations = filter_iterator; //! Iterator which outputs dynamic const Relocation& object (not related to the PLT/GOT mechanism) using it_const_dynamic_relocations = const_filter_iterator; //! Iterator which outputs Relocation& object found in object files (.o) using it_object_relocations = filter_iterator; //! Iterator which outputs const Relocation& object found in object files (.o) using it_const_object_relocations = const_filter_iterator; //! Iterator which outputs Relocation& object using it_relocations = ref_iterator; //! Iterator which outputs const Relocation& object using it_const_relocations = const_ref_iterator; //! Internal container for storing ELF's Symbol using symbols_t = std::vector>; //! Iterator which outputs the Dynamic Symbol& object using it_dynamic_symbols = ref_iterator; //! Iterator which outputs the Dynamic const Symbol& object using it_const_dynamic_symbols = const_ref_iterator; //! Iterator which outputs the static/debug Symbol& object using it_static_symbols = ref_iterator; //! Iterator which outputs the static/debug const Symbol& object using it_const_static_symbols = const_ref_iterator; //! Iterator which outputs static and dynamic Symbol& object using it_symbols = ref_iterator>; //! Iterator which outputs static and dynamic const Symbol& object using it_const_symbols = const_ref_iterator>; //! Iterator which outputs exported Symbol& object using it_exported_symbols = filter_iterator>; //! Iterator which outputs exported const Symbol& object using it_const_exported_symbols = const_filter_iterator>; //! Iterator which outputs imported Symbol& object using it_imported_symbols = filter_iterator>; //! Iterator which outputs imported const Symbol& object using it_const_imported_symbols = const_filter_iterator>; //! Internal container for storing ELF's Section using sections_t = std::vector>; //! Iterator which outputs Section& object using it_sections = ref_iterator; //! Iterator which outputs const Section& object using it_const_sections = const_ref_iterator; public: Binary& operator=(const Binary& ) = delete; Binary(const Binary& copy) = delete; //! Return binary's class (ELF32 or ELF64) ELF_CLASS type() const; //! Return @link ELF::Header Elf header @endlink Header& header(); const Header& header() const; //! Return the last offset used in binary //! according to sections table uint64_t last_offset_section() const; //! Return the last offset used in binary //! according to segments table uint64_t last_offset_segment() const; //! Return the next virtual address available uint64_t next_virtual_address() const; //! Return an iterator over the binary's sections it_sections sections(); it_const_sections sections() const; //! Return the binary's entrypoint uint64_t entrypoint() const override; //! Return binary's segments it_segments segments(); it_const_segments segments() const; //! Return binary's dynamic entries it_dynamic_entries dynamic_entries(); it_const_dynamic_entries dynamic_entries() const; //! Add the given dynamic entry and return the new entry DynamicEntry& add(const DynamicEntry& entry); //! Add the given note and return the created entry Note& add(const Note& note); //! Remove the given dynamic entry void remove(const DynamicEntry& entry); //! Remove **all** dynamic entries with the given tag void remove(DYNAMIC_TAGS tag); //! Remove the given section. The ``clear`` parameter //! can be used to zeroize the original content beforehand //! //! @param[in] section The section to remove //! @param[in] clear Whether zeroize the original content void remove(const Section& section, bool clear = false); //! Remove the given note void remove(const Note& note); //! Remove **all** notes with the given type void remove(NOTE_TYPES type); //! Remove the given segment void remove(const Segment& seg); //! Return an iterator over the binary's dynamic symbols //! The dynamic symbols are those located in the ``.dynsym`` section it_dynamic_symbols dynamic_symbols(); it_const_dynamic_symbols dynamic_symbols() const; //! Return symbols which are exported by the binary it_exported_symbols exported_symbols(); it_const_exported_symbols exported_symbols() const; //! Return symbols which are imported by the binary it_imported_symbols imported_symbols(); it_const_imported_symbols imported_symbols() const; //! Return statics symbols. it_static_symbols static_symbols(); it_const_static_symbols static_symbols() const; //! Return the symbol versions it_symbols_version symbols_version(); it_const_symbols_version symbols_version() const; //! Return symbols version definition it_symbols_version_definition symbols_version_definition(); it_const_symbols_version_definition symbols_version_definition() const; //! Return Symbol version requirement it_symbols_version_requirement symbols_version_requirement(); it_const_symbols_version_requirement symbols_version_requirement() const; //! Return dynamic relocations it_dynamic_relocations dynamic_relocations(); it_const_dynamic_relocations dynamic_relocations() const; //! Add a new *dynamic* relocation. //! //! We consider a dynamic relocation as a relocation which is not plt-related //! //! See: add_pltgot_relocation Relocation& add_dynamic_relocation(const Relocation& relocation); //! Add a .plt.got relocation. This kind of relocation is usually //! associated with a PLT stub that aims at resolving the underlying symbol //! //! See also: add_dynamic_relocation Relocation& add_pltgot_relocation(const Relocation& relocation); //! Add relocation for object file (.o) //! //! The first parameter is the section to add while the second parameter //! is the LIEF::ELF::Section associated with the relocation. //! //! If there is an error, this function returns a ``nullptr``. Otherwise, it returns //! the relocation added. Relocation* add_object_relocation(const Relocation& relocation, const Section& section); //! Return `plt.got` relocations it_pltgot_relocations pltgot_relocations(); it_const_pltgot_relocations pltgot_relocations() const; //! Return relocations used in an object file (``*.o``) it_object_relocations object_relocations(); it_const_object_relocations object_relocations() const; //! Return **all** relocations present in the binary it_relocations relocations(); it_const_relocations relocations() const; //! Return relocation associated with the given address. //! It returns a ``nullptr`` if it is not found const Relocation* get_relocation(uint64_t address) const; Relocation* get_relocation(uint64_t address); //! Return relocation associated with the given Symbol //! It returns a ``nullptr`` if it is not found const Relocation* get_relocation(const Symbol& symbol) const; Relocation* get_relocation(const Symbol& symbol); //! Return relocation associated with the given Symbol name //! It returns a ``nullptr`` if it is not found const Relocation* get_relocation(const std::string& symbol_name) const; Relocation* get_relocation(const std::string& symbol_name); //! ``true`` if GNU hash is used //! //! @see gnu_hash and use_sysv_hash bool use_gnu_hash() const; //! Return the GnuHash object in **readonly** //! If the ELF binary does not use the GNU hash table, return a nullptr const GnuHash* gnu_hash() const; //! ``true`` if SYSV hash is used //! //! @see sysv_hash and use_gnu_hash bool use_sysv_hash() const; //! Return the SysvHash object as a **read-only** object //! If the ELF binary does not use the legacy sysv hash table, return a nullptr const SysvHash* sysv_hash() const; //! Check if a section with the given name exists in the binary bool has_section(const std::string& name) const; //! Check if a section that handles the given offset exists bool has_section_with_offset(uint64_t offset) const; //! Check if a section that handles the given virtual address exists bool has_section_with_va(uint64_t va) const; //! Return Section with the given `name`. If the section can't be //! found, it returns a nullptr Section* get_section(const std::string& name); const Section* get_section(const std::string& name) const; //! Return the `.text` section. If the section //! can't be found, it returns a nullptr Section* text_section(); //! Return the `.dynamic` section. If the section //! can't be found, it returns a nullptr Section* dynamic_section(); //! Return the hash section. If the section //! can't be found, it returns a nullptr Section* hash_section(); //! Return section which holds static symbols. If the section //! can't be found, it returns a nullptr Section* static_symbols_section(); //! Return program image base. For instance ``0x40000`` //! //! To compute the image base, we look for the PT_PHDR segment header (phdr), //! and we return ``phdr->p_vaddr - phdr->p_offset`` uint64_t imagebase() const override; //! Return the size of the mapped binary uint64_t virtual_size() const; //! Check if the binary uses a loader (also named linker or interpreter) //! @see interpreter bool has_interpreter() const; //! Return the ELF interpreter if any. (e.g. `/lib64/ld-linux-x86-64.so.2`) //! If the binary does not have an interpreter, it returns an empty string //! //! @see has_interpreter const std::string& interpreter() const; //! Change the interpreter void interpreter(const std::string& interpreter); //! Return an iterator on both static and dynamic symbols it_symbols symbols(); it_const_symbols symbols() const; //! Export the given symbol and create it if it doesn't exist Symbol& export_symbol(const Symbol& symbol); //! Export the symbol with the given name and create it if it doesn't exist Symbol& export_symbol(const std::string& symbol_name, uint64_t value = 0); //! Check if the symbol with the given ``name`` exists in the dynamic symbols table bool has_dynamic_symbol(const std::string& name) const; //! Get the dynamic symbol from the given name. //! Return a nullptr if it can't be found const Symbol* get_dynamic_symbol(const std::string& name) const; Symbol* get_dynamic_symbol(const std::string& name); //! Check if the symbol with the given ``name`` exists in the static symbol table bool has_static_symbol(const std::string& name) const; //! Get the static symbol from the given name //! Return a nullptr if it can't be found const Symbol* get_static_symbol(const std::string& name) const; Symbol* get_static_symbol(const std::string& name); //! Return list of the strings used by the ELF binary. //! //! Basically, this function looks for string in the ``.roadata`` section string_list_t strings(size_t min_size = 5) const; //! Remove symbols with the given name in both: //! * dynamic symbols //! * static symbols //! //! @see remove_static_symbol, remove_dynamic_symbol void remove_symbol(const std::string& name); //! Remove static symbols with the given name void remove_static_symbol(const std::string& name); void remove_static_symbol(Symbol* symbol); //! Remove dynamic symbols with the given name void remove_dynamic_symbol(const std::string& name); //! Remove the given symbol from the dynamic symbols table. //! //! As a side effect, it will remove any ELF::Relocation //! that refers to this symbol and the SymbolVersion (if any) //! associated with this symbol void remove_dynamic_symbol(Symbol* symbol); //! Return the address of the given function name result get_function_address(const std::string& func_name) const override; //! Return the address of the given function name // //! @param[in] func_name The function's name target //! @param[in] demangled Use the demangled name result get_function_address(const std::string& func_name, bool demangled) const; //! Add a new section in the binary //! //! @param[in] section The section object to insert //! @param[in] loaded Boolean value to indicate that section's data must be loaded //! by a PT_LOAD segment //! //! @return The section added. The `size` and the `virtual address` might change. Section* add(const Section& section, bool loaded = true); Section* extend(const Section& section, uint64_t size); //! Add a static symbol Symbol& add_static_symbol(const Symbol& symbol); //! Add a dynamic symbol with the associated SymbolVersion Symbol& add_dynamic_symbol(const Symbol& symbol, const SymbolVersion* version = nullptr); //! Create a symbol for the function at the given address and export it Symbol& add_exported_function(uint64_t address, const std::string& name = ""); //! Add a library as dependency DynamicEntryLibrary& add_library(const std::string& library_name); //! Remove the given library from the dependencies void remove_library(const std::string& library_name); //! Get the library object (DynamicEntryLibrary) from the given name //! If the library can't be found, it returns a nullptr. DynamicEntryLibrary* get_library(const std::string& library_name); //! Get the library object (DynamicEntryLibrary) from the given name //! If the library can't be found, it returns a nullptr. const DynamicEntryLibrary* get_library(const std::string& library_name) const; //! Check if the given library name exists in the current binary bool has_library(const std::string& name) const; //! Add a new segment in the binary //! //! The segment is inserted at the end //! //! @return The segment added. `Virtual address` and `File Offset` might change. Segment* add(const Segment& segment, uint64_t base = 0); //! Replace the segment given in 2nd parameter with the segment given in the first one and return the updated segment. //! //! @warning The ``original_segment`` is no longer valid after this function Segment* replace(const Segment& new_segment, const Segment& original_segment, uint64_t base = 0); Segment* extend(const Segment& segment, uint64_t size); //! Patch the content at virtual address @p address with @p patch_value //! //! @param[in] address Address to patch //! @param[in] patch_value Patch to apply //! @param[in] addr_type Specify if the address should be used as an absolute virtual address or an RVA void patch_address(uint64_t address, const std::vector& patch_value, LIEF::Binary::VA_TYPES addr_type = LIEF::Binary::VA_TYPES::AUTO) override; //! Patch the address with the given value //! //! @param[in] address Address to patch //! @param[in] patch_value Patch to apply //! @param[in] size Size of the value in **bytes** (1, 2, ... 8) //! @param[in] addr_type Specify if the address should be used as an absolute virtual address or an RVA void patch_address(uint64_t address, uint64_t patch_value, size_t size = sizeof(uint64_t), LIEF::Binary::VA_TYPES addr_type = LIEF::Binary::VA_TYPES::AUTO) override; //! Patch the imported symbol with the ``address`` //! //! @param[in] symbol Imported symbol to patch //! @param[in] address New address void patch_pltgot(const Symbol& symbol, uint64_t address); //! Patch the imported symbol's name with the ``address`` //! //! @param[in] symbol_name Imported symbol's name to patch //! @param[in] address New address void patch_pltgot(const std::string& symbol_name, uint64_t address); //! Strip the binary by removing static symbols void strip(); //! Remove a binary's section. //! //! @param[in] name The name of the section to remove //! @param[in] clear Whether zeroize the original content void remove_section(const std::string& name, bool clear = false) override; //! Reconstruct the binary object and write it in `filename` //! //! @param filename Path for the written ELF binary void write(const std::string& filename) override; //! Reconstruct the binary object and write it in `os` stream //! //! @param Output stream for the written ELF binary void write(std::ostream& os) override; //! Reconstruct the binary object and return its content as a byte vector std::vector raw(); //! Convert a virtual address to a file offset result virtual_address_to_offset(uint64_t virtual_address) const; //! Convert the given offset into a virtual address. //! //! @param[in] offset The offset to convert. //! @param[in] slide If not 0, it will replace the default base address (if any) result offset_to_virtual_address(uint64_t offset, uint64_t slide = 0) const override; //! Check if the binary has been compiled with `-fpie -pie` flags //! //! To do so we check if there is a `PT_INTERP` segment and if //! the binary type is `ET_DYN` (Shared object) bool is_pie() const override; //! Check if the binary uses the ``NX`` protection (Non executable stack) bool has_nx() const override; //! Return the ELF::Section from the given @p offset. Return a nullptr //! if a section can't be found //! //! If @p skip_nobits is set (which is the case by default), this function won't //! consider section for which the type is ``SHT_NOBITS`` (like ``.bss, .tbss, ...``) const Section* section_from_offset(uint64_t offset, bool skip_nobits = true) const; Section* section_from_offset(uint64_t offset, bool skip_nobits = true); //! Return the ELF::Section from the given @p address. Return a nullptr //! if a section can't be found. //! //! If @p skip_nobits is set (which is the case by default), this function won't //! consider section for which type is ``SHT_NOBITS`` (like ``.bss, .tbss, ...``) const Section* section_from_virtual_address(uint64_t address, bool skip_nobits = true) const; Section* section_from_virtual_address(uint64_t address, bool skip_nobits = true); //! Return the ELF::Segment from the given @p address. Return a nullptr //! if a segment can't be found. const Segment* segment_from_virtual_address(uint64_t address) const; Segment* segment_from_virtual_address(uint64_t address); //! Return the ELF::Segment from the @p offset. Return a nullptr //! if a segment can't be found. const Segment* segment_from_offset(uint64_t offset) const; Segment* segment_from_offset(uint64_t offset); //! Return the **first** ELF::DynamicEntry associated with the given tag //! If the tag can't be found, it returns a nullptr const DynamicEntry* get(DYNAMIC_TAGS tag) const; DynamicEntry* get(DYNAMIC_TAGS tag); //! Return the **first** ELF::Segment associated with the given type. //! If a segment can't be found, it returns a nullptr. const Segment* get(SEGMENT_TYPES type) const; Segment* get(SEGMENT_TYPES type); //! Return the **first** ELF::Note associated with the given type //! If a note can't be found, it returns a nullptr. const Note* get(NOTE_TYPES type) const; Note* get(NOTE_TYPES type); //! Return the **first** ELF::Section associated with the given type //! If a section can't be found, it returns a nullptr. const Section* get(ELF_SECTION_TYPES type) const; Section* get(ELF_SECTION_TYPES type); //! Check if an ELF::DynamicEntry associated with the given tag exists. bool has(DYNAMIC_TAGS tag) const; //! Check if ELF::Segment associated with the given type exists. bool has(SEGMENT_TYPES type) const; //! Check if a ELF::Note associated with the given type exists. bool has(NOTE_TYPES type) const; //! Check if a ELF::Section associated with the given type exists. bool has(ELF_SECTION_TYPES type) const; //! Return the content located at virtual address std::vector get_content_from_virtual_address(uint64_t virtual_address, uint64_t size, LIEF::Binary::VA_TYPES addr_type = LIEF::Binary::VA_TYPES::AUTO) const override; //! Method associated with the visitor pattern. void accept(LIEF::Visitor& visitor) const override; //! Apply the given permutation on the dynamic symbols table void permute_dynamic_symbols(const std::vector& permutation); //! List of binary constructors (typically, the functions located in the ``.init_array``) LIEF::Binary::functions_t ctor_functions() const override; //! List of the binary destructors (typically, the functions located in the ``.fini_array``) LIEF::Binary::functions_t dtor_functions() const; //! List of the functions found the in the binary. LIEF::Binary::functions_t functions() const; //! ``true`` if the binary embeds notes bool has_notes() const; //! Return an iterator over the ELF's LIEF::ELF::Note //! //! @see has_note it_const_notes notes() const; it_notes notes(); //! Return the last offset used by the ELF binary according to both: the sections table //! and the segments table uint64_t eof_offset() const; //! True if data are present at the end of the binary bool has_overlay() const; //! Overlay data (if any) const overlay_t& overlay() const; //! Function to set the overlay void overlay(overlay_t overlay); size_t hash(const std::string& name); ~Binary() override; std::ostream& print(std::ostream& os) const override; bool operator==(const Binary& rhs) const; bool operator!=(const Binary& rhs) const; Binary& operator+=(const DynamicEntry& entry); Binary& operator+=(const Section& section); Binary& operator+=(const Segment& segment); Binary& operator+=(const Note& note); Binary& operator-=(const DynamicEntry& entry); Binary& operator-=(DYNAMIC_TAGS tag); Binary& operator-=(const Note& note); Binary& operator-=(NOTE_TYPES type); Segment* operator[](SEGMENT_TYPES type); const Segment* operator[](SEGMENT_TYPES type) const; DynamicEntry* operator[](DYNAMIC_TAGS tag); const DynamicEntry* operator[](DYNAMIC_TAGS tag) const; Note* operator[](NOTE_TYPES type); const Note* operator[](NOTE_TYPES type) const; Section* operator[](ELF_SECTION_TYPES type); const Section* operator[](ELF_SECTION_TYPES type) const; protected: struct phdr_relocation_info_t { uint64_t new_offset = 0; size_t nb_segments = 0; inline void clear() { new_offset = 0; nb_segments = 0; } }; Binary(); //! Return an abstraction of binary's section: LIEF::Section LIEF::Binary::sections_t get_abstract_sections() override; LIEF::Header get_abstract_header() const override; LIEF::Binary::functions_t get_abstract_exported_functions() const override; LIEF::Binary::functions_t get_abstract_imported_functions() const override; std::vector get_abstract_imported_libraries() const override; LIEF::Binary::symbols_t get_abstract_symbols() override; LIEF::Binary::relocations_t get_abstract_relocations() override; template void patch_relocations(uint64_t from, uint64_t shift); template void patch_addend(Relocation& relocatio, uint64_t from, uint64_t shift); void shift_sections(uint64_t from, uint64_t shift); void shift_segments(uint64_t from, uint64_t shift); void shift_dynamic_entries(uint64_t from, uint64_t shift); void shift_symbols(uint64_t from, uint64_t shift); void shift_relocations(uint64_t from, uint64_t shift); template void fix_got_entries(uint64_t from, uint64_t shift); LIEF::Binary::functions_t eh_frame_functions() const; LIEF::Binary::functions_t armexid_functions() const; template Segment* add_segment(const Segment& segment, uint64_t base); uint64_t relocate_phdr_table(); uint64_t relocate_phdr_table_pie(); uint64_t relocate_phdr_table_v1(); uint64_t relocate_phdr_table_v2(); template Segment* extend_segment(const Segment& segment, uint64_t size); template Section* add_section(const Section& section); std::vector static_dyn_symbols() const; std::string shstrtab_name() const; Section* add_frame_section(const Section& sec); LIEF::Binary::functions_t tor_functions(DYNAMIC_TAGS tag) const; ELF_CLASS type_ = ELF_CLASS::ELFCLASSNONE; Header header_; sections_t sections_; segments_t segments_; dynamic_entries_t dynamic_entries_; symbols_t dynamic_symbols_; symbols_t static_symbols_; relocations_t relocations_; symbols_version_t symbol_version_table_; symbols_version_requirement_t symbol_version_requirements_; symbols_version_definition_t symbol_version_definition_; notes_t notes_; std::unique_ptr gnu_hash_; std::unique_ptr sysv_hash_; std::unique_ptr datahandler_; phdr_relocation_info_t phdr_reloc_info_; std::string interpreter_; overlay_t overlay_; std::unique_ptr sizing_info_; }; } } #endif