C++

Note

You can also find the Doxygen documentation here: here

inline std::unique_ptr<DyldSharedCache> LIEF::dsc::load(const std::string &path, const std::string &arch = "")

Load a shared cache from a single file or from a directory specified by the path parameter.

In the case where multiple architectures are available in the path directory, the arch parameter can be used to define which architecture should be prefered.

Example:

// From a directory (split caches)
auto cache = LIEF::dsc::load("vision-pro-2.0/");

// From a single cache file
auto cache = LIEF::dsc::load("ios-14.2/dyld_shared_cache_arm64");

// From a directory with multiple architectures
auto cache = LIEF::dsc::load("macos-12.6/", /*arch=*&zwj;/"x86_64h");
inline std::unique_ptr<DyldSharedCache> LIEF::dsc::load(const std::vector<std::string> &files)

Load a shared cache from a list of files.

std::vector<std::string> files = {
  "/tmp/dsc/dyld_shared_cache_arm64e",
  "/tmp/dsc/dyld_shared_cache_arm64e.1"
};
auto cache = LIEF::dsc::load(files);

Cache Processing

Warning

If you aim at extracting several libraries from a dyld shared cache, it is highly recommended to enable caching. Otherwise, performances can be impacted.

bool LIEF::dsc::enable_cache()

Enable globally cache/memoization. One can also leverage this function by setting the environment variable DYLDSC_ENABLE_CACHE to 1

By default, LIEF will use the directory specified by the environment variable DYLDSC_CACHE_DIR as its cache-root directory:

DYLDSC_ENABLE_CACHE=1 DYLDSC_CACHE_DIR=/tmp/my_dir ./my-program

Otherwise, if DYLDSC_CACHE_DIR is not set, LIEF will use the following directory (in this priority):

  1. System or user cache directory

    • macOS: DARWIN_USER_TEMP_DIR / DARWIN_USER_CACHE_DIR + /dyld_shared_cache

    • Linux: ${XDG_CACHE_HOME}/dyld_shared_cache

    • Windows: LOCALAPPDATA%\dyld_shared_cache

  2. Home directory

    • macOS/Linux: $HOME/.dyld_shared_cache

    • Windows: USERPROFILE%\.dyld_shared_cache

See also

LIEF::dsc::DyldSharedCache::enable_caching for a finer granularity

bool LIEF::dsc::enable_cache(const std::string &dir)

Same behavior as enable_cache() but with a user-provided cache directory.

DyldSharedCache

class DyldSharedCache

This class represents a dyld shared cache file.

Public Types

enum class VERSION : uint32_t

This enum wraps the dyld’s git tags for which the structure of dyld shared cache evolved.

Values:

enumerator UNKNOWN = 0
enumerator DYLD_95_3

dyld-95.3 (2007-10-30)

enumerator DYLD_195_5

dyld-195.5 (2011-07-13)

enumerator DYLD_239_3

dyld-239.3 (2013-10-29)

enumerator DYLD_360_14

dyld-360.14 (2015-09-04)

enumerator DYLD_421_1

dyld-421.1 (2016-09-22)

enumerator DYLD_832_7_1

dyld-832.7.1 (2020-11-19)

enumerator DYLD_940

dyld-940 (2021-02-09)

enumerator DYLD_1042_1

dyld-1042.1 (2022-10-19)

enumerator DYLD_1231_3

dyld-1231.3 (2024-09-24)

enumerator UNRELEASED

This value is used for versions of dyld not publicly released or not yet supported by LIEF.

enum class DYLD_TARGET_PLATFORM : uint32_t

Platforms supported by the dyld shared cache.

Values:

enumerator UNKNOWN = 0
enumerator MACOS = 1
enumerator IOS = 2
enumerator TVOS = 3
enumerator WATCHOS = 4
enumerator BRIDGEOS = 5
enumerator IOSMAC = 6
enumerator IOS_SIMULATOR = 7
enumerator TVOS_SIMULATOR = 8
enumerator WATCHOS_SIMULATOR = 9
enumerator DRIVERKIT = 10
enumerator VISIONOS = 11
enumerator VISIONOS_SIMULATOR = 12
enumerator FIRMWARE = 13
enumerator SEPOS = 14
enumerator ANY = 0xFFFFFFFF
enum class DYLD_TARGET_ARCH

Architecture supported by the dyld shared cache.

Values:

enumerator UNKNOWN = 0
enumerator I386
enumerator X86_64
enumerator X86_64H
enumerator ARMV5
enumerator ARMV6
enumerator ARMV7
enumerator ARM64
enumerator ARM64E
using dylib_iterator = iterator_range<Dylib::Iterator>

Iterator over the libraries in the shared cache.

using mapping_info_iterator = iterator_range<MappingInfo::Iterator>

Iterator over the mapping info in the shared cache.

using subcache_iterator = iterator_range<SubCache::Iterator>

Iterator over the split/sub-cache in this main shared cache.

using instructions_iterator = iterator_range<assembly::Instruction::Iterator>

Public Functions

DyldSharedCache(std::unique_ptr<details::DyldSharedCache> impl)
~DyldSharedCache()
std::string filename() const

Filename of the dyld shared file associated with this object.

For instance: dyld_shared_cache_arm64e, dyld_shared_cache_arm64e.62.dyldlinkedit

VERSION version() const

Version of dyld used by this cache.

std::string filepath() const

Full path to the original dyld shared cache file associated with object (e.g. /home/lief/downloads/visionos/dyld_shared_cache_arm64e.42)

uint64_t load_address() const

Based address of this cache.

std::string arch_name() const

Name of the architecture targeted by this cache (x86_64h)

DYLD_TARGET_PLATFORM platform() const

Platform targeted by this cache (e.g. vision-os)

DYLD_TARGET_ARCH arch() const

Architecture targeted by this cache.

std::unique_ptr<Dylib> find_lib_from_va(uint64_t va) const

Find the Dylib that encompasses the given virtual address. It returns a nullptr if a Dylib can’t be found.

std::unique_ptr<Dylib> find_lib_from_path(const std::string &path) const

Find the Dylib whose Dylib::path matches the provided path.

std::unique_ptr<Dylib> find_lib_from_name(const std::string &name) const

Find the Dylib whose filename of Dylib::path matches the provided name.

If multiple libraries have the same name (but with a different path), the first one matching the provided name is returned.

bool has_subcaches() const

True if the subcaches are associated with this cache.

dylib_iterator libraries() const

Return an interator over the libraries embedded in this dyld shared cache.

This iterator implements the random access trait. Thus, one can use iterator_range::size, iterator_range::at, iterator_range::operator[] to a access Dylib at an arbitrary index:

auto libraries = cache.libaries();
for (size_t i = 0; i < libraries.size(); ++i) {
  std::string path = libaries[i]->path();
}
mapping_info_iterator mapping_info() const

Return an interator over the mapping information of this dyld shared cache.

This iterator implements the random access trait. Thus, one can use iterator_range::size, iterator_range::at, iterator_range::operator[] to access a MappingInfo at an arbitrary index:

auto mapping = cache.mapping_info();
for (size_t i = 0; i < mapping.size(); ++i) {
  const uint64_t addr = mapping[i]->address();
}
subcache_iterator subcaches() const

Return an interator over the subcaches associated with this (main) dyld shared cache.

This iterator implements the random access trait. Thus, one can use iterator_range::size, iterator_range::at, iterator_range::operator[] to access a SubCache at an arbitrary index:

auto subcaches = cache.subcaches();
for (size_t i = 0; i < subcaches.size(); ++i) {
  std::unique_ptr<DyldSharedCache> impl = subcaches[i]->cache();
}
instructions_iterator disassemble(uint64_t va) const

Disassemble instructions at the provided virtual address. This function returns an iterator over assembly::Instruction.

std::vector<uint8_t> get_content_from_va(uint64_t va, uint64_t size) const

Return the content at the specified virtual address.

std::unique_ptr<DyldSharedCache> cache_for_address(uint64_t va) const

Find the sub-DyldSharedCache that wraps the given virtual address.

std::unique_ptr<DyldSharedCache> main_cache() const

Return the principal dyld shared cache in the case of multiple subcaches.

std::unique_ptr<DyldSharedCache> find_subcache(const std::string &filename) const

Try to find the DyldSharedCache associated with the filename given in the first parameter.

result<uint64_t> va_to_offset(uint64_t va) const

Convert the given virtual address into an offset.

Warning

If the shared cache contains multiple subcaches, this function needs to be called on the targeted subcache. See cache_for_address() to find the associated subcache.

FileStream &stream() const

Return the stream associated with this dyld shared cache.

FileStream &stream()

Return the stream associated with this dyld shared cache.

void enable_caching(const std::string &target_cache_dir) const

When enabled, this function allows to record and to keep in cache, dyld shared cache information that are costly to access.

For instance, GOT symbols, rebases information, stub symbols, …

It is highly recommended to enable this function when processing a dyld shared cache several times or when extracting a large number of LIEF::dsc::Dylib with enhanced extraction options (e.g. Dylib::extract_opt_t::fix_branches)

One can enable caching by calling this function:

auto dyld_cache = LIEF::dsc::load("macos-15.0.1/");
dyld_cache->enable_caching("/home/user/.cache/lief-dsc");

One can also enable this cache optimization globally using the function: LIEF::dsc::enable_cache or by setting the environment variable DYLDSC_ENABLE_CACHE to 1.

void flush_cache() const

Flush internal information into the on-disk cache (see: enable_caching)

Public Static Functions

static std::unique_ptr<DyldSharedCache> from_path(const std::string &path, const std::string &arch = "")

See the load functions for the details.

static std::unique_ptr<DyldSharedCache> from_files(const std::vector<std::string> &path)

See the load functions for the details.

Dylib

class Dylib

This class represents a library embedded in a dyld shared cache. It mirrors the original dyld_cache_image_info structure.

Public Functions

Dylib(std::unique_ptr<details::Dylib> impl)
~Dylib()
std::string path() const

Original path of the library (e.g. /usr/lib/libcryptex.dylib)

uint64_t address() const

In-memory address of the library.

uint64_t modtime() const

Modification time of the library matching stat.st_mtime, or 0.

uint64_t inode() const

File serial number matching stat.st_ino or 0.

Note that for shared cache targeting iOS, this value can hold a hash of the path (if modtime is set to 0)

uint64_t padding() const

Padding alignment value (should be 0)

std::unique_ptr<LIEF::MachO::Binary> get(const extract_opt_t &opt = extract_opt_t()) const

Get a MachO::Binary representation for this Dylib.

One can use this function to write back the Mach-O binary on the disk:

dyld_cache->libraries()[12]->get()->write("liblockdown.dylib");
struct extract_opt_t

This structure is used to tweak the extraction process while calling Dylib::get. These options allow to deoptimize the dylib and get an accurate representation of the origin Mach-O binary.

Public Functions

extract_opt_t()

Public Members

bool pack = true

Whether the segment’s offsets should be packed to avoid an in-memory size while writing back the binary.

Note

This option does not have an impact on the performances

bool fix_branches = false

Fix call instructions that target addresses outside the current dylib virtual space.

Warning

Enabling this option can have a significant impact on the performances. Make sure to enable the internal cache mechanism: LIEF::dsc::enable_cache or LIEF::dsc::DyldSharedCache::enable_caching

bool fix_memory = false

Fix memory accesses performed outside the dylib’s virtual space.

Warning

Enabling this option can have a significant impact on the performances. Make sure to enable the internal cache mechanism: LIEF::dsc::enable_cache or LIEF::dsc::DyldSharedCache::enable_caching

bool fix_relocations = false

Recover and fix relocations.

Warning

Enabling this option can have a significant impact on the performances. Make sure to enable the internal cache mechanism: LIEF::dsc::enable_cache or LIEF::dsc::DyldSharedCache::enable_caching

bool fix_objc = false

Fix Objective-C information.

LIEF::result<bool> create_dyld_chained_fixup_cmd

Whether the LC_DYLD_CHAINED_FIXUPS command should be (re)created.

If this value is not set, LIEF will add the command only if it’s meaningful regarding the other options

class Iterator : public LIEF::iterator_facade_base<Iterator, std::random_access_iterator_tag, std::unique_ptr<Dylib>, std::ptrdiff_t, Dylib*, std::unique_ptr<Dylib>>

Dylib Iterator.

Public Types

using implementation = details::DylibIt

Public Functions

Iterator(std::unique_ptr<details::DylibIt> impl)
Iterator(const Iterator&)
Iterator &operator=(const Iterator&)
Iterator(Iterator&&) noexcept
Iterator &operator=(Iterator&&) noexcept
~Iterator()
bool operator<(const Iterator &rhs) const
std::ptrdiff_t operator-(const Iterator &R) const
Iterator &operator+=(std::ptrdiff_t n)
Iterator &operator-=(std::ptrdiff_t n)
std::unique_ptr<Dylib> operator*() const

Friends

friend bool operator==(const Iterator &LHS, const Iterator &RHS)
inline friend bool operator!=(const Iterator &LHS, const Iterator &RHS)

MappingInfo

class MappingInfo

This class represents a dyld_cache_mapping_info entry.

It provides information about the relationshiop between on-disk shared cache and in-memory shared cache.

Public Functions

MappingInfo(std::unique_ptr<details::MappingInfo> impl)
~MappingInfo()
uint64_t address() const

The in-memory address where this dyld shared cache region is mapped.

uint64_t size() const

Size of the region being mapped.

inline uint64_t end_address() const

End virtual address of the region.

uint64_t file_offset() const

On-disk file offset.

uint32_t max_prot() const

Max memory protection.

uint32_t init_prot() const

Initial memory protection.

class Iterator : public LIEF::iterator_facade_base<Iterator, std::random_access_iterator_tag, std::unique_ptr<MappingInfo>, std::ptrdiff_t, MappingInfo*, std::unique_ptr<MappingInfo>>

MappingInfo Iterator.

Public Types

using implementation = details::MappingInfoIt

Public Functions

Iterator(std::unique_ptr<details::MappingInfoIt> impl)
Iterator(const Iterator&)
Iterator &operator=(const Iterator&)
Iterator(Iterator&&) noexcept
Iterator &operator=(Iterator&&) noexcept
~Iterator()
bool operator<(const Iterator &rhs) const
std::ptrdiff_t operator-(const Iterator &R) const
Iterator &operator+=(std::ptrdiff_t n)
Iterator &operator-=(std::ptrdiff_t n)
std::unique_ptr<MappingInfo> operator*() const

Friends

friend bool operator==(const Iterator &LHS, const Iterator &RHS)
inline friend bool operator!=(const Iterator &LHS, const Iterator &RHS)

SubCache

class SubCache

This class represents a subcache in the case of large/split dyld shared cache.

It mirror (and abstracts) the original dyld_subcache_entry / dyld_subcache_entry_v1

Public Functions

SubCache(std::unique_ptr<details::SubCache> impl)
~SubCache()
sc_uuid_t uuid() const

The uuid of the subcache file.

uint64_t vm_offset() const

The offset of this subcache from the main cache base address.

std::string suffix() const

The file name suffix of the subCache file (e.g. .25.data, .03.development)

std::unique_ptr<const DyldSharedCache> cache() const

The associated DyldSharedCache object for this subcache.

Friends

friend std::ostream &operator<<(std::ostream &os, const SubCache &subcache)
class Iterator : public LIEF::iterator_facade_base<Iterator, std::random_access_iterator_tag, std::unique_ptr<SubCache>, std::ptrdiff_t, SubCache*, std::unique_ptr<SubCache>>

SubCache Iterator.

Public Types

using implementation = details::SubCacheIt

Public Functions

Iterator(std::unique_ptr<details::SubCacheIt> impl)
Iterator(const Iterator&)
Iterator &operator=(const Iterator&)
Iterator(Iterator&&) noexcept
Iterator &operator=(Iterator&&) noexcept
~Iterator()
bool operator<(const Iterator &rhs) const
std::ptrdiff_t operator-(const Iterator &R) const
Iterator &operator+=(std::ptrdiff_t n)
Iterator &operator-=(std::ptrdiff_t n)
std::unique_ptr<SubCache> operator*() const

Friends

friend bool operator==(const Iterator &LHS, const Iterator &RHS)
inline friend bool operator!=(const Iterator &LHS, const Iterator &RHS)