ida_dscu

Apple Dyld Shared Cache (DSC) API.

A DSC: is essentially, a large collection of dylib files (AKA _images_), packed together in an Apple-custom format those are used to limit the amount of overhead at program launch-time, by having a lot of the relocations/resolutions heavylifting already addressed in addition to _images_, the DSC-producing tooling creates specific regions whose purpose is to “link” the various images together. Those regions are known as “branch mappings” (older caches used “branch islands”.) occasionally, you will also find some GOT’s (and possibly “unknown regions”) in the address space of a DSC DSC’s can grow very large in size, and will then be split into multiple _files_ (e.g., iPhone 16 DSC’s have north of 80 files) All-in-all a DSC is an unusual beast, in the sense that hardly makes sense to load it all in an IDA database: you would end up with a a set of mostly-unrelated libraries. Instead, an iterative approach is preferable: load whatever part of the DSC you need, when you need it. This API provides exactly that. # Key concepts/entities images: the dylib files, packed in the DSC unknown regions: portions of the address space that ARE covered by the DSC’s mappings, but are not referred to by any of the known entities. The address space is not missing - it’s our understanding of the content that has a gap. branch islands/branch mappings: stubs, that help stitch together calls between images files: the file(s) that compose the DSC. When a DSC is composed of multiple files, the one that is used as the entrypoint, is called the “toplevel” file. # Secondary concepts/entities file mappings: (to not be confused with branch mappings!) internal, high-level representation of “portions” of a file. Typically files have somewhere between 1…5 mappings region_info_t: a “range”: either a section of an image, or a branch mapping, GOT, unknown region… Typically, an image will have dozens of regions. See below for more info # API Keeping the above concepts in mind, navigating the API should be pretty straightforward: it’s kept simple on-purpose. A couple notes: Use get_dscu_svc() to retrieve the API interface, Initially, the DSC loader will only load the DSC header, Additional images/regions can be loaded through the API, as needed.

Attributes

rt_invalid

Invalid.

rt_image_entity

A subset of an image (segment, section, ...).

rt_island

A branch island.

rt_header

The dyld header.

rt_mapping

A subcache branch mapping.

rt_unknown

A covered cache region whose content we don't (yet) identify.

rt_got

A Global Offset Table.

rt_cache_data

Cache-wide named data (e.g. a linkedit subcache mapping).

DLRF_UNDO_ON_FAILURE

failure to satisfy any part of the request, will revert everything

DLRF_CREATE_UNDO_POINT

should the request create a new undo point (or rely on the last created one and undo to that.)

DLRF_SILENT

don't emit loader_finished notification

DLRF_ASK_CONFIRMATION

ask the user's confirmation before performing the load

DLRF_DEFAULT

default set of flags for DSC load requests

FSF_LOADED_IMAGES_ONLY

Skip export tables of images that have not been loaded yet.

FSF_CASE_INSENSITIVE

Match needle case-insensitively.

FSSF_SCOPE_IMAGES

Limit scanning to images.

FSSF_SCOPE_FILES

Scan entire files.

FSSF_SCOPE_MASK

Scope mask.

FSSF_IMAGES_SCOPE_DATA_SECTIONS

When FSSF_SCOPE_IMAGES, limit scanning to data sections.

FSSF_IMAGES_SCOPE_ALL

When FSSF_SCOPE_IMAGES, scan all sections.

FSSF_IMAGES_SCOPE_MASK

Images scope mask.

FSSF_FILES_INCLUDE_SYMBOLS

When scanning files, include the .symbols pool.

FSSF_FILES_INCLUDE_BRANCH_MAPPINGS

When scanning files, include branch mapping files.

FSSF_FILES_INCLUDE_OTHER

When scanning files, include other adjacent files.

FSSF_CASE_INSENSITIVE

Match needle case-insensitively.

MDF_ALLOW_CPU_MISMATCH

Perform match operation despite the CPU architecture of the external file & the DSC not matching.

MDF_ALLOW_PLATFORM_MISMATCH

Perform match operation despite the platform of the external file & the DSC not matching.

