Skip to main content

Crate darwinscope

Crate darwinscope 

Source
Expand description

§darwinscope: Mach-O / Objective-C / Swift binary parser

A Rust library for statically analyzing Mach-O binaries - the container format used by macOS, iOS, watchOS, tvOS, visionOS, and Mac Catalyst - and the rich Apple-runtime metadata they embed.

Given an arbitrary byte slice, darwinscope decodes:

  • The Mach-O container itself: header, load commands, segments, sections, nlist symbol table, bind / export tries, fat-binary slices, dylib graph, LC_FUNCTION_STARTS, and the data ranges LC_DATA_IN_CODE declares inside code sections.
  • The embedded code-signature SuperBlob: CodeDirectory identifier and Team ID, signing flags, CodeDirectory hash type, embedded CMS signature size, entitlements XML plist (key / value pairs).
  • The Objective-C runtime tables: classes, metaclasses, methods (legacy and small-method-list), instance variables, properties, protocols, categories, and the cross-section reference tables (__objc_selrefs, __objc_classrefs, __objc_superrefs, __objc_protorefs).
  • The Swift 5 type metadata: type descriptors (__swift5_types), protocol descriptors (__swift5_protos), field descriptors (__swift5_fieldmd), protocol conformances (__swift5_proto), and class vtable entries.
  • CoreFoundation constant strings (__cfstring) - both ASCII / UTF-8 (__TEXT,__cstring) and UTF-16 LE (__TEXT,__ustring) bodies.
  • Apple Blocks-runtime metadata - bind sites for _NSConcrete{Global,Stack}Block plus the full Block_descriptor_{1,2,3} decode for global block literals (invoke pointer, signature, layout string).

The crate handles arm64e pointer authentication (PAC) by canonicalising signed pointers before every dereference, and supports both the legacy bind-opcode pointer format and LC_DYLD_CHAINED_FIXUPS chains.

§Motivation

Apple binaries are unusually rich static-analysis targets. Stripped Mach-O dylibs and executables still carry:

  • Obj-C class hierarchy + selectors - required at runtime for message dispatch.
  • Swift type names + field layouts - required for runtime reflection, generic specialization, and protocol witness lookup.
  • Code-signing identity - Team ID and bundle identifier, embedded for system-wide code-signing enforcement.
  • Entitlements XML - explicit list of every privileged API the binary requested.
  • Function entry points - LC_FUNCTION_STARTS ULEB128 table, used by dyld for the unwinder.

This metadata survives stripping because the OS depends on it for linking, dispatch, and code-signing enforcement.

§Architecture

The crate is organised in layers:

  • Container (binary): wraps goblin::mach::MachO and exposes typed views over the structural layer (Header, Segment, Section, Symbol, Import, Export, Dylib, LoadCommand).
  • Code signing (codesign): SuperBlob walker, CodeDirectory parser, entitlements plist decoder.
  • Objective-C (objc): aggregate ObjcRuntime walker with class_t / class_ro_t / method_list_t (legacy + small) / ivar_list_t / property_list_t / protocol_t / category_t decoders, cross-section reference readers, and class ↔ protocol conformance edges.
  • Swift (swift): type / protocol / field / conformance / vtable descriptor walkers.
  • Support (ptrauth, util): pointer-authentication stripping, ULEB128 decoding, virtual-to-file-offset translation.

§Quick start

use darwinscope::MachoBinary;

let bytes = std::fs::read("/usr/bin/codesign")?;
let binary = MachoBinary::parse(&bytes)?;

let header = binary.header();
println!("cputype=0x{:x} ncmds={}", header.cputype(), header.ncmds());
if let Some(uuid) = header.uuid() {
    println!("uuid={:02x?}", uuid);
}

§Status

v0.1 is under active development. The public API will remain unstable until v0.1 ships.

Re-exports§

