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.
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
- methods: BoundListIterator[ObjCMethod] | None = None#
an iterator over all defined methods
- 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
orTargetMethodRaw32
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
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
orTargetPropertyRaw32
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
orTargetIVarRaw32
.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
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
andTargetCategoryRaw32
.Note
Categories with no base class are extensions.
- raw: TargetCategoryRaw32 | TargetCategoryRaw64#
the parsed raw structure
- name: str#
the parsed category name
- 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
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