DLF_VALIDATE

Perform validation of persisted layout information.

DLF_VALIDATE_HARD

Do a lot more validating (time-consuming).

DLF_TOPLEVEL_INPUT_PATH

Dump the DSC's (toplevel) input path.

DLF_TOPLEVEL_DETAILS

Dump some additional details about the toplevel file.

DLF_TOPLEVEL

Alias.

DLF_FILES

Dump information about files composing this DSC.

DLF_MAPPINGS

Dump information about high-level mappings described in files composing this DSC.

DLF_IMAGES

Dump information about images (i.e., libraries) found in this DSC.

DLF_IMAGES_DEPENDENCIES

Dump information about each image's dependencies.

DLF_IMAGES_REGIONS

Dump information about each image's known regions.

DLF_ISLANDS

Dump information about branch islands.

DLF_ISLANDS_REGIONS

Dump information about each branch island's known regions.

DLF_GOTS

Dump information about known GOT's in this DSC.

DLF_UNKNOWN_REGIONS

Dump information about the unknown (covered but unidentified) regions of this DSC.

DLF_CACHE_DATA

Dump information about known cache-wide data regions.

DLF_ALL

Classes

symbol_match_vec_t

string_match_vec_t

region_info_vec_t

mapping_coords_vec_t

dependency_match_entry_vec_t

mapping_coords_t

region_info_t

address_info_t

dscu_load_request_t

symbol_match_t

string_match_t

dependency_match_entry_t

dependency_match_result_t

dscu_svc_t

Functions

get_dscu_svc(→ dscu_svc_t *)

Retrieve the "shared cache services".

Module Contents

class ida_dscu.symbol_match_vec_t(*args)

Bases: object

thisown
push_back(*args) symbol_match_t &
pop_back() None
size() int
empty() bool
at(_idx: int) symbol_match_t const &
qclear() None
clear() None
resize(*args) None
grow(*args) None
capacity() int
reserve(cnt: int) None
truncate() None
swap(r: symbol_match_vec_t) None
extract() symbol_match_t *
inject(s: symbol_match_t, len: int) None
begin(*args) qvector< symbol_match_t >::const_iterator
end(*args) qvector< symbol_match_t >::const_iterator
insert(it: symbol_match_t, x: symbol_match_t) qvector< symbol_match_t >::iterator
erase(*args) qvector< symbol_match_t >::iterator
find(*args) qvector< symbol_match_t >::const_iterator
has(x: symbol_match_t) bool
add_unique(x: symbol_match_t) bool
append(x: symbol_match_t) None
extend(x: symbol_match_vec_t) None
front
back
class ida_dscu.string_match_vec_t(*args)

Bases: object

thisown
push_back(*args) string_match_t &
pop_back() None
size() int
empty() bool
at(_idx: int) string_match_t const &
qclear() None
clear() None
resize(*args) None
grow(*args) None
capacity() int
reserve(cnt: int) None
truncate() None
swap(r: string_match_vec_t) None
extract() string_match_t *
inject(s: string_match_t, len: int) None
begin(*args) qvector< string_match_t >::const_iterator
end(*args) qvector< string_match_t >::const_iterator
insert(it: string_match_t, x: string_match_t) qvector< string_match_t >::iterator
erase(*args) qvector< string_match_t >::iterator
find(*args) qvector< string_match_t >::const_iterator
has(x: string_match_t) bool
add_unique(x: string_match_t) bool
append(x: string_match_t) None
extend(x: string_match_vec_t) None
front
back
class ida_dscu.region_info_vec_t(*args)

Bases: object

thisown
push_back(*args) region_info_t &
pop_back() None
size() int
empty() bool
at(_idx: int) region_info_t const &
qclear() None
clear() None
resize(*args) None
grow(*args) None
capacity() int
reserve(cnt: int) None
truncate() None
swap(r: region_info_vec_t) None
extract() region_info_t *
inject(s: region_info_t, len: int) None
begin(*args) qvector< region_info_t >::const_iterator
end(*args) qvector< region_info_t >::const_iterator
insert(it: region_info_t, x: region_info_t) qvector< region_info_t >::iterator
erase(*args) qvector< region_info_t >::iterator
find(*args) qvector< region_info_t >::const_iterator
has(x: region_info_t) bool
add_unique(x: region_info_t) bool
append(x: region_info_t) None
extend(x: region_info_vec_t) None
front
back
class ida_dscu.mapping_coords_vec_t(*args)