pub use binary::MachoBinary;
pub use error::Error;
pub use error::Result;
pub use cfstring::CFString;
pub use cfstring::CFStringBody;
pub use cfstring::CFStringEncoding;
pub use cfstring::CFStringIter;
pub use cfstring::CFStringRuntime;
pub use block::BlockDescriptor;
pub use block::BlockIsa;
pub use block::BlockLiteral;
pub use block::BlockReference;
pub use block::BlockRuntime;
pub use block::LiteralIter;
pub use block::ReferenceIter;
pub use objc::ClassIter;
pub use objc::ClassRefIter;
pub use objc::ConformanceEdge;
pub use objc::ConformanceIter;
pub use objc::ImageInfo;
pub use objc::Ivar;
pub use objc::IvarIter;
pub use objc::Method;
pub use objc::MethodIter;
pub use objc::MethodKind;
pub use objc::ObjcCategory;
pub use objc::ObjcClass;
pub use objc::ObjcProtocol;
pub use objc::ObjcRuntime;
pub use objc::ParsedAttribute;
pub use objc::ParsedAttributes;
pub use objc::Property;
pub use objc::PropertyIter;
pub use objc::ProtoRefIter;
pub use objc::ProtocolIter;
pub use objc::ProtocolNameIter;
pub use objc::RefTarget;
pub use objc::SelRefIter;
pub use objc::SuperRefIter;
pub use swift::CaptureDescriptor;
pub use swift::CaptureIter;
pub use swift::Conformance;
pub use swift::ConformanceFlags;
pub use swift::ConformanceIter as SwiftConformanceIter;
pub use swift::ContextDescriptorFlags;
pub use swift::ContextDescriptorKind;
pub use swift::DefaultOverrideEntry;
pub use swift::DefaultOverrideEntryIter;
pub use swift::DefaultOverrideTableHeader;
pub use swift::DynamicReplacementScope;
pub use swift::FieldDescriptor;
pub use swift::FieldDescriptorKind;
pub use swift::FieldIter;
pub use swift::FieldRecord;
pub use swift::FieldRecordFlags;
pub use swift::FieldRecordIter;
pub use swift::ForeignMetadataInit;
pub use swift::GenericContextHeader;
pub use swift::InvertibleProtocolSet;
pub use swift::MetadataInitializationKind;
pub use swift::MethodDescriptorFlags;
pub use swift::ObjcResilientClassStubInfo;
pub use swift::OverrideEntry;
pub use swift::OverrideEntryIter;
pub use swift::OverrideTableHeader;
pub use swift::ParentChain;
pub use swift::ParentContext;
pub use swift::PrespecializationIter;
pub use swift::ProtocolIter as SwiftProtocolIter;
pub use swift::ReplacementIter;
pub use swift::ResilientSuperclass;
pub use swift::SingletonMetadataInit;
pub use swift::SingletonMetadataPointer;
pub use swift::SwiftMethodKind;
pub use swift::SwiftProtocol;
pub use swift::SwiftRuntime;
pub use swift::TypeContextDescriptorFlags;
pub use swift::TypeDescriptor;
pub use swift::TypeIter;
pub use swift::TypeKindBody;
pub use swift::TypeReference;
pub use swift::TypeReferenceKind;
pub use swift::VTableEntry;
pub use swift::VTableHeader;
pub use swift::VTableIter;

Modules§

binary
Top-level MachoBinary view.
block
Apple Blocks runtime metadata.
cfstring
CoreFoundation constant strings (__cfstring).
codesign
Apple Code Signing decoder.
dataincode
LC_DATA_IN_CODE: the linker’s account of data inside code sections.
dylib
Dylib graph (LC_LOAD_*_DYLIB) and load-command summary.
error
Error and result types for darwinscope.
export
Exports - symbols this image makes available to other dylibs.
fixup
LC_DYLD_CHAINED_FIXUPS decoder.
import
Imports - dyld bind targets.
objc
Objective-C 2 / non-fragile-ABI runtime metadata walker.
ptrauth
Pointer authentication and chained-fixup canonicalisation.
segment
Segments and sections (LC_SEGMENT_64 / LC_SEGMENT).
swift
Swift 5 type-metadata walker.
symbol
Nlist symbol table iterator (LC_SYMTAB).
unwind
__TEXT,__unwind_info: the compact unwind table.
util
Shared low-level helpers - ULEB128 / SLEB128 decoding, virtual-to-file-offset translation, primitive byte readers.