Mach-O#

class cle.backends.macho.macho.MachO[source]#

Bases: Backend

Mach-O binaries for CLE#

The Mach-O format is notably different from other formats. Specifically:

  • Sections are always part of a segment, so self.sections will be empty.

  • Symbols cannot be categorized like in ELF.

  • Symbol resolution must be handled by the binary.

  • Rebasing in dyld is implemented by adding a small slide to addresses inside the binary, instead of changing the base address of the binary. Consequently, the addresses are absolute rather than relative. CLE requires relative addresses, leading to numerous AT.from_lva().to_rva() calls in this backend.

is_default = True#
MH_MAGIC_64 = 4277009103#
MH_CIGAM_64 = 3489328638#
MH_MAGIC = 4277009102#
MH_CIGAM = 3472551422#
__init__(*args, **kwargs)[source]#
Parameters:
  • binary – The path to the binary to load

  • binary_stream – The open stream to this binary. The reference to this will be held until you call close.

  • is_main_bin – Whether this binary should be loaded as the main executable

symbols: List[Symbol]#
ncmds: int#
sizeofcmds: int#
property min_addr#

This returns the lowest virtual address contained in any loaded segment of the binary.

classmethod check_compatibility(spec, obj)[source]#

Performs a minimal static load of spec and returns whether it’s compatible with other_obj

classmethod is_compatible(stream)[source]#

Determine quickly whether this backend can load an object from this stream

is_thumb_interworking(address)[source]#

Returns true if the given address is a THUMB interworking address

decode_thumb_interworking(address)[source]#

Decodes a thumb interworking address

find_segment_by_name(name)[source]#
do_binding()[source]#
get_string(start)[source]#

Loads a string from the string table

parse_lc_str(f, start, limit: int | None = None)[source]#

Parses a lc_str data structure

Parameters:

limit (int | None) –

S = ~S#
addr_to_offset(addr: int) int | None#
Return type:

Optional[int]

Parameters:

addr (int) –

property arch: Arch#
classmethod check_magic_compatibility(stream: BinaryIO) bool#

Check if a stream of bytes contains the same magic number as the main object

Return type:

bool

Parameters:

stream (BinaryIO) –

close() None#
Return type:

None

contains_addr(addr)#

Is addr in one of the binary’s segments/sections we have loaded? (i.e. is it mapped into memory ?)

property entry#
static extract_soname(path) str | None#

Extracts the shared object identifier from the path, or returns None if it cannot.

Return type:

Optional[str]

property finalizers: List[int]#

Stub function. Like initializers, but with finalizers.

find_loadable_containing(addr)#
find_section_containing(addr: int) cle.backends.region.Section | None#

Returns the section that contains addr or None.

Return type:

Optional[Section]

Parameters:

addr (int) –

find_segment_containing(addr: int) cle.backends.region.Segment | None#

Returns the segment that contains addr, or None.

Return type:

Optional[Segment]

Parameters:

addr (int) –

property image_base_delta#
initial_register_values()#

Deprecated

property initializers: List[int]#

Stub function. Should be overridden by backends that can provide initializer functions that ought to be run before execution reaches the entry point. Addresses should be rebased.

property loader: Loader#
property max_addr: int#

This returns the highest virtual address contained in any loaded segment of the binary.

offset_to_addr(offset: int) int | None#
Return type:

Optional[int]

Parameters:

offset (int) –

rebase(new_base)#

Rebase backend’s regions to the new base where they were mapped by the loader

relocate()#

Apply all resolved relocations to memory.

The meaning of “resolved relocations” is somewhat subtle - there is a linking step which attempts to resolve each relocation, currently only present in the main internal loading function since the calculation of which objects should be available

property sections: Regions[Section]#
set_arch(arch)#
property symbols_by_addr#
thread_registers(thread=None) Dict[str, Any]#

If this backend represents a dump of a running program, it may contain one or more thread contexts, i.e. register files. This method should return the register file for a given thread (as named in Backend.threads) as a dict mapping register names (as seen in archinfo) to numbers. If the thread is not specified, it should return the context for a “default” thread. If there are no threads, it should return an empty dict.

Return type:

Dict[str, Any]

property threads: List#

If this backend represents a dump of a running program, it may contain one or more thread contexts, i.e. register files. This property should contain a list of names for these threads, which should be unique.

imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
get_symbol_by_address_fuzzy(address)[source]#

Locates a symbol by checking the given address against sym.addr, sym.bind_xrefs and sym.symbol_stubs

get_symbol(name, include_stab=False, fuzzy=False)[source]#

Returns all symbols matching name.

Note that especially when include_stab=True there may be multiple symbols with the same name, therefore this method always returns an array.