Bases: object

thisown
push_back(*args) mapping_coords_t &
pop_back() None
size() int
empty() bool
at(_idx: int) mapping_coords_t const &
qclear() None
clear() None
resize(*args) None
grow(*args) None
capacity() int
reserve(cnt: int) None
truncate() None
swap(r: mapping_coords_vec_t) None
extract() mapping_coords_t *
inject(s: mapping_coords_t, len: int) None
begin(*args) qvector< mapping_coords_t >::const_iterator
end(*args) qvector< mapping_coords_t >::const_iterator
insert(it: mapping_coords_t, x: mapping_coords_t) qvector< mapping_coords_t >::iterator
erase(*args) qvector< mapping_coords_t >::iterator
find(*args) qvector< mapping_coords_t >::const_iterator
has(x: mapping_coords_t) bool
add_unique(x: mapping_coords_t) bool
append(x: mapping_coords_t) None
extend(x: mapping_coords_vec_t) None
front
back
class ida_dscu.dependency_match_entry_vec_t(*args)

Bases: object

thisown
push_back(*args) dependency_match_entry_t &
pop_back() None
size() int
empty() bool
at(_idx: int) dependency_match_entry_t const &
qclear() None
clear() None
resize(*args) None
grow(*args) None
capacity() int
reserve(cnt: int) None
truncate() None
swap(r: dependency_match_entry_vec_t) None
extract() dependency_match_entry_t *
inject(s: dependency_match_entry_t, len: int) None
begin(*args) qvector< dependency_match_entry_t >::const_iterator
end(*args) qvector< dependency_match_entry_t >::const_iterator
insert(it: dependency_match_entry_t, x: dependency_match_entry_t) qvector< dependency_match_entry_t >::iterator
erase(*args) qvector< dependency_match_entry_t >::iterator
find(*args) qvector< dependency_match_entry_t >::const_iterator
has(x: dependency_match_entry_t) bool
add_unique(x: dependency_match_entry_t) bool
append(x: dependency_match_entry_t) None
extend(x: dependency_match_entry_vec_t) None
front
back
ida_dscu.get_dscu_svc() dscu_svc_t *

Retrieve the “shared cache services”. The returned instance is shared, and must not be deleted. Furthermore, the following situations will cause this function to return a nullptr: * we are currently not operating on a shared cache * dscu_bootstrap wasn’t called (by the loader) * an error occurs

Returns:

the services instance, or nullptr

ida_dscu.rt_invalid

Invalid.

ida_dscu.rt_image_entity

A subset of an image (segment, section, …).

ida_dscu.rt_island

A branch island.

ida_dscu.rt_header

The dyld header.

ida_dscu.rt_mapping

A subcache branch mapping.

ida_dscu.rt_unknown

A covered cache region whose content we don’t (yet) identify.

ida_dscu.rt_got

A Global Offset Table.

ida_dscu.rt_cache_data

Cache-wide named data (e.g. a linkedit subcache mapping).

class ida_dscu.mapping_coords_t

Bases: object

thisown
file_index: int16
mapping_index: int16

the toplevel/subcache to which mapping_index applies. 0 means toplevel file

valid() bool
static make_invalid() mapping_coords_t
class ida_dscu.region_info_t

Bases: object

thisown
start: ida_idaapi.ea_t
size: asize_t

Coordinates in address space.

type: region_type_t

Size in bytes.

image_index: int
branch_island_number: int

for rt_image

name: char[40]
swap(r: region_info_t) None

region name (e.g., __text). Not unique

get_range() range_t
class ida_dscu.address_info_t

Bases: object

thisown
region: region_info_t

Region containing the address (type=rt_invalid if not found).

