/* Copyright 2017 - 2021 R. Thomas * Copyright 2017 - 2021 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_PE_BINARY_H_ #define LIEF_PE_BINARY_H_ #include #include "LIEF/PE/Header.hpp" #include "LIEF/PE/OptionalHeader.hpp" #include "LIEF/PE/DosHeader.hpp" #include "LIEF/PE/RichHeader.hpp" #include "LIEF/PE/Import.hpp" #include "LIEF/PE/TLS.hpp" #include "LIEF/PE/Export.hpp" #include "LIEF/PE/Debug.hpp" #include "LIEF/PE/Symbol.hpp" #include "LIEF/PE/signature/Signature.hpp" #include "LIEF/Abstract/Binary.hpp" #include "LIEF/visibility.h" namespace LIEF { namespace PE { class Parser; class Builder; //! Class which represent a PE binary object class LIEF_API Binary : public LIEF::Binary { friend class Parser; friend class Builder; public: Binary(const std::string& name, PE_TYPE type); virtual ~Binary(void); //! Return `PE32` or `PE32+` PE_TYPE type(void) const; //! Convert Relative Virtual Address to offset //! //! We try to get the get section wich hold the given //! `RVA` and convert it to offset. If the section //! does not exist, we assume that `RVA` = `offset` uint64_t rva_to_offset(uint64_t RVA); //! Convert Virtual address to offset uint64_t va_to_offset(uint64_t VA); //! Find the section associated with the `offset` Section& section_from_offset(uint64_t offset); const Section& section_from_offset(uint64_t offset) const; //! Find the section associated with the `virtual address` Section& section_from_rva(uint64_t virtual_address); const Section& section_from_rva(uint64_t virtual_address) const; //! Return binary's sections it_sections sections(void); it_const_sections sections(void) const; // ======= // Headers // ======= //! Return a reference to the PE::DosHeader object DosHeader& dos_header(void); const DosHeader& dos_header(void) const; //! Return a reference to the PE::Header object Header& header(void); const Header& header(void) const; //! Return a reference to the OptionalHeader object OptionalHeader& optional_header(void); const OptionalHeader& optional_header(void) const; //! Compute the binary's virtual size. //! It should match with OptionalHeader::sizeof_image uint64_t virtual_size(void) const; //! Compute the size of all headers uint32_t sizeof_headers(void) const; //! Return a reference to the TLS object TLS& tls(void); const TLS& tls(void) const; //! Set a TLS object in the current Binary void tls(const TLS& tls); //! Check if the current binary has a TLS object bool has_tls(void) const; //! Check if the current binary has imports //! //! @see Import bool has_imports(void) const; //! Check if the current binary conatains signatures bool has_signatures(void) const; //! Check if the current binary has exports. //! //! @see Export bool has_exports(void) const; //! Check if the current binary has resources bool has_resources(void) const; //! Check if the current binary has exceptions bool has_exceptions(void) const; //! Check if the current binary has relocations //! //! @see Relocation bool has_relocations(void) const; //! Check if the current binary has debugs bool has_debug(void) const; //! Check if the current binary has a load configuration bool has_configuration(void) const; //! Check if the current binary has been built has reproducible, replacing timestamps by a compile hash. //! //! @see Debug bool is_reproducible_build(void) const; //! Return the Signature object(s) if the bianry is signed it_const_signatures signatures(void) const; //! Verify the binary against the embedded signature(s) (if any) //! First, it checks that the embedded signatures are correct (c.f. Signature::check) //! and then it checks that the authentihash matches ContentInfo::digest //! //! One can tweak the verification process with the Signature::VERIFICATION_CHECKS flags //! //! @see LIEF::PE::Signature::check Signature::VERIFICATION_FLAGS verify_signature( Signature::VERIFICATION_CHECKS checks = Signature::VERIFICATION_CHECKS::DEFAULT) const; //! Verify the binary with the Signature object provided in the first parameter //! It can be used to verify a detached signature: //! //! \code{.cpp} //! result detached = LIEF::PE::SignatureParser::parse("sig.pkcs7") //! if (detached) { //! binary->verify_signature(detached.value()); //! } //! \endcode Signature::VERIFICATION_FLAGS verify_signature(const Signature& sig, Signature::VERIFICATION_CHECKS checks = Signature::VERIFICATION_CHECKS::DEFAULT) const; //! Compute the authentihash according to the algorithm provided in the first //! parameter std::vector authentihash(ALGORITHMS algo) const; //! Try to predict the RVA of the function `function` in the import library `library` //! //! @warning //! The value could be chang if imports change //! //! @note //! It should be used with: //! LIEF::PE::Builder::build_imports set to ``true`` //! //! @param[in] library Library name in which the function is located //! @param[in] function Function name //! @return The address of the function (``IAT``) in the new import table uint32_t predict_function_rva(const std::string& library, const std::string& function); //! Return the Export object Export& get_export(void); const Export& get_export(void) const; //! Return binary Symbols std::vector& symbols(void); const std::vector& symbols(void) const; //! Return resources as a tree ResourceNode& resources(void); const ResourceNode& resources(void) const; //! Set a new resource tree void set_resources(const ResourceDirectory& resource); //! Set a new resource tree void set_resources(const ResourceData& resource); //! Return the ResourcesManager (class to manage resources more easily than the tree one) ResourcesManager resources_manager(void); const ResourcesManager resources_manager(void) const; // ========================== // Methods to manage sections // ========================== //! Return binary's section from its name //! //! @param[in] name Name of the Section Section& get_section(const std::string& name); const Section& get_section(const std::string& name) const; //! Return the section associated with import table const Section& import_section(void) const; Section& import_section(void); //! Delete the section with the given name //! //! @param[in] name Name of section to delete //! @param[in] clear if ``true`` clear the section's content with 0 before removing (default: ``false``) virtual void remove_section(const std::string& name, bool clear = false) override; //! Remove the given section void remove(const Section& section, bool clear = false); //! Add a section to the binary and return the section added. Section& add_section( const Section& section, PE_SECTION_TYPES type = PE_SECTION_TYPES::UNKNOWN); // ============================= // Methods to manage relocations // ============================= it_relocations relocations(void); it_const_relocations relocations(void) const; //! Add a @link PE::Relocation relocation @endlink Relocation& add_relocation(const Relocation& relocation); //! Remove all relocations void remove_all_relocations(void); // =============================== // Methods to manage DataDirectory // =============================== //! Return data directories in the binary it_data_directories data_directories(void); it_const_data_directories data_directories(void) const; //! Return the DataDirectory with the given type (or index) DataDirectory& data_directory(DATA_DIRECTORY index); const DataDirectory& data_directory(DATA_DIRECTORY index) const; bool has(DATA_DIRECTORY index) const; //! Return the debug_entries_t object debug_entries_t& debug(void); const debug_entries_t& debug(void) const; //! Retrun the LoadConfiguration object const LoadConfiguration& load_configuration(void) const; LoadConfiguration& load_configuration(void); // ======= // Overlay // ======= //! Return the overlay content const std::vector& overlay(void) const; std::vector& overlay(void); // ======== // DOS Stub // ======== //! Return the DOS stub content const std::vector& dos_stub(void) const; std::vector& dos_stub(void); //! Update the DOS stub content void dos_stub(const std::vector& content); // Rich Header // ----------- //! Return a reference to the RichHeader object RichHeader& rich_header(void); const RichHeader& rich_header(void) const; //! Set a RichHeader object in the current Binary void rich_header(const RichHeader& rich_header); //! Check if the current binary has a RichHeader object bool has_rich_header(void) const; // ========================= // Methods to manage Imports // ========================= //! return binary's @link PE::Import imports @endlink it_imports imports(void); it_const_imports imports(void) const; //! Returns the PE::Import from the given name //! //! @param[in] import_name Name of the import Import& get_import(const std::string& import_name); const Import& get_import(const std::string& import_name) const; //! ``True`` if the binary import the given library name //! //! @param[in] import_name Name of the import bool has_import(const std::string& import_name) const; //! Add the function @p function of the library @p library //! //! @param[in] library library name of the function //! @param[in] function function's name from the library to import ImportEntry& add_import_function(const std::string& library, const std::string& function); //! add an imported library (i.e. `DLL`) to the binary Import& add_library(const std::string& name); //! Remove the library with the given `name` void remove_library(const std::string& name); //! Remove all libraries in the binary void remove_all_libraries(void); //! Hook an imported function //! //! When using this function, LIEF::PE::Builder::build_imports and LIEF::PE::Builder::patch_imports //! should be set to ``true`` //! //! @param[in] function Function name to hook //! @param[in] address Address of the hook void hook_function(const std::string& function, uint64_t address); //! Hook an imported function //! //! When using this function, LIEF::PE::Builder::build_imports(true) and LIEF::PE::Builder::patch_imports //! should be set to ``true`` //! //! @param[in] library Library name in which the function is located //! @param[in] function Function name to hook //! @param[in] address Address of the hook void hook_function(const std::string& library, const std::string& function, uint64_t address); //! Reconstruct the binary object and write it in `filename` //! //! Rebuild a PE binary from the current Binary object. //! When rebuilding, import table and relocations are not rebuilt. virtual void write(const std::string& filename) override; virtual void accept(Visitor& visitor) const override; // LIEF Interface // ============== //! 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 Type of the Virtual address: VA or RVA. Default: Auto virtual 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 Type of the Virtual address: VA or RVA. Default: Auto virtual 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; //! Return the content located at virtual address // //! @param[in] virtual_address Virtual address of the data to retrieve //! @param[in] size Size in bytes of the data to retrieve //! @param[in] addr_type Type of the Virtual address: VA or RVA. Default: Auto virtual 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; //! Return the binary's entrypoint virtual uint64_t entrypoint(void) const override; //! Check if the binary is position independent virtual bool is_pie(void) const override; //! Check if the binary uses ``NX`` protection virtual bool has_nx(void) const override; virtual LIEF::Binary::functions_t ctor_functions(void) const override; //! **All** functions found in the binary LIEF::Binary::functions_t functions(void) const; //! Functions found in the Exception table directory LIEF::Binary::functions_t exception_functions(void) const; bool operator==(const Binary& rhs) const; bool operator!=(const Binary& rhs) const; virtual std::ostream& print(std::ostream& os) const override; private: Binary(void); //! Make space between the last section header and the beginning of the //! content of first section void make_space_for_new_section(void); //! Return binary's symbols as LIEF::Symbol virtual LIEF::symbols_t get_abstract_symbols(void) override; virtual LIEF::Header get_abstract_header(void) const override; //! Return binary's section as LIEF::Section virtual LIEF::sections_t get_abstract_sections(void) override; virtual LIEF::relocations_t get_abstract_relocations(void) override; virtual LIEF::Binary::functions_t get_abstract_exported_functions(void) const override; virtual LIEF::Binary::functions_t get_abstract_imported_functions(void) const override; virtual std::vector get_abstract_imported_libraries(void) const override; void update_lookup_address_table_offset(void); void update_iat(void); PE_TYPE type_; DosHeader dos_header_; RichHeader rich_header_; Header header_; OptionalHeader optional_header_; int32_t available_sections_space_; bool has_rich_header_; bool has_tls_; bool has_imports_; bool has_exports_; bool has_resources_; bool has_exceptions_; bool has_relocations_; bool has_debug_; bool has_configuration_; bool is_reproducible_build_; signatures_t signatures_; TLS tls_; sections_t sections_; data_directories_t data_directories_; symbols_t symbols_; strings_table_t strings_table_; relocations_t relocations_; ResourceNode* resources_; imports_t imports_; Export export_; debug_entries_t debug_; uint64_t overlay_offset_ = 0; std::vector overlay_; std::vector dos_stub_; std::vector section_offset_padding_; LoadConfiguration* load_configuration_{nullptr}; std::map> hooks_; }; } } #endif