Parameters:
  • name – the name of the symbol

  • include_stab – Include debugging symbols NOT RECOMMENDED

  • fuzzy – Replace exact match with “contains”-style match

get_symbol_by_insertion_order(idx: int) cle.backends.macho.symbol.AbstractMachOSymbol[source]#
Parameters:

idx (int) – idx when this symbol was inserted

Return type:

AbstractMachOSymbol

Returns:

get_segment_by_name(name)[source]#

Searches for a MachOSegment with the given name and returns it :type name: :param name: Name of the sought segment :return: MachOSegment or None

property segments: Regions[Segment]#
class cle.backends.macho.macho.SymbolList[source]#

Bases: SortedKeyList

Special data structure that extends SortedKeyList to allow looking up a MachO library by name and ordinal quickly without having to iterate over the whole list

__init__(**kwargs)[source]#

Initialize sorted-key list instance.

Optional iterable argument provides an initial iterable of values to initialize the sorted-key list.

Optional key argument defines a callable that, like the key argument to Python’s sorted function, extracts a comparison key from each value. The default is the identity function.

Runtime complexity: O(n*log(n))

>>> from operator import neg
>>> skl = SortedKeyList(key=neg)
>>> skl
SortedKeyList([], key=<built-in function neg>)
>>> skl = SortedKeyList([3, 1, 2], key=neg)
>>> skl
SortedKeyList([3, 2, 1], key=<built-in function neg>)
Parameters:
  • iterable – initial values (optional)

  • key – function used to extract comparison key (optional)

add(value: cle.backends.macho.symbol.AbstractMachOSymbol)[source]#

Add value to sorted-key list.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList(key=neg)
>>> skl.add(3)
>>> skl.add(1)
>>> skl.add(2)
>>> skl
SortedKeyList([3, 2, 1], key=<built-in function neg>)
Parameters:

value (AbstractMachOSymbol) – value to add to sorted-key list

get_by_name_and_ordinal(name: str, ordinal: int, include_stab=False) List[cle.backends.macho.symbol.AbstractMachOSymbol][source]#
Return type:

List[AbstractMachOSymbol]

Parameters:
  • name (str) –

  • ordinal (int) –

DEFAULT_LOAD_FACTOR = 1000#
static __new__(cls, iterable=None, key=<function identity>)#

Create new sorted list or sorted-key list instance.

Optional key-function argument will return an instance of subtype SortedKeyList.

>>> sl = SortedList()
>>> isinstance(sl, SortedList)
True
>>> sl = SortedList(key=lambda x: -x)
>>> isinstance(sl, SortedList)
True
>>> isinstance(sl, SortedKeyList)
True
Parameters:
  • iterable – initial values (optional)

  • key – function used to extract comparison key (optional)

Returns:

sorted list or sorted-key list instance

append(value)#

Raise not-implemented error.

Implemented to override MutableSequence.append which provides an erroneous default implementation.

Raises:

NotImplementedError – use sl.add(value) instead

bisect(value)#

Return an index to insert value in the sorted-key list.

Similar to bisect_left, but if value is already present, the insertion point will be after (to the right of) any existing values.

Similar to the bisect module in the standard library.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedList([5, 4, 3, 2, 1], key=neg)
>>> skl.bisect_right(1)
5
Parameters:

value – insertion index of value in sorted-key list

Returns:

index

bisect_key(key)#

Return an index to insert key in the sorted-key list.

Similar to bisect_key_left, but if key is already present, the insertion point will be after (to the right of) any existing keys.

Similar to the bisect module in the standard library.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedList([5, 4, 3, 2, 1], key=neg)
>>> skl.bisect_key_right(-1)
5
Parameters:

key – insertion index of key in sorted-key list

Returns:

index

bisect_key_left(key)#

Return an index to insert key in the sorted-key list.

If the key is already present, the insertion point will be before (to the left of) any existing keys.

Similar to the bisect module in the standard library.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList([5, 4, 3, 2, 1], key=neg)
>>> skl.bisect_key_left(-1)
4
Parameters:

key – insertion index of key in sorted-key list

Returns:

index

bisect_key_right(key)#

Return an index to insert key in the sorted-key list.

Similar to bisect_key_left, but if key is already present, the insertion point will be after (to the right of) any existing keys.

Similar to the bisect module in the standard library.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedList([5, 4, 3, 2, 1], key=neg)
>>> skl.bisect_key_right(-1)
5
Parameters:

key – insertion index of key in sorted-key list

Returns:

index

bisect_left(value)#

Return an index to insert value in the sorted-key list.

If the value is already present, the insertion point will be before (to the left of) any existing values.

Similar to the bisect module in the standard library.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList([5, 4, 3, 2, 1], key=neg)
>>> skl.bisect_left(1)
4
Parameters:

value – insertion index of value in sorted-key list

Returns:

index

bisect_right(value)#

Return an index to insert value in the sorted-key list.

Similar to bisect_left, but if value is already present, the insertion point will be after (to the right of) any existing values.

Similar to the bisect module in the standard library.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedList([5, 4, 3, 2, 1], key=neg)
>>> skl.bisect_right(1)
5
Parameters:

value – insertion index of value in sorted-key list

Returns:

index

clear()#

Remove all values from sorted-key list.

Runtime complexity: O(n)

copy()#

Return a shallow copy of the sorted-key list.

Runtime complexity: O(n)

Returns:

new sorted-key list

count(value)#

Return number of occurrences of value in the sorted-key list.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList([4, 4, 4, 4, 3, 3, 3, 2, 2, 1], key=neg)
>>> skl.count(2)
2
Parameters:

value – value to count in sorted-key list

Returns:

count

discard(value)#

Remove value from sorted-key list if it is a member.

If value is not a member, do nothing.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList([5, 4, 3, 2, 1], key=neg)
>>> skl.discard(1)
>>> skl.discard(0)
>>> skl == [5, 4, 3, 2]
True
Parameters:

valuevalue to discard from sorted-key list

extend(values)#

Raise not-implemented error.

Implemented to override MutableSequence.extend which provides an erroneous default implementation.

Raises:

NotImplementedError – use sl.update(values) instead

index(value, start=None, stop=None)#

Return first index of value in sorted-key list.

Raise ValueError if value is not present.

Index must be between start and stop for the value to be considered present. The default value, None, for start and stop indicate the beginning and end of the sorted-key list.

Negative indices are supported.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList([5, 4, 3, 2, 1], key=neg)
>>> skl.index(2)
3
>>> skl.index(0)
Traceback (most recent call last):
  ...
ValueError: 0 is not in list
Parameters:
  • value – value in sorted-key list

  • start (int) – start index (default None, start of sorted-key list)

  • stop (int) – stop index (default None, end of sorted-key list)

Returns:

index of value

Raises:

ValueError – if value is not present

insert(index, value)#

Raise not-implemented error.

Raises:

NotImplementedError – use sl.add(value) instead

irange(minimum=None, maximum=None, inclusive=(True, True), reverse=False)#

Create an iterator of values between minimum and maximum.

Both minimum and maximum default to None which is automatically inclusive of the beginning and end of the sorted-key list.

The argument inclusive is a pair of booleans that indicates whether the minimum and maximum ought to be included in the range, respectively. The default is (True, True) such that the range is inclusive of both minimum and maximum.

When reverse is True the values are yielded from the iterator in reverse order; reverse defaults to False.

>>> from operator import neg
>>> skl = SortedKeyList([11, 12, 13, 14, 15], key=neg)
>>> it = skl.irange(14.5, 11.5)
>>> list(it)
[14, 13, 12]
Parameters:
  • minimum – minimum value to start iterating

  • maximum – maximum value to stop iterating

  • inclusive – pair of booleans

  • reverse (bool) – yield values in reverse order

Returns:

iterator

irange_key(min_key=None, max_key=None, inclusive=(True, True), reverse=False)#

Create an iterator of values between min_key and max_key.

Both min_key and max_key default to None which is automatically inclusive of the beginning and end of the sorted-key list.

The argument inclusive is a pair of booleans that indicates whether the minimum and maximum ought to be included in the range, respectively. The default is (True, True) such that the range is inclusive of both minimum and maximum.

When reverse is True the values are yielded from the iterator in reverse order; reverse defaults to False.

>>> from operator import neg
>>> skl = SortedKeyList([11, 12, 13, 14, 15], key=neg)
>>> it = skl.irange_key(-14, -12)
>>> list(it)
[14, 13, 12]
Parameters:
  • min_key – minimum key to start iterating

  • max_key – maximum key to stop iterating

  • inclusive – pair of booleans

  • reverse (bool) – yield values in reverse order

Returns:

iterator

islice(start=None, stop=None, reverse=False)#

Return an iterator that slices sorted list from start to stop.

The start and stop index are treated inclusive and exclusive, respectively.

Both start and stop default to None which is automatically inclusive of the beginning and end of the sorted list.

When reverse is True the values are yielded from the iterator in reverse order; reverse defaults to False.

>>> sl = SortedList('abcdefghij')
>>> it = sl.islice(2, 6)
>>> list(it)
['c', 'd', 'e', 'f']
Parameters:
  • start (int) – start index (inclusive)

  • stop (int) – stop index (exclusive)

  • reverse (bool) – yield values in reverse order

Returns:

iterator

property key#

Function used to extract comparison key from values.

pop(index=-1)#

Remove and return value at index in sorted list.

Raise IndexError if the sorted list is empty or index is out of range.

Negative indices are supported.

Runtime complexity: O(log(n)) – approximate.

>>> sl = SortedList('abcde')
>>> sl.pop()
'e'
>>> sl.pop(2)
'c'
>>> sl
SortedList(['a', 'b', 'd'])
Parameters:

index (int) – index of value (default -1)

Returns:

value

Raises:

IndexError – if index is out of range

remove(value)#

Remove value from sorted-key list; value must be a member.

If value is not a member, raise ValueError.

Runtime complexity: O(log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList([1, 2, 3, 4, 5], key=neg)
>>> skl.remove(5)
>>> skl == [4, 3, 2, 1]
True
>>> skl.remove(0)
Traceback (most recent call last):
  ...
ValueError: 0 not in list
Parameters:

valuevalue to remove from sorted-key list

Raises:

ValueError – if value is not in sorted-key list

reverse()#

Raise not-implemented error.

Sorted list maintains values in ascending sort order. Values may not be reversed in-place.

Use reversed(sl) for an iterator over values in descending sort order.

Implemented to override MutableSequence.reverse which provides an erroneous default implementation.

Raises:

NotImplementedError – use reversed(sl) instead

update(iterable)#

Update sorted-key list by adding all values from iterable.

Runtime complexity: O(k*log(n)) – approximate.

>>> from operator import neg
>>> skl = SortedKeyList(key=neg)
>>> skl.update([3, 1, 2])
>>> skl
SortedKeyList([3, 2, 1], key=<built-in function neg>)
Parameters:

iterable – iterable of values to add

class cle.backends.macho.symbol.AbstractMachOSymbol[source]#

Bases: Symbol

Base class for Mach-O symbols. Defines the minimum common properties all types of mach-o symbols must have

owner: MachO#
__init__(owner: cle.backends.backend.Backend, name: str, relative_addr: int, size: int, sym_type: cle.backends.symbol.SymbolType)[source]#

Not documenting this since if you try calling it, you’re wrong.

Parameters:
property library_ordinal#
property is_stab#
property library_name: bytes | None#
property library_base_name: str | None#
is_common = False#
is_export = False#
is_extern = False#
is_forward = False#
property is_function#

Whether this symbol is a function

is_import = False#
is_local = False#
is_static = False#
is_weak = False#
property linked_addr#
property owner_obj#
property rebased_addr#

The address of this symbol in the global memory space

resolve(obj)#
resolve_forwarder()#

If this symbol is a forwarding export, return the symbol the forwarding refers to, or None if it cannot be found

property subtype: SymbolSubType#

A subclass’ ABI-specific types

property type: SymbolType#

The ABI-agnostic SymbolType. Must be overridden by derived types.

class cle.backends.macho.symbol.SymbolTableSymbol[source]#

Bases: AbstractMachOSymbol

“Regular” symbol. Made to be (somewhat) compatible with backends.Symbol. A SymbolTableSymbol is an entry in the binary’s symbol table.

Note that ELF-specific fields from backends.Symbol are not used and semantics of the remaining fields differ in many cases. As a result most stock functionality from Angr and related libraries WILL NOT WORK PROPERLY on MachOSymbol.

Much of the code below is based on heuristics as official documentation is sparse, consider yourself warned!

The relevant struct with documentation is nlist_64 defined in mach-o/nlist.h

__init__(owner: cle.backends.macho.macho.MachO, symtab_offset, n_strx, n_type, n_sect, n_desc, n_value)[source]#

Not documenting this since if you try calling it, you’re wrong.

Parameters:

owner (MachO) –

is_import = False#
is_export = False#
property library_name: bytes | None#
property segment_name#
property section_name#
property value#
property referenced_symbol_index#

For indirect symbols n_value contains an index into the string table indicating the referenced symbol’s name

is_weak()[source]#

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

property is_function#

Whether this symbol is a function

property is_stab#
property is_private_external#
property is_external#
property sym_type#
property is_common#

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

property common_align#
property reference_type#
property library_ordinal#
property is_no_dead_strip#
property is_desc_discarded#
property is_weak_referenced#
property is_weak_defined#
property is_reference_to_weak#
property is_thumb_definition#
property is_symbol_resolver#
property is_alt_entry#
is_extern = False#
is_forward = False#
is_local = False#
is_static = False#
property library_base_name: str | None#
property linked_addr#
property owner_obj#
property rebased_addr#

The address of this symbol in the global memory space

resolve(obj)#
resolve_forwarder()#

If this symbol is a forwarding export, return the symbol the forwarding refers to, or None if it cannot be found

property subtype: SymbolSubType#

A subclass’ ABI-specific types

property type: SymbolType#

The ABI-agnostic SymbolType. Must be overridden by derived types.

owner: MachO#
class cle.backends.macho.symbol.DyldBoundSymbol[source]#

Bases: AbstractMachOSymbol

The new kind of symbol handling introduced with ios15

owner: MachO#
__init__(owner, name, lib_ordinal)[source]#

Based on the constructor of BindingSymbol

is_import = False#
is_export = False#
property library_name#
property is_function#

Whether this symbol is a function

demangled_name()[source]#
property library_ordinal#
is_common = False#
is_extern = False#
is_forward = False#
is_local = False#
property is_stab#
is_static = False#
is_weak = False#
property library_base_name: str | None#
property linked_addr#
property owner_obj#
property rebased_addr#

The address of this symbol in the global memory space

resolve(obj)#
resolve_forwarder()#

If this symbol is a forwarding export, return the symbol the forwarding refers to, or None if it cannot be found

property subtype: SymbolSubType#

A subclass’ ABI-specific types

property type: SymbolType#

The ABI-agnostic SymbolType. Must be overridden by derived types.

class cle.backends.macho.symbol.BindingSymbol[source]#

Bases: AbstractMachOSymbol

“Binding” symbol. Made to be (somewhat) compatible with backends.Symbol. A BindingSymbol is an imported symbol discovered during the binding process.

Note that ELF-specific fields from backends.Symbol are not used and semantics of the remaining fields differ in many cases. As a result most stock functionality from Angr and related libraries WILL NOT WORK PROPERLY on MachOSymbol.

Much of the code below is based on heuristics as official documentation is sparse, consider yourself warned!

__init__(owner, name, lib_ordinal)[source]#

Not documenting this since if you try calling it, you’re wrong.

is_import = False#
is_export = False#
property library_name#
property is_function#

Whether this symbol is a function

demangled_name()[source]#
property library_ordinal#
is_common = False#
is_extern = False#
is_forward = False#
is_local = False#
property is_stab#
is_static = False#
is_weak = False#
property library_base_name: str | None#
property linked_addr#
property owner_obj#
property rebased_addr#

The address of this symbol in the global memory space

resolve(obj)#
resolve_forwarder()#

If this symbol is a forwarding export, return the symbol the forwarding refers to, or None if it cannot be found

property subtype: SymbolSubType#

A subclass’ ABI-specific types

property type: SymbolType#

The ABI-agnostic SymbolType. Must be overridden by derived types.

owner: MachO#
class cle.backends.macho.section.MachOSection[source]#

Bases: Section

Mach-O Section, only defined within the context of a Mach-O Segment.

  • offset is the offset into the file the region starts

  • vaddr (or just addr) is the virtual address

  • filesize (or just size) is the size of the region in the file

  • memsize (or vsize) is the size of the region when loaded into memory

  • segname is the corresponding segment’s name without padding

  • sectname is the section’s name without padding

  • align is the sections alignment as a power of 2

  • reloff is the file offset to the section’s relocation entries

  • nreloc is the number of relocation entries for this section

  • flags is a bit vector containing per-section flags

  • r1 and r2 are values for the reserved1 and reserved2 fields respectively

__init__(offset, vaddr, size, vsize, segname, sectname, align, reloff, nreloc, flags, r1, r2, parent_segment: cle.backends.macho.segment.MachOSegment | None = None)[source]#
Parameters:
  • name (str) – The name of the section

  • offset (int) – The offset into the binary file this section begins

  • vaddr (int) – The address in virtual memory this section begins

  • size (int) – How large this section is

  • parent_segment (MachOSegment | None) –

filesize: int#
memsize: int#
property type#
property attributes#
property is_readable#

Always true, because sections should always be readable :return:

property is_writable#

Returns the permission of the parent segment, because MachO sections simply inherit that :return:

property is_executable#

Returns the permission of the parent segment, because MachO sections simply inherit that :return:

property only_contains_uninitialized_data#

I actually don’t know if this is true, but it seems like a saner assumption than true :return:

addr_to_offset(addr)#

Convert a virtual memory address into a file offset

contains_addr(addr)#

Does this region contain this virtual address?

contains_offset(offset)#

Does this region contain this offset into the file?

property max_addr#

The maximum virtual address of this region

property max_offset#

The maximum file offset of this region

property min_addr#

The minimum virtual address of this region

min_offset()#

The minimum file offset of this region

offset_to_addr(offset)#

Convert a file offset into a virtual memory address

vaddr: int#
class cle.backends.macho.segment.MachOSegment[source]#

Bases: Segment

Mach-O Segment

  • offset is the offset into the file the region starts

  • vaddr (or just addr) is the virtual address

  • filesize (or just size) is the size of the region in the file

  • memsize (or vsize) is the size of the region when loaded into memory

  • segname is the segment’s name without padding

  • nsect is the number of sections contained in this segment

  • sections is an array of MachOSections

  • flags is a bit vector containing per-segment flags

  • initprot and maxprot are initial and maximum permissions respectively

__init__(offset, vaddr, size, vsize, segname, nsect, sections, flags, initprot, maxprot)[source]#
get_section_by_name(name)[source]#

Searches for a section by name within this segment :type name: :param name: Name of the section :return: MachOSection or None

property is_readable#
property is_writable#
property is_executable#
addr_to_offset(addr)#

Convert a virtual memory address into a file offset

contains_addr(addr)#

Does this region contain this virtual address?

contains_offset(offset)#

Does this region contain this offset into the file?

property max_addr#

The maximum virtual address of this region

property max_offset#

The maximum file offset of this region

property min_addr#

The minimum virtual address of this region

min_offset()#

The minimum file offset of this region

offset_to_addr(offset)#

Convert a file offset into a virtual memory address

vaddr: int#
memsize: int#
filesize: int#
cle.backends.macho.binding.chh(x)[source]#
cle.backends.macho.binding.read_uleb(blob: bytes, offset: int) Tuple[int, int][source]#

Reads a number encoded as uleb128

Return type:

Tuple[int, int]

Parameters:
cle.backends.macho.binding.read_sleb(blob, offset)[source]#

Reads a number encoded as sleb128

class cle.backends.macho.binding.BindingState[source]#

Bases: object

State object

__init__(is_64)[source]#
add_address_ov(address, addend)[source]#

this is a very ugly klugde. It is needed because dyld relies on overflow semantics and represents several negative offsets through BIG ulebs

check_address_bounds()[source]#
class cle.backends.macho.binding.BindingHelper[source]#

Bases: object

Factors out binding logic from MachO. Intended to work in close conjunction with MachO not for standalone use

__init__(binary)[source]#
binary: MachO#
do_normal_bind(blob: bytes)[source]#

Performs non-lazy, non-weak bindings :type blob: bytes :param blob: Blob containing binding opcodes

Parameters:

blob (bytes) –

do_lazy_bind(blob)[source]#

Performs lazy binding

cle.backends.macho.binding.n_opcode_done(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, _i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_dylib_ordinal_imm(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_dylib_ordinal_uleb(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, _i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_dylib_special_imm(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_trailing_flags_imm(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_type_imm(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_addend_sleb(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, _i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_set_segment_and_offset_uleb(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.l_opcode_set_segment_and_offset_uleb(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_add_addr_uleb(s: cle.backends.macho.binding.BindingState, _b: cle.backends.macho.macho.MachO, _i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_do_bind(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, _i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.l_opcode_do_bind(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, _i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_do_bind_add_addr_uleb(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, _i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_do_bind_add_addr_imm_scaled(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, i: int, _blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
cle.backends.macho.binding.n_opcode_do_bind_uleb_times_skipping_uleb(s: cle.backends.macho.binding.BindingState, b: cle.backends.macho.macho.MachO, _i: int, blob: bytes) cle.backends.macho.binding.BindingState[source]#
Return type:

BindingState

Parameters:
class cle.backends.macho.binding.MachORelocation[source]#

Bases: Relocation

Generic Relocation for MachO. It handles relocations that point to symbols

__init__(owner: cle.backends.macho.macho.MachO, symbol: cle.backends.macho.symbol.AbstractMachOSymbol, relative_addr: int, data)[source]#
Parameters:
resolve_symbol(solist, thumb=False, extern_object=None, **kwargs)[source]#
property dest_addr#
property value#
AUTO_HANDLE_NONE = False#
property linked_addr#
property owner_obj#
property rebased_addr#

The address in the global memory space this relocation would like to write to

relocate()#

Applies this relocation. Will make changes to the memory object of the object it came from.

This implementation is a generic version that can be overridden in subclasses.

resolve(obj, **kwargs)#
class cle.backends.macho.binding.MachOChainedFixup[source]#

Bases: Relocation

A special kind of relocation that handles internal pointers in the binary. This was introduced with iOS15+ and is somewhat explained here https://github.com/datatheorem/strongarm/blob/release/chained_fixup_pointers.md

__init__(owner: cle.backends.macho.macho.MachO, relative_addr: int, data)[source]#
Parameters:
  • owner (MachO) –

  • relative_addr (int) – the relative addr where this relocation is located

  • data – the rebase offset relative to the linked base

property value#
resolve_symbol(solist, thumb=False, extern_object=None, **kwargs)[source]#

This relocation has no associated symbol, so we don’t need to resolve it. :type solist: :param solist: :type thumb: :param thumb: :type extern_object: :param extern_object: :type kwargs: :param kwargs: :return:

AUTO_HANDLE_NONE = False#
property dest_addr#
property linked_addr#
property owner_obj#
property rebased_addr#

The address in the global memory space this relocation would like to write to

relocate()#

Applies this relocation. Will make changes to the memory object of the object it came from.

This implementation is a generic version that can be overridden in subclasses.

resolve(obj, **kwargs)#
cle.backends.macho.binding.default_binding_handler(state: cle.backends.macho.binding.BindingState, binary: cle.backends.macho.macho.MachO)[source]#

Binds location to the symbol with the given name and library ordinal

Parameters:
class cle.backends.macho.structs.HelperStruct[source]#

Bases: Structure

Subclass of ctypes.Structure that adds a helpful repr method for debugging

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.DyldImportFormats[source]#

Bases: IntEnum

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L249-L254

DYLD_CHAINED_IMPORT = 1#
DYLD_CHAINED_IMPORT_ADDEND = 2#
DYLD_CHAINED_IMPORT_ADDEND64 = 3#
class cle.backends.macho.structs.DyldChainedPtrFormats[source]#

Bases: IntEnum

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L89-L104

DYLD_CHAINED_PTR_ARM64E = 1#
DYLD_CHAINED_PTR_64 = 2#
DYLD_CHAINED_PTR_32 = 3#
DYLD_CHAINED_PTR_32_CACHE = 4#
DYLD_CHAINED_PTR_32_FIRMWARE = 5#
DYLD_CHAINED_PTR_64_OFFSET = 6#
DYLD_CHAINED_PTR_ARM64E_KERNEL = 7#
DYLD_CHAINED_PTR_64_KERNEL_CACHE = 8#
DYLD_CHAINED_PTR_ARM64E_USERLAND = 9#
DYLD_CHAINED_PTR_ARM64E_FIRMWARE = 10#
DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE = 11#
DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12#
class cle.backends.macho.structs.dyld_chained_ptr_arm64e_auth_rebase[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L128-L138

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_arm64e_auth_bind[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L140-L151

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_arm64e_rebase[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L107-L115

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_arm64e_bind[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L117-L126

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_arm64e_bind24[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L164-L173

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_arm64e_auth_bind24[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L175-L186

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.Arm64e[source]#

Bases: Union

named after the Union Arm64e from dyld MachOLoaded.h https://github.com/apple-opensource/dyld/blob/852.2/dyld3/MachOLoaded.h#L89-L103

authRebase: dyld_chained_ptr_arm64e_auth_rebase#

Structure/Union member

authBind: dyld_chained_ptr_arm64e_auth_bind#

Structure/Union member

rebase: dyld_chained_ptr_arm64e_rebase#

Structure/Union member

bind: dyld_chained_ptr_arm64e_bind#

Structure/Union member

bind24: dyld_chained_ptr_arm64e_bind24#

Structure/Union member

authBind24: dyld_chained_ptr_arm64e_auth_bind24#

Structure/Union member

static check_valid_pointer_format(pointer_format: cle.backends.macho.structs.DyldChainedPtrFormats) bool[source]#

helper to check if a pointer format is relevant for this :type pointer_format: DyldChainedPtrFormats :param pointer_format: :rtype: bool :return:

Parameters:

pointer_format (DyldChainedPtrFormats) –

Return type:

bool

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_64_rebase[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L153-L161

target: int#

Structure/Union member

high8: int#

Structure/Union member

next: int#

Structure/Union member

bind: int#

Structure/Union member

property unpackedTarget#
__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_ptr_64_bind[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L189-L197

ordinal: int#

Structure/Union member

addend: int#

Structure/Union member

next: int#

Structure/Union member

bind: int#

Structure/Union member

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.Generic64[source]#

Bases: Union

named after the Union Generic64 from dyld MachOLoaded.h https://github.com/apple-opensource/dyld/blob/852.2/dyld3/MachOLoaded.h#L105-L111

rebase: dyld_chained_ptr_64_rebase#

Structure/Union member

bind: dyld_chained_ptr_64_bind#

Structure/Union member

static check_valid_pointer_format(pointer_format: cle.backends.macho.structs.DyldChainedPtrFormats) bool[source]#
Return type:

bool

Parameters:

pointer_format (DyldChainedPtrFormats) –

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.ChainedFixupPointerOnDisk[source]#

Bases: Union

the ChainedFixupPointerOnDisk union from dyld MachOLoaded.h https://github.com/apple-opensource/dyld/blob/852.2/dyld3/MachOLoaded.h#L87-L141

generic64: Generic64#

Structure/Union member

arm64e: Arm64e#

Structure/Union member

isBind(pointer_format: cle.backends.macho.structs.DyldChainedPtrFormats) Tuple[int, int] | None[source]#

Port of ChainedFixupPointerOnDisk::isBind(uint16_t pointerFormat, uint32_t& bindOrdinal, int64_t& addend) https://github.com/apple-opensource/dyld/blob/852.2/dyld3/MachOLoaded.cpp#L1098-L1147 Returns None if not a bind (so if struct.isBind() works), :rtype: Optional[Tuple[int, int]] :return:

Parameters:

pointer_format (DyldChainedPtrFormats) –

Return type:

Tuple[int, int] | None

isRebase(pointer_format: cle.backends.macho.structs.DyldChainedPtrFormats, preferredLoadAddress: int) int | None[source]#

port of ChainedFixupPointerOnDisk::isRebase( uint16_t pointerFormat, uint64_t preferedLoadAddress, uint64_t& targetRuntimeOffset) https://github.com/apple-opensource/dyld/blob/852.2/dyld3/MachOLoaded.cpp#L1046-L1096 :type pointer_format: DyldChainedPtrFormats :param pointer_format: :type preferredLoadAddress: int :param preferredLoadAddress: I think that’s just the requested base address :rtype: Optional[int] :return:

Parameters:
Return type:

int | None

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.DyldImportStruct[source]#

Bases: HelperStruct

Meta Struct for the different kind of import structs and the fields they are all guaranteed to have

lib_ordinal: int#
weak_import: bool#
name_offset: int#
static get_struct(pointer: cle.backends.macho.structs.DyldImportFormats) Type[cle.backends.macho.structs.DyldImportStruct][source]#
Return type:

Type[DyldImportStruct]

Parameters:

pointer (DyldImportFormats) –

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_import[source]#

Bases: DyldImportStruct

Struct for symbol format DYLD_CHAINED_IMPORT

__init__(*args, **kwargs)#
__new__(**kwargs)#
static get_struct(pointer: cle.backends.macho.structs.DyldImportFormats) Type[cle.backends.macho.structs.DyldImportStruct]#
Return type:

Type[DyldImportStruct]

Parameters:

pointer (DyldImportFormats) –

lib_ordinal: int#

Structure/Union member

name_offset: int#

Structure/Union member

weak_import: bool#

Structure/Union member

class cle.backends.macho.structs.dyld_chained_import_addend[source]#

Bases: DyldImportStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L264-L271

addend: int#

Structure/Union member

__init__(*args, **kwargs)#
__new__(**kwargs)#
static get_struct(pointer: cle.backends.macho.structs.DyldImportFormats) Type[cle.backends.macho.structs.DyldImportStruct]#
Return type:

Type[DyldImportStruct]

Parameters:

pointer (DyldImportFormats) –

lib_ordinal: int#

Structure/Union member

name_offset: int#

Structure/Union member

weak_import: bool#

Structure/Union member

class cle.backends.macho.structs.dyld_chained_import_addend64[source]#

Bases: DyldImportStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L273-L281

addend: int#

Structure/Union member

__init__(*args, **kwargs)#
__new__(**kwargs)#
static get_struct(pointer: cle.backends.macho.structs.DyldImportFormats) Type[cle.backends.macho.structs.DyldImportStruct]#
Return type:

Type[DyldImportStruct]

Parameters:

pointer (DyldImportFormats) –

lib_ordinal: int#

Structure/Union member

name_offset: int#

Structure/Union member

reserved#

Structure/Union member

weak_import: bool#

Structure/Union member

class cle.backends.macho.structs.dyld_chained_fixups_header[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L36-L46

fixups_version: int#

Structure/Union member

starts_offset: int#

Structure/Union member

imports_offset: int#

Structure/Union member

symbols_offset: int#

Structure/Union member

imports_count: int#

Structure/Union member

imports_format: DyldImportFormats#

Structure/Union member

symbols_format: int#

Structure/Union member

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_starts_in_image[source]#

Bases: Structure

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L48-L54

seg_count: int#

Structure/Union member

seg_info_offset: Array#

Structure/Union member

__init__(*args, **kwargs)#
__new__(**kwargs)#
class cle.backends.macho.structs.dyld_chained_starts_in_segment[source]#

Bases: HelperStruct

https://github.com/apple-opensource/dyld/blob/852.2/include/mach-o/fixup-chains.h#L56-L72

page_size: int#

Structure/Union member

segment_offset: int#

Structure/Union member

max_valid_pointer: int#

Structure/Union member

page_count: int#

Structure/Union member

page_start: int#

Structure/Union member

property pointer_format: DyldChainedPtrFormats#
__init__(*args, **kwargs)#
__new__(**kwargs)#