mapping: mapping_coords_t

Mapping that backs the address.

file_offset: uint64

Offset within the on-disk file backing mapping.

valid() bool
class ida_dscu.dscu_load_request_t(*args)

Bases: object

thisown
images: intvec_t

image indexes

islands: intvec_t

branch island numbers

mappings: eavec_t

branch mappings

gots: eavec_t

global offset table ranges

unknown_regions: eavec_t

unknown-region ranges (covered, but unidentified)

cache_data: eavec_t

cache-wide data ranges (e.g. linkedit subcache mappings)

flags: int
add_region(ri: region_info_t) None
add_regions(ris: region_info_vec_t) None
clear() None
empty() bool
ida_dscu.DLRF_UNDO_ON_FAILURE

failure to satisfy any part of the request, will revert everything

ida_dscu.DLRF_CREATE_UNDO_POINT

should the request create a new undo point (or rely on the last created one and undo to that.)

ida_dscu.DLRF_SILENT

don’t emit loader_finished notification

ida_dscu.DLRF_ASK_CONFIRMATION

ask the user’s confirmation before performing the load

ida_dscu.DLRF_DEFAULT

default set of flags for DSC load requests

class ida_dscu.symbol_match_t

Bases: object

thisown
symbol: std::string_view

Matching symbol name; the view is valid for the lifetime of the dscu_svc_t.

ea: ida_idaapi.ea_t

Address of the symbol.

image_index: int

Owning image index, or -1 if the symbol came from the cache’s local symbol table (.symbols).

class ida_dscu.string_match_t

Bases: object

thisown
ea: ida_idaapi.ea_t

Mapped address; BADADDR for non-image hits.

image_index: int

Owning image index, or -1 if the hit came from a non-image blob (.symbols, branch mappings, other adjacent files).

file_index: int

When image_index == -1: the file the hit lives in (see get_file_name()).

file_offset: uint64

Offset within that file (when image_index == -1).

context: str

Bytes around the match, for display.

class ida_dscu.dependency_match_entry_t

Bases: object

thisown
image_name: str

The image name.

image_index: int

The image index in this DSC (-1 if not found).

load_command_type: int

Load command type. One of ACH_LC_*.

class ida_dscu.dependency_match_result_t

Bases: dependency_match_entry_vec_t

thisown
class ida_dscu.dscu_svc_t(*args, **kwargs)

Bases: object

thisown
get_input_file_path() str | None

Retrieve the path to the dyld_shared_cache file on disk.

Returns:

true on success

get_dyld_slide() adiff_t

Return the cumulative ASLR slide applied to the cache.

update_dyld_slide(delta: adiff_t) None

Apply an additional slide delta and reload the cache.

Parameters:

delta – slide increment (added to the current slide)

get_files_names() None
get_file_name(file_index: int) str | None
get_file_index(file_name: str) int
get_file_mappings(file_name: str) bool
get_mapping_range(mapping: mapping_coords_t) bool
locate_address(ea: ida_idaapi.ea_t) address_info_t
get_region(ri: region_info_t, region_index: int, full: bool = True) bool
get_region_by_ea(ri: region_info_t, ea: ida_idaapi.ea_t, out_region_index: size_t * = None, full: bool = True) bool
get_regions(region_indexes: sizevec_t const * = None, full: bool = True) None
get_images_count() int
get_images_names() None
get_image_index(image_name: str) int
get_image_name(image_index: int) str | None
get_image_filename(image_index: int) str | None
get_image_mapping(*args) mapping_coords_t
is_image_loaded(*args) bool
get_image_file_name(*args) bool
get_image_regions(*args) bool
get_image_regions_indexes(*args) bool
get_image_dependencies(*args) bool
get_image_address(image_index: int) ida_idaapi.ea_t
get_image_total_size(*args) uint64
get_image_file_index(*args) int
get_images_dependencies(images_indexes: intvec_t const &, depth: int = 1) bool
is_island_loaded(island_index: int) bool
load_image(*args) bool
load_island(*args) bool
load_branch_mapping(*args) bool
is_mapping_loaded(mapping_addr: ida_idaapi.ea_t) bool
load_got(*args) bool
is_got_loaded(got_addr: ida_idaapi.ea_t) bool
load_unknown_region(*args) bool
is_unknown_region_loaded(ea: ida_idaapi.ea_t) bool
load_cache_data(*args) bool
is_cache_data_loaded(cache_data_addr: ida_idaapi.ea_t) bool
load_regions(regions: dscu_load_request_t) bool
get_load_regions_requests_count() int
get_region_type(region_index: int) region_type_t
query_symbols(range: range_t) bool
query_symbol(ea: ida_idaapi.ea_t) std::string_view
query_exported_symbol(ea: ida_idaapi.ea_t) std::string_view
find_symbol(*args) bool
find_string(*args) bool
has_local_symbols() bool
dmc_ok
dmc_bad_file
dmc_cpu_mismatch
dmc_platform_mismatch
dmc_failed
match_dependencies(path: str, flags: int = 0) dscu_svc_t::depmatch_code_t
dump_layout(*args) None
ida_dscu.FSF_LOADED_IMAGES_ONLY

