2. Objective-C ABI#

The following sections are going to introduce the Objective-C binary structure with its binary sections and structs. As each struct definition is mapped to an actual Python class, they will be displayed together. Furthermore, this ABI implementation explicitly supports 32-bit and 64-bit binaries - the struct will be chosen according to the currently used binary.

To get more information about the type encoding used by Apple in Objective-C binaries, please refer to their website: Type Encodings.

Note

All classes documented here will refer to a 64-bit architecture binary if both 64-bit and 32-bit structures don’t differ in the number of their fields (only pointer size has changed). For a list of annotated types, please refer to Types.

2.1. Objects#

The base for all Objective-C structs that can be instantiated will be the TargetObjCObjectRaw64 and TargetObjCObjectRaw32. Structs extending an Objective-C object structure store a pointer to the class/protocol or category definition of which the object of this struct is an instance (also known as an isa pointer). For instance, the protocol A will store a reference to the protocol class A which stores class-level properties and methods.

class umbrella.objc.TargetObjCObjectRaw64(isa_storage: int)[source]#

Base struct for all definitions that may store a class definition.

isa_storage: uintptr_t#

Class storage or pointer

2.2. Classes#

According to Apple’s developer documentation, “a class describes the behavior and properties common to any particular type of object”. [1] They can be defined as blueprints for actual objects. Internally, classes first define their super class, cache, an optional vtable and their data as references with pointers.

class umbrella.objc.TargetObjCClassRaw64[source]#

The basic structure of Objective-C class interfaces.

superclass: uintptr_t#

The super class of this Objective-C class interface.

cache: uintptr_t#

Internal cache pointer (unused)

vtable: uintptr_t#

Reference to the internal VTable of this class interface (unused).

data: ClassDataBits64#

A mangled reference to the actual class data.

Each class data reference stores additional information in its top bits. Therefore, an additional data structure is used to determine the actual location of the class data.

class umbrella.objc.ClassDataBits64[source]#

Additional data structure to measure the referenced class data location.

bits: int#

The actual bits of a reference

ptr: int = False#

The ‘decoded’ pointer (computed at runtime)

is_swift() bool#

Returns whether the referenced class data points to a swift class.

Returns:

whether the class is a swift class

Return type:

bool

2.2.1. Class Data#

The internal class data is responsible for providing information about the defined instance variables, methods and properties as well as the conforming protocols. Note that the following class describes the class data on 64-bit architectures. It includes an additional field named reserved.

class umbrella.objc.TargetClassDataRaw64[source]#

Struct equivalent to class_data_ro_t.

flags: uint32_t#

class flags (most common is_swift and has_cxx_dtor)

instance_start: uint32_t#

The instance starting point (unused)

instance_end: uint32_t#

The instance end point (unused)

reserved: uint32_t#

Additional field on 64-bit systems (unused)

ivar_layout: uintptr_t#

A reference to the IVar layout - always zero (unused)

name: uintptr_t#

Pointer to the source-written name of this class

base_methods: uintptr_t#

A reference to all defined instance methods

base_protocols: uintptr_t#

A reference to all conformed protocols

ivars: uintptr_t#

A pointer to a list of defined instance variables

weak_ivar_layout: uintptr_t#

Reference to the weak instance variable layout (unused)

base_properties: uintptr_t#

A pointer to a list of all instance properties

2.2.2. Class Model#

After parsing the data, the Python API will create an instance of ObjCClass which stores all relevant information about the class.

class umbrella.objc.ObjCClass[source]#

The Class [2] runtime type implementation. This class may also represent an encoded Swift class, but it won’t store Swift type information. These should be retrieved via a :class`SwiftRuntime` instance.

All list attributes with a size greater than one will be set as a BoundListIterator and are therefore lazy within their usage.

raw: TargetObjCClassRaw32 | TargetObjCClassRaw64#

parsed raw class struct

raw_data: TargetClassDataRaw32 | TargetClassDataRaw64#

parsed raw class data

name: str#

the name of this class

super_class: ObjCClass | None = None#

the super class (optional)

metaclass: ObjCClass | None = None#

the class of which this one is an instance

methods: BoundListIterator[ObjCMethod] | None = None#

an iterator over all defined methods

ivars: BoundListIterator[ObjCIVar] | None = None#

all defined instance variables

protocols: BoundListIterator[ObjCProtocol] | None = None#

a list of all conformed protocols

properties: BoundListIterator[ObjCProperty] | None = None#

a list of instance properties

2.3. Methods#

“Methods are the primary way an object manipulates and provides access to its state”. [3] Internally, they are represented through a simple struct that stores the method’s name, signature and implementation address.

class umbrella.objc.TargetMethodRaw64[source]#

Objective-C method description.

name: uintptr_t#

The name of this method.

signature: uintptr_t#

The types of this method.

impl: uintptr_t#

The absolute implementation address

class umbrella.objc.ObjCMethod[source]#

The Method runtime type implementation. See TargetMethodRaw64 or TargetMethodRaw32 for detailed information about the internal structure of an objc-method.

Hint

You can simply generate a fully qualified signature of this method by using decode_desc(). It will produce something like this:

>>> method = ObjCMethod(name="someMethod", signature="B16@0:8", ...)
>>> method.decode_desc()
'(BOOL)someMethod'
raw: TargetMethodRaw32 | TargetMethodRaw64#

parsed raw structure

name: str#

the method’s name (selector string)

signature: str#

the method’s signature (encoded)

is_class_method: bool#

whether this method is a class method

is_small: bool#

whether this method stores relative pointers

decode_desc() str[source]#

Decodes the signature of this method.

>>> method = ObjCMethod(name="foo:bar:", signature="q32@0:8@16q24", ...)
>>> method.decode_desc()
'(long long)foo:(id) bar:(long long)'
Returns:

the decoded signature.

Return type:

str

get_impl() int[source]#

Returns the address for the implementation of this method

Returns:

the implementation address

Return type:

int

Note

Small methods store pointers (int32_t) relative to the struct’s address.

2.4. Properties#

Properties in Objective-C provide a public access interface to a class. Their internal structure is even more simple than the previously introduced method structure: They just store the name and attributes as a string.

class umbrella.objc.TargetPropertyRaw64[source]#

Raw layout of an Objective-C property.

name: uintptr_t#

the property’s name (reference)

attributes: uintptr_t#

its attributes (reference)

class umbrella.objc.ObjCProperty[source]#

The Property [4] runtime type implementation. TargetPropertyRaw64 or TargetPropertyRaw32 provide more information about the raw structure.

raw: TargetPropertyRaw32 | TargetPropertyRaw64#

the parsed structure

name: str#

the property’s name

attributes: str#

its attributes

parent: ObjCClass | ObjCCategory | ObjCProtocol | None#

the parent context

decode_attributes() str[source]#

Decodes this property into a fully representative string.

Example:

>>> prop = ObjCProperty(name="foo", attributes='T@"NSMutableSet",&,N,V_foo', ...)
>>> prop.decode_attributes()
'@property (retain, nonatomic) NSMutableSet foo'
Returns:

the decoded attributes as string

Return type:

str

2.5. Instance Variables#

The primary way to maintain the internal state of an object can be done by defining instance variables.

class umbrella.objc.TargetIVarRaw64[source]#

Raw IVar structure.

offset: int32_t#

offset was originally 64-bit on some x86_64 platforms. We read and write only 32 bits of it. Some metadata provides all 64 bits. This is harmless for unsigned little-endian values.

remainder: uint32_t#

unused (only 64-bit)

name: uintptr_t#

the name of this ivar

type: uintptr_t#

its type

alignment: uint32_t#

the internal alignment

size: uint32_t#

the internal ivar size in memory

Warning

Be aware that sometimes the name and encoded type of an instance variable must be swapped before using them - no idea why. Automatic swapping will be applied while parsing IVars.

class umbrella.objc.ObjCIVar[source]#

The Ivar runtime type implementation. For more information about its raw structure, see TargetIVarRaw64 or TargetIVarRaw32.

Note

Ivar objects will store their mangled/encoded name by default. It can be decoded using decode_type().

raw: TargetIVarRaw32 | TargetIVarRaw64#

parsed raw structure

name: str#

the name of this ivar

type_name: str#

the encoded type-name of this ivar

parent: ObjCClass | ObjCCategory | ObjCProtocol | None#

the parent context

decode_type() str[source]#

Decodes the type-name of this ivar using the objc.decoder.

Returns:

the decoded type name

Return type:

str

2.6. Protocols#

Objective-C protocols are used to declare properties and methods that are independent from any other class. They can be seen as interfaces in terms of the Java language, except this type can define required and optional methods, both class and instance ones. Fortunately

class umbrella.objc.TargetProtocolRaw64[source]#

Raw protocol struct.

name: uintptr_t#

the protocol’s name (reference)

protocols: uintptr_t#

a reference to a list of protocols this one conforms to

required_instance_methods: uintptr_t#

a list of required instance methods (list reference)

required_class_methods: uintptr_t#

a list of required class methods (list reference)

optional_instance_methods: uintptr_t#

a list of optional instance methods (list reference)

optional_class_methods: uintptr_t#

a list of optional class methods (list reference)

instance_properties: uintptr_t#

all defined instance properties (list reference)

size: uint32_t#

the size of this struct

flags: uint32_t#

additional flags for this protocol

class umbrella.objc.ObjCProtocol[source]#

Runtime type of an Objective-C protocol.

raw: TargetProtocolRaw32 | TargetProtocolRaw64#

the parsed raw structure

name: str#

the parsed protocol name

parent: ObjCClass | ObjCCategory | ObjCProtocol | None#

the parent context

protocols: BoundListIterator[ObjCProtocol] | None = None#

all conformed protocols

required_instance_methods: BoundListIterator[ObjCMethod] | None = None#

a list of required instance methods

required_class_methods: BoundListIterator[ObjCMethod] | None = None#

a list of required class methods

optional_instance_methods: BoundListIterator[ObjCMethod] | None = None#

a list of optional instance methods

optional_class_methods: BoundListIterator[ObjCMethod] | None = None#

a list of optional class methods

instance_properties: BoundListIterator[ObjCProperty] | None = None#

a list of defined instance properties

2.7. Categories and Extensions#

Categories in Objective-C add methods (and properties) to an existing class. There are two types of categories: Anonymous Categories (Extensions) and default Categories.

class umbrella.objc.TargetCategoryRaw64[source]#

Raw struct of an Objective-C Category

name: uintptr_t#

the catgory’s name

base_class: uintptr_t#

a reference to the base class of this category

instance_methods: uintptr_t#

a reference to a list of instance methods

class_methods: uintptr_t#

a reference to all defined additional class methods

base_protocols: uintptr_t#

a reference to all additional conformed protocols

instance_properties: uintptr_t#

pointer to a property list structure

class umbrella.objc.ObjCCategory[source]#

The Category runtime type implementation. More information about the raw structures can be taken from TargetCategoryRaw64 and TargetCategoryRaw32.

Note

Categories with no base class are extensions.

raw: TargetCategoryRaw32 | TargetCategoryRaw64#

the parsed raw structure

name: str#

the parsed category name

base_class: ObjCClass | None = None#

optional base class

class_methods: BoundListIterator[ObjCMethod] | None = None#

defined class methods

instance_methods: BoundListIterator[ObjCMethod] | None = None#

defined instance methods

protocols: BoundListIterator[ObjCProtocol] | None = None#

all conformed protocols

properties: BoundListIterator[ObjCProperty] | None = None#

all defined additional properties

is_extension() bool[source]#

Returns whether this categoriy is an extension.

Returns:

true, if this category has no base class.

Return type:

bool

For a detailed overview of all structs mentioned in this document, please refer to runtime-new.h of the official Apple Source Code.

TODO: Metadata, Dumper

Footnotes