File: C:/Users/fred/anaconda3/Library/include/LIEF/MachO/Binary.hpp
/* 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_MACHO_BINARY_H_
#define LIEF_MACHO_BINARY_H_
#include <vector>
#include <map>
#include "LIEF/types.hpp"
#include "LIEF/visibility.h"
#include "LIEF/Abstract/Binary.hpp"
#include "LIEF/iterators.hpp"
#include "LIEF/MachO/Header.hpp"
#include "LIEF/errors.hpp"
namespace LIEF {
//! Namespace related to the LIEF's Mach-O module
namespace MachO {
class BinaryParser;
class Builder;
class DyldInfo;
class BuildVersion;
class EncryptionInfo;
class DyldEnvironment;
class SubFramework;
class SegmentSplitInfo;
class DataInCode;
class CodeSignature;
class RPathCommand;
class ThreadCommand;
class VersionMin;
class SourceVersion;
class FunctionStarts;
class DynamicSymbolCommand;
class MainCommand;
class SymbolCommand;
class Symbol;
class UUIDCommand;
class DylinkerCommand;
class DylibCommand;
class SegmentCommand;
class LoadCommand;
class Header;
//! Class which represents a MachO binary
class LIEF_API Binary : public LIEF::Binary {
friend class BinaryParser;
friend class Builder;
friend class DyldInfo;
public:
using range_t = std::pair<uint64_t, uint64_t>;
//! Internal container for storing Mach-O LoadCommand
using commands_t = std::vector<std::unique_ptr<LoadCommand>>;
//! Iterator that outputs LoadCommand&
using it_commands = ref_iterator<commands_t&, LoadCommand*>;
//! Iterator that outputs const LoadCommand&
using it_const_commands = const_ref_iterator<const commands_t&, LoadCommand*>;
//! Internal container for storing Mach-O Symbol
using symbols_t = std::vector<std::unique_ptr<Symbol>>;
//! Iterator that outputs Symbol&
using it_symbols = ref_iterator<symbols_t&, Symbol*>;
//! Iterator that outputs const Symbol&
using it_const_symbols = const_ref_iterator<const symbols_t&, const Symbol*>;
//! Iterator that outputs exported Symbol&
using it_exported_symbols = filter_iterator<symbols_t&, Symbol*>;
//! Iterator that outputs exported const Symbol&
using it_const_exported_symbols = const_filter_iterator<const symbols_t&, const Symbol*>;
//! Iterator that outputs imported Symbol&
using it_imported_symbols = filter_iterator<symbols_t&, Symbol*>;
//! Iterator that outputs imported const Symbol&
using it_const_imported_symbols = const_filter_iterator<const symbols_t&, const Symbol*>;
//! Internal container for caching Mach-O Section
using sections_cache_t = std::vector<Section*>;
//! Iterator that outputs Section&
using it_sections = ref_iterator<sections_cache_t&>;
//! Iterator that outputs const Section&
using it_const_sections = const_ref_iterator<const sections_cache_t&>;
//! Internal container for storing Mach-O SegmentCommand
using segments_cache_t = std::vector<SegmentCommand*>;
//! Iterator that outputs SegmentCommand&
using it_segments = ref_iterator<segments_cache_t&>;
//! Iterator that outputs const SegmentCommand&
using it_const_segments = const_ref_iterator<const segments_cache_t&>;
//! Internal container for storing Mach-O DylibCommand
using libraries_cache_t = std::vector<DylibCommand*>;
//! Iterator that outputs DylibCommand&
using it_libraries = ref_iterator<libraries_cache_t&>;
//! Iterator that outputs const DylibCommand&
using it_const_libraries = const_ref_iterator<const libraries_cache_t&>;
//! Internal container for storing Mach-O Fileset Binary
using fileset_binaries_t = std::vector<std::unique_ptr<Binary>>;
//! Iterator that outputs Binary&
using it_fileset_binaries = ref_iterator<fileset_binaries_t&, Binary*>;
//! Iterator that outputs const Binary&
using it_const_fileset_binaries = const_ref_iterator<const fileset_binaries_t&, Binary*>;
struct KeyCmp {
bool operator() (const Relocation* lhs, const Relocation* rhs) const;
};
//! Internal container that store all the relocations
//! found in a Mach-O. The relocations are actually owned
//! by Section & SegmentCommand and these references are used for convenience
using relocations_t = std::set<Relocation*, KeyCmp>;
//! Iterator which outputs Relocation&
using it_relocations = ref_iterator<relocations_t&, Relocation*>;
//! Iterator which outputs const Relocation&
using it_const_relocations = const_ref_iterator<const relocations_t&, const Relocation*>;
public:
Binary(const Binary&) = delete;
Binary& operator=(const Binary&) = delete;
//! Return a reference to the MachO::Header
Header& header();
const Header& header() const;
//! Return an iterator over the MachO LoadCommand present
//! in the binary
it_commands commands();
it_const_commands commands() const;
//! Return an iterator over the MachO::Binary associated
//! with the LOAD_COMMAND_TYPES::LC_FILESET_ENTRY commands
it_fileset_binaries filesets();
it_const_fileset_binaries filesets() const;
//! Return binary's @link MachO::Symbol symbols @endlink
it_symbols symbols();
it_const_symbols symbols() const;
//! Check if a symbol with the given name exists
bool has_symbol(const std::string& name) const;
//! Return Symbol from the given name. If the symbol does not
//! exists, it returns a null pointer
const Symbol* get_symbol(const std::string& name) const;
Symbol* get_symbol(const std::string& name);
//! Check if the given symbol is exported
static bool is_exported(const Symbol& symbol);
//! Return binary's exported symbols (iterator over LIEF::MachO::Symbol)
it_exported_symbols exported_symbols();
it_const_exported_symbols exported_symbols() const;
//! Check if the given symbol is an imported one
static bool is_imported(const Symbol& symbol);
//! Return binary's imported symbols (iterator over LIEF::MachO::Symbol)
it_imported_symbols imported_symbols();
it_const_imported_symbols imported_symbols() const;
//! Return binary imported libraries (MachO::DylibCommand)
it_libraries libraries();
it_const_libraries libraries() const;
//! Return an iterator over the SegmentCommand
it_segments segments();
it_const_segments segments() const;
//! Return an iterator over the MachO::Section
it_sections sections();
it_const_sections sections() const;
//! Return an iterator over the MachO::Relocation
it_relocations relocations();
it_const_relocations relocations() const;
//! Reconstruct the binary object and write the result in the given `filename`
//!
//! @param filename Path to write the reconstructed binary
void write(const std::string& filename) override;
//! Reconstruct the binary object and return its content as bytes
std::vector<uint8_t> raw();
//! Check if the current binary has the given MachO::LOAD_COMMAND_TYPES
bool has(LOAD_COMMAND_TYPES type) const;
//! Return the LoadCommand associated with the given LOAD_COMMAND_TYPES
//! or a nullptr if the command can't be found.
const LoadCommand* get(LOAD_COMMAND_TYPES type) const;
LoadCommand* get(LOAD_COMMAND_TYPES type);
//! Insert a new LoadCommand
LoadCommand& add(const LoadCommand& command);
//! Insert a new LoadCommand at the specified ``index``
LoadCommand& add(const LoadCommand& command, size_t index);
//! Insert the given DylibCommand
LoadCommand& add(const DylibCommand& library);
//! Add a new LC_SEGMENT command from the given SegmentCommand
LoadCommand& add(const SegmentCommand& segment);
//! Insert a new shared library through a ``LC_LOAD_DYLIB`` command
LoadCommand& add_library(const std::string& name);
//! Add a new MachO::Section in the __TEXT segment
Section* add_section(const Section& section);
//! Add a section in the given MachO::SegmentCommand.
//!
//! @warning This method may corrupt the file if the segment is not the first one
//! nor the last one
Section* add_section(const SegmentCommand& segment, const Section& section);
//! Remove the section with the name provided in the first parameter.
//!
//! @param name Name of the MachO::Section to remove
//! @param clear If ``true`` clear the content of the section before removing
void remove_section(const std::string& name, bool clear = false) override;
//! Remove the given LoadCommand
bool remove(const LoadCommand& command);
//! Remove **all** LoadCommand with the given type (MachO::LOAD_COMMAND_TYPES)
bool remove(LOAD_COMMAND_TYPES type);
//! Remove the Load Command at the provided ``index``
bool remove_command(size_t index);
//! Remove the LC_SIGNATURE command
bool remove_signature();
//! Extend the **size** of the given LoadCommand
bool extend(const LoadCommand& command, uint64_t size);
//! Extend the **content** of the given SegmentCommand
bool extend_segment(const SegmentCommand& segment, size_t size);
//! Remove the ``PIE`` flag
bool disable_pie();
//! Return the binary's imagebase. ``0`` if not relevant
uint64_t imagebase() const override;
//! Size of the binary in memory when mapped by the loader (``dyld``)
uint64_t virtual_size() const;
//! Return the binary's loader (e.g. ``/usr/lib/dyld``) or an
//! empty string if the binary does not use a loader/linker
std::string loader() const;
//! Check if a section with the given name exists
bool has_section(const std::string& name) const;
//! Return the section from the given name of a nullptr
//! if the section can't be found.
Section* get_section(const std::string& name);
//! Return the section from the given name or a nullptr
//! if the section can't be found
const Section* get_section(const std::string& name) const;
//! Check if a segment with the given name exists
bool has_segment(const std::string& name) const;
//! Return the segment from the given name
const SegmentCommand* get_segment(const std::string& name) const;
//! Return the segment from the given name
SegmentCommand* get_segment(const std::string& name);
//! Remove the symbol with the given name
bool remove_symbol(const std::string& name);
//! Remove the given symbol
bool remove(const Symbol& sym);
//! Check if the given symbol can be safely removed.
bool can_remove(const Symbol& sym) const;
//! Check if the MachO::Symbol with the given name can be safely removed.
bool can_remove_symbol(const std::string& name) const;
//! Remove the given MachO::Symbol with the given name from the export table
bool unexport(const std::string& name);
//! Remove the given symbol from the export table
bool unexport(const Symbol& sym);
//! Return the MachO::Section that encompasses the provided offset.
//! If a section can't be found, it returns a null pointer (``nullptr``)
Section* section_from_offset(uint64_t offset);
const Section* section_from_offset(uint64_t offset) const;
//! Return the MachO::Section that encompasses the provided virtual address.
//! If a section can't be found, it returns a null pointer (``nullptr``)
Section* section_from_virtual_address(uint64_t virtual_address);
const Section* section_from_virtual_address(uint64_t virtual_address) const;
//! Convert a virtual address to an offset in the file
uint64_t 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)
uint64_t offset_to_virtual_address(uint64_t offset, uint64_t slide = 0) const override;
//! Return the binary's SegmentCommand that encompasses the provided offset
//!
//! If a SegmentCommand can't be found it returns a null pointer (``nullptr``).
SegmentCommand* segment_from_offset(uint64_t offset);
const SegmentCommand* segment_from_offset(uint64_t offset) const;
//! Return the index of the given SegmentCommand
size_t segment_index(const SegmentCommand& segment) const;
//! Return binary's *fat offset*. ``0`` if not relevant.
uint64_t fat_offset() const;
//! Return the binary's SegmentCommand which encompasses the given virtual address
//! or a nullptr if not found.
SegmentCommand* segment_from_virtual_address(uint64_t virtual_address);
const SegmentCommand* segment_from_virtual_address(uint64_t virtual_address) const;
//! Return the range of virtual addresses
range_t va_ranges() const;
//! Return the range of offsets
range_t off_ranges() const;
//! Check if the given address is encompassed in the
//! binary's virtual addresses range
bool is_valid_addr(uint64_t address) const;
//! Method so that the ``visitor`` can visit us
void accept(LIEF::Visitor& visitor) const override;
std::ostream& print(std::ostream& os) const override;
//! 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<uint8_t>& 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;
//! Return the content located at virtual address
std::vector<uint8_t> 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;
//! The binary entrypoint
uint64_t entrypoint() const override;
//! Check if the binary is position independent
bool is_pie() const override;
//! Check if the binary uses ``NX`` protection
bool has_nx() const override;
//! ``true`` if the binary has an entrypoint.
//!
//! Basically for libraries it will return ``false``
bool has_entrypoint() const;
//! ``true`` if the binary has a MachO::UUIDCommand command.
bool has_uuid() const;
//! Return the MachO::UUIDCommand if present, a nullptr otherwise.
UUIDCommand* uuid();
const UUIDCommand* uuid() const;
//! ``true`` if the binary has a MachO::MainCommand command.
bool has_main_command() const;
//! Return the MachO::MainCommand if present, a nullptr otherwise.
MainCommand* main_command();
const MainCommand* main_command() const;
//! ``true`` if the binary has a MachO::DylinkerCommand.
bool has_dylinker() const;
//! Return the MachO::DylinkerCommand if present, a nullptr otherwise.
DylinkerCommand* dylinker();
const DylinkerCommand* dylinker() const;
//! ``true`` if the binary has a MachO::DyldInfo command.
bool has_dyld_info() const;
//! Return the MachO::Dyld command if present, a nullptr otherwise.
DyldInfo* dyld_info();
const DyldInfo* dyld_info() const;
//! ``true`` if the binary has a MachO::FunctionStarts command.
bool has_function_starts() const;
//! Return the MachO::FunctionStarts command if present, a nullptr otherwise.
FunctionStarts* function_starts();
const FunctionStarts* function_starts() const;
//! ``true`` if the binary has a MachO::SourceVersion command.
bool has_source_version() const;
//! Return the MachO::SourceVersion command if present, a nullptr otherwise.
SourceVersion* source_version();
const SourceVersion* source_version() const;
//! ``true`` if the binary has a MachO::VersionMin command.
bool has_version_min() const;
//! Return the MachO::VersionMin command if present, a nullptr otherwise.
VersionMin* version_min();
const VersionMin* version_min() const;
//! ``true`` if the binary has a MachO::ThreadCommand command.
bool has_thread_command() const;
//! Return the MachO::ThreadCommand command if present, a nullptr otherwise.
ThreadCommand* thread_command();
const ThreadCommand* thread_command() const;
//! ``true`` if the binary has a MachO::RPathCommand command.
bool has_rpath() const;
//! Return the MachO::RPathCommand command if present, a nullptr otherwise.
RPathCommand* rpath();
const RPathCommand* rpath() const;
//! ``true`` if the binary has a MachO::SymbolCommand command.
bool has_symbol_command() const;
//! Return the MachO::SymbolCommand if present, a nullptr otherwise.
SymbolCommand* symbol_command();
const SymbolCommand* symbol_command() const;
//! ``true`` if the binary has a MachO::DynamicSymbolCommand command.
bool has_dynamic_symbol_command() const;
//! Return the MachO::SymbolCommand if present, a nullptr otherwise.
DynamicSymbolCommand* dynamic_symbol_command();
const DynamicSymbolCommand* dynamic_symbol_command() const;
//! ``true`` if the binary is signed with `LC_CODE_SIGNATURE` command
bool has_code_signature() const;
//! Return the MachO::CodeSignature if present, a nullptr otherwise.
CodeSignature* code_signature();
const CodeSignature* code_signature() const;
//! ``true`` if the binary is signed with the command `DYLIB_CODE_SIGN_DRS`
bool has_code_signature_dir() const;
//! Return the MachO::CodeSignature if present, a nullptr otherwise.
CodeSignature* code_signature_dir();
const CodeSignature* code_signature_dir() const;
//! ``true`` if the binary has a MachO::DataInCode command.
bool has_data_in_code() const;
//! Return the MachO::DataInCode if present, a nullptr otherwise.
DataInCode* data_in_code();
const DataInCode* data_in_code() const;
//! ``true`` if the binary has segment split info.
bool has_segment_split_info() const;
//! Return the MachO::SegmentSplitInfo if present, a nullptr otherwise.
SegmentSplitInfo* segment_split_info();
const SegmentSplitInfo* segment_split_info() const;
//! ``true`` if the binary has a sub framework command.
bool has_sub_framework() const;
//! ``true`` if the binary has Encryption Info.
bool has_encryption_info() const;
//! Return the MachO::DyldEnvironment if present, a nullptr otherwise.
EncryptionInfo* encryption_info();
const EncryptionInfo* encryption_info() const;
//! Return the MachO::SubFramework if present, a nullptr otherwise.
SubFramework* sub_framework();
const SubFramework* sub_framework() const;
//! ``true`` if the binary has Dyld envrionment variables.
bool has_dyld_environment() const;
//! Return the MachO::DyldEnvironment if present, a nullptr otherwise
DyldEnvironment* dyld_environment();
const DyldEnvironment* dyld_environment() const;
//! ``true`` if the binary has Build Version command.
bool has_build_version() const;
//! Return the MachO::BuildVersion if present, a nullptr otherwise.
BuildVersion* build_version();
const BuildVersion* build_version() const;
template<class T>
LIEF_LOCAL bool has_command() const;
template<class T>
LIEF_LOCAL T* command();
template<class T>
LIEF_LOCAL const T* command() const;
template<class T>
size_t count_commands() const;
LoadCommand* operator[](LOAD_COMMAND_TYPES type);
const LoadCommand* operator[](LOAD_COMMAND_TYPES type) const;
//! Return the list of the MachO's constructors
LIEF::Binary::functions_t ctor_functions() const override;
//! Return all the functions found in this MachO
LIEF::Binary::functions_t functions() const;
//! Return the functions found in the ``__unwind_info`` section
LIEF::Binary::functions_t unwind_functions() const;
//! ``true`` if the binary has a LOAD_COMMAND_TYPES::LC_FILESET_ENTRY command
bool has_filesets() const;
~Binary() override;
private:
//! Default constructor
Binary();
// Shift content next to LC table
void shift(size_t value);
void shift_command(size_t width, size_t from_offset);
//! Insert a Segment command in the cache field (segments_)
//! and keep a consistent state of the indexes.
size_t add_cached_segment(SegmentCommand& segment);
template<class T>
LIEF_LOCAL ok_error_t patch_relocation(Relocation& relocation, uint64_t from, uint64_t shift);
LIEF::Header get_abstract_header() const override;
LIEF::Binary::sections_t get_abstract_sections() override;
LIEF::Binary::symbols_t get_abstract_symbols() override;
LIEF::Binary::relocations_t get_abstract_relocations() override;
LIEF::Binary::functions_t get_abstract_exported_functions() const override;
LIEF::Binary::functions_t get_abstract_imported_functions() const override;
std::vector<std::string> get_abstract_imported_libraries() const override;
inline relocations_t& relocations_list() {
return this->relocations_;
}
inline const relocations_t& relocations_list() const {
return this->relocations_;
}
inline size_t pointer_size() const {
return this->is64_ ? sizeof(uint64_t) : sizeof(uint32_t);
}
bool is64_ = true;
Header header_;
commands_t commands_;
symbols_t symbols_;
// Same purpose as sections_cache_t
libraries_cache_t libraries_;
// The sections are owned by the SegmentCommand object.
// This attribute is a cache to speed-up the iteration
sections_cache_t sections_;
// Same purpose as sections_cache_t
segments_cache_t segments_;
fileset_binaries_t filesets_;
// Cached relocations from segment / sections
mutable relocations_t relocations_;
int32_t available_command_space_ = 0;
// This is used to improve performances of
// offset_to_virtual_address
std::map<uint64_t, SegmentCommand*> offset_seg_;
protected:
uint64_t fat_offset_ = 0;
uint64_t fileset_offset_ = 0;
};
} // namespace MachO
} // namespace LIEF
#endif