Skip export tables of images that have not been loaded yet.

ida_dscu.FSF_CASE_INSENSITIVE

Match needle case-insensitively.

ida_dscu.FSSF_SCOPE_IMAGES

Limit scanning to images.

ida_dscu.FSSF_SCOPE_FILES

Scan entire files.

ida_dscu.FSSF_SCOPE_MASK

Scope mask.

ida_dscu.FSSF_IMAGES_SCOPE_DATA_SECTIONS

When FSSF_SCOPE_IMAGES, limit scanning to data sections.

ida_dscu.FSSF_IMAGES_SCOPE_ALL

When FSSF_SCOPE_IMAGES, scan all sections.

ida_dscu.FSSF_IMAGES_SCOPE_MASK

Images scope mask.

ida_dscu.FSSF_FILES_INCLUDE_SYMBOLS

When scanning files, include the .symbols pool.

ida_dscu.FSSF_FILES_INCLUDE_BRANCH_MAPPINGS

When scanning files, include branch mapping files.

ida_dscu.FSSF_FILES_INCLUDE_OTHER

When scanning files, include other adjacent files.

ida_dscu.FSSF_CASE_INSENSITIVE

Match needle case-insensitively.

ida_dscu.MDF_ALLOW_CPU_MISMATCH

Perform match operation despite the CPU architecture of the external file & the DSC not matching.

ida_dscu.MDF_ALLOW_PLATFORM_MISMATCH

Perform match operation despite the platform of the external file & the DSC not matching.

ida_dscu.DLF_VALIDATE

Perform validation of persisted layout information.

ida_dscu.DLF_VALIDATE_HARD

Do a lot more validating (time-consuming).

ida_dscu.DLF_TOPLEVEL_INPUT_PATH

Dump the DSC’s (toplevel) input path.

ida_dscu.DLF_TOPLEVEL_DETAILS

Dump some additional details about the toplevel file.

ida_dscu.DLF_TOPLEVEL

Alias.

ida_dscu.DLF_FILES

Dump information about files composing this DSC.

ida_dscu.DLF_MAPPINGS

Dump information about high-level mappings described in files composing this DSC.

ida_dscu.DLF_IMAGES

Dump information about images (i.e., libraries) found in this DSC.

ida_dscu.DLF_IMAGES_DEPENDENCIES

Dump information about each image’s dependencies.

ida_dscu.DLF_IMAGES_REGIONS

Dump information about each image’s known regions.

ida_dscu.DLF_ISLANDS

Dump information about branch islands.

ida_dscu.DLF_ISLANDS_REGIONS

Dump information about each branch island’s known regions.

ida_dscu.DLF_GOTS

Dump information about known GOT’s in this DSC.

ida_dscu.DLF_UNKNOWN_REGIONS

Dump information about the unknown (covered but unidentified) regions of this DSC.

ida_dscu.DLF_CACHE_DATA

Dump information about known cache-wide data regions.

ida_dscu.DLF_ALL