CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-lief

Library to instrument executable formats including ELF, PE, Mach-O, and Android formats

Pending
Overview
Eval results
Files

macho-format.mddocs/

Mach-O Format

Native support for Mach-O format used by macOS and iOS executables, frameworks, and universal binaries. Mach-O provides comprehensive Apple platform integration with support for fat binaries, dylib linking, code signing, and Objective-C metadata.

Capabilities

Mach-O Parsing

Parse Mach-O files including universal binaries with architecture-specific extraction.

def parse(filename: str, config: ParserConfig = None) -> Optional[FatBinary]:
    """Parse Mach-O file, returns FatBinary even for single architecture."""

def parse(raw: Sequence[int], config: ParserConfig = None) -> Optional[FatBinary]:
    """Parse Mach-O from raw bytes."""
    
def parse(obj: Union[io.IOBase, os.PathLike], config: ParserConfig = None) -> Optional[FatBinary]:
    """Parse Mach-O from file-like object."""

def parse_from_memory(address: int, config: ParserConfig = None) -> Optional[FatBinary]:
    """Parse Mach-O directly from memory address."""

def is_fat(file: str) -> bool:
    """Check if file is universal binary (fat binary)."""
    
def is_64(file: str) -> bool:
    """Check if Mach-O is 64-bit architecture."""

class ParserConfig:
    parse_dyld_exports: bool
    parse_dyld_bindings: bool
    parse_dyld_rebases: bool
    fix_from_memory: bool
    full_dyldinfo: bool

Usage example:

import lief.MachO as MachO

# Parse universal binary
fat_binary = MachO.parse("/usr/bin/file")

if MachO.is_fat("/usr/bin/file"):
    print("Universal binary detected")
    
# Check architecture
if MachO.is_64("/usr/bin/file"):
    print("64-bit binary")

# Parse with configuration
config = MachO.ParserConfig()
config.parse_dyld_exports = True
config.parse_dyld_bindings = True
fat_binary = MachO.parse("/System/Library/Frameworks/Foundation.framework/Foundation", config)

Universal Binary Management

Handle universal binaries (fat binaries) containing multiple architectures.

class FatBinary:
    binaries: Iterator[Binary]
    
    def size(self) -> int
    def take(self, arch: Header.CPU_TYPE) -> Optional[Binary]
    def add(self, binary: Binary) -> None
    def write(self, output: str) -> None
    def at(self, index: int) -> Binary

def check_layout(binary: Union[Binary, FatBinary]) -> Tuple[bool, str]:
    """Validate Mach-O binary layout and structure."""

Usage example:

fat_binary = MachO.parse("/usr/bin/lipo")

print(f"Number of architectures: {fat_binary.size()}")

# List all architectures
for binary in fat_binary.binaries:
    print(f"Architecture: {binary.header.cpu_type}")
    print(f"Subtype: {binary.header.cpu_subtype}")

# Extract specific architecture
x86_64_binary = fat_binary.take(MachO.Header.CPU_TYPE.X86_64)
if x86_64_binary:
    print("Found x86_64 architecture")
    
# Validate binary layout
is_valid, message = MachO.check_layout(fat_binary)
print(f"Layout valid: {is_valid} - {message}")

Mach-O Binary Operations

Mach-O-specific binary manipulation with Apple platform features.

class Binary(lief.Binary):
    header: Header
    sections: Iterator[Section]
    segments: Iterator[Segment]
    commands: Iterator[LoadCommand]
    symbols: Iterator[Symbol]
    relocations: Iterator[Relocation]
    dyld_info: Optional[DyldInfo]
    uuid: Optional[UUID]
    main_command: Optional[Main]
    dylinker: Optional[DyLinker]
    function_starts: Optional[FunctionStarts]
    source_version: Optional[SourceVersion]
    version_min: Optional[VersionMin]
    thread_command: Optional[ThreadCommand]
    rpath: Iterator[RPathCommand]
    symbol_command: Optional[SymbolCommand]
    dynamic_symbol_command: Optional[DynamicSymbolCommand]
    data_in_code: Optional[DataInCode]
    segment_split_info: Optional[SegmentSplitInfo]
    sub_framework: Optional[SubFramework]
    encryption_info: Optional[EncryptionInfo]
    build_version: Optional[BuildVersion]
    dyld_chained_fixups: Optional[DyldChainedFixups]
    dyld_exports_trie: Optional[DyldExportsTrie]
    two_level_hints: Optional[TwoLevelHints]
    linker_opt_hint: Optional[LinkerOptHint]
    
    def add_section(self, section: Section) -> Section
    def remove_section(self, name: str, clear: bool = False) -> None
    def add_segment(self, segment: Segment) -> Segment
    def remove_signature(self) -> None
    def add_library(self, library: str) -> DylibCommand
    def remove_library(self, library: str) -> None
    def get_segment(self, name: str) -> Optional[Segment]
    def get_section(self, segment_name: str, section_name: str) -> Optional[Section]
    def has_section(self, section_name: str) -> bool
    def has_segment(self, segment_name: str) -> bool
    def can_remove(self, command: LoadCommand) -> bool
    def can_remove_symbol(self, symbol: Symbol) -> bool
    def unexport(self, name: str) -> None
    def remove_command(self, index: int) -> None
    def extend_segment(self, segment: Segment, size: int) -> Optional[Segment]
    def add_exported_function(self, address: int, name: str) -> Symbol
    def add_local_symbol(self, address: int, name: str) -> Symbol

Usage example:

# Extract single architecture for manipulation
fat_binary = MachO.parse("/usr/lib/libSystem.dylib")
binary = fat_binary.at(0)  # Get first architecture

# Add new library dependency
dylib = binary.add_library("libcustom.dylib")
print(f"Added library: {dylib.name}")

# Add new section
section = MachO.Section()
section.name = "__custom"
section.segment_name = "__DATA"
section.content = b"Custom data"
binary.add_section(section)

# Symbol manipulation
symbol = binary.add_exported_function(0x1000, "_custom_function")
print(f"Added symbol: {symbol.name}")

# Remove code signature (for modification)
binary.remove_signature()

Load Commands

Analyze and manipulate Mach-O load commands for dynamic linking and loading.

class LoadCommand(lief.Object):
    command: LOAD_COMMAND_TYPES
    size: int
    command_offset: int

class DylibCommand(LoadCommand):
    name: str
    timestamp: int
    current_version: List[int]
    compatibility_version: List[int]

class Main(LoadCommand):
    entrypoint: int
    stack_size: int

class UUID(LoadCommand):
    uuid: List[int]

class VersionMin(LoadCommand):
    version: List[int]  # [major, minor, patch]
    sdk: List[int]      # [major, minor, patch]

class SourceVersion(LoadCommand):
    version: List[int]  # [a, b, c, d, e]

class BuildVersion(LoadCommand):
    platform: PLATFORMS
    minos: List[int]    # [major, minor, patch]
    sdk: List[int]      # [major, minor, patch]
    tools: Iterator[BuildToolVersion]

class RPathCommand(LoadCommand):
    path: str

class DyLinker(LoadCommand):
    name: str

enum LOAD_COMMAND_TYPES:
    LC_SEGMENT = 0x1
    LC_SYMTAB = 0x2
    LC_SYMSEG = 0x3
    LC_THREAD = 0x4
    LC_UNIXTHREAD = 0x5
    LC_LOADFVMLIB = 0x6
    LC_IDFVMLIB = 0x7
    LC_IDENT = 0x8
    LC_FVMFILE = 0x9
    LC_PREPAGE = 0xa
    LC_DYSYMTAB = 0xb
    LC_LOAD_DYLIB = 0xc
    LC_ID_DYLIB = 0xd
    LC_LOAD_DYLINKER = 0xe
    LC_ID_DYLINKER = 0xf
    LC_PREBOUND_DYLIB = 0x10
    LC_ROUTINES = 0x11
    LC_SUB_FRAMEWORK = 0x12
    LC_SUB_UMBRELLA = 0x13
    LC_SUB_CLIENT = 0x14
    LC_SUB_LIBRARY = 0x15
    LC_TWOLEVEL_HINTS = 0x16
    LC_PREBIND_CKSUM = 0x17
    LC_LOAD_WEAK_DYLIB = 0x80000018
    LC_SEGMENT_64 = 0x19
    LC_ROUTINES_64 = 0x1a
    LC_UUID = 0x1b
    LC_RPATH = 0x8000001c
    LC_CODE_SIGNATURE = 0x1d
    LC_SEGMENT_SPLIT_INFO = 0x1e
    LC_REEXPORT_DYLIB = 0x8000001f
    LC_LAZY_LOAD_DYLIB = 0x20
    LC_ENCRYPTION_INFO = 0x21
    LC_DYLD_INFO = 0x22
    LC_DYLD_INFO_ONLY = 0x80000022
    LC_LOAD_UPWARD_DYLIB = 0x80000023
    LC_VERSION_MIN_MACOSX = 0x24
    LC_VERSION_MIN_IPHONEOS = 0x25
    LC_FUNCTION_STARTS = 0x26
    LC_DYLD_ENVIRONMENT = 0x27
    LC_MAIN = 0x80000028
    LC_DATA_IN_CODE = 0x29
    LC_SOURCE_VERSION = 0x2A
    LC_DYLIB_CODE_SIGN_DRS = 0x2B
    LC_ENCRYPTION_INFO_64 = 0x2C
    LC_LINKER_OPTION = 0x2D
    LC_LINKER_OPTIMIZATION_HINT = 0x2E
    LC_VERSION_MIN_TVOS = 0x2F
    LC_VERSION_MIN_WATCHOS = 0x30
    LC_NOTE = 0x31
    LC_BUILD_VERSION = 0x32
    LC_DYLD_EXPORTS_TRIE = 0x80000033
    LC_DYLD_CHAINED_FIXUPS = 0x80000034

Usage example:

binary = fat_binary.at(0)

print("Load commands:")
for command in binary.commands:
    print(f"  {command.command}: size {command.size}")
    
    # Analyze specific command types
    if isinstance(command, MachO.DylibCommand):
        print(f"    Library: {command.name}")
        print(f"    Version: {'.'.join(map(str, command.current_version))}")
        
    elif isinstance(command, MachO.UUID):
        uuid_str = ''.join(f'{b:02x}' for b in command.uuid)
        print(f"    UUID: {uuid_str}")
        
    elif isinstance(command, MachO.BuildVersion):
        print(f"    Platform: {command.platform}")
        print(f"    Min OS: {'.'.join(map(str, command.minos))}")
        print(f"    SDK: {'.'.join(map(str, command.sdk))}")

Segment and Section Management

Manage Mach-O segments and sections with Apple-specific attributes.

class Segment(lief.Object):
    name: str
    virtual_address: int
    virtual_size: int
    file_size: int
    file_offset: int
    max_protection: int
    init_protection: int
    number_of_sections: int
    flags: int
    sections: Iterator[Section]
    
    def add_section(self, section: Section) -> Section
    def remove_section(self, name: str) -> None

class Section(lief.Section):
    segment_name: str
    address: int
    alignment: int
    relocation_offset: int
    number_of_relocations: int
    flags: int
    type: MACHO_SECTION_TYPES
    reserved1: int
    reserved2: int
    reserved3: int
    segment: Segment
    relocations: Iterator[Relocation]
    
    def has_segment(self) -> bool

enum MACHO_SECTION_TYPES:
    S_REGULAR = 0x0
    S_ZEROFILL = 0x1
    S_CSTRING_LITERALS = 0x2
    S_4BYTE_LITERALS = 0x3
    S_8BYTE_LITERALS = 0x4
    S_LITERAL_POINTERS = 0x5
    S_NON_LAZY_SYMBOL_POINTERS = 0x6
    S_LAZY_SYMBOL_POINTERS = 0x7
    S_SYMBOL_STUBS = 0x8
    S_MOD_INIT_FUNC_POINTERS = 0x9
    S_MOD_TERM_FUNC_POINTERS = 0xa
    S_COALESCED = 0xb
    S_GB_ZEROFILL = 0xc
    S_INTERPOSING = 0xd
    S_16BYTE_LITERALS = 0xe
    S_DTRACE_DOF = 0xf
    S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10
    S_THREAD_LOCAL_REGULAR = 0x11
    S_THREAD_LOCAL_ZEROFILL = 0x12
    S_THREAD_LOCAL_VARIABLES = 0x13
    S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14
    S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15

Usage example:

binary = fat_binary.at(0)

# Analyze segments
for segment in binary.segments:
    print(f"Segment: {segment.name}")
    print(f"  Address: 0x{segment.virtual_address:x}")
    print(f"  Size: {segment.virtual_size}")
    print(f"  Sections: {segment.number_of_sections}")
    
    # Analyze sections in segment
    for section in segment.sections:
        print(f"    Section: {section.name}")
        print(f"      Type: {section.type}")
        print(f"      Address: 0x{section.address:x}")
        print(f"      Size: {section.size}")

# Find specific segment/section
text_segment = binary.get_segment("__TEXT")
if text_segment:
    text_section = binary.get_section("__TEXT", "__text")
    if text_section:
        print(f"__text section at 0x{text_section.address:x}")

Dynamic Linking Information

Analyze dyld (dynamic linker) information for runtime binding and symbol resolution.

class DyldInfo(LoadCommand):
    rebase: memoryview
    bind: memoryview  
    weak_bind: memoryview
    lazy_bind: memoryview
    export_info: memoryview
    
    def show_rebases(self) -> Iterator[DyldBindingInfo]
    def show_bindings(self) -> Iterator[DyldBindingInfo]
    def show_lazy_bindings(self) -> Iterator[DyldBindingInfo]
    def show_weak_bindings(self) -> Iterator[DyldBindingInfo]
    def show_exports(self) -> Iterator[ExportInfo]

class DyldBindingInfo(lief.Object):
    address: int
    library_ordinal: int
    symbol_name: str
    symbol_flags: int
    original_offset: int
    
    def has_segment(self) -> bool
    def has_library(self) -> bool

class ExportInfo(lief.Object):
    node_offset: int
    flags: int
    address: int
    other: int
    symbol_name: str

class DyldChainedFixups(LoadCommand):
    fixups_version: int
    starts_offset: int
    imports_offset: int
    symbols_offset: int
    imports_count: int
    imports_format: DYLD_CHAINED_FORMAT
    symbols_format: int
    
    def bindings(self) -> Iterator[ChainedBindingInfo]

class DyldExportsTrie(LoadCommand):
    data_offset: int
    data_size: int
    
    def exports(self) -> Iterator[ExportInfo]

Usage example:

binary = fat_binary.at(0)

# Analyze dyld information
if binary.dyld_info:
    print("Dyld rebases:")
    for rebase in binary.dyld_info.show_rebases():
        print(f"  0x{rebase.address:x}: {rebase.symbol_name}")
        
    print("Dyld bindings:")
    for binding in binary.dyld_info.show_bindings():
        print(f"  0x{binding.address:x}: {binding.symbol_name} (lib {binding.library_ordinal})")
        
    print("Dyld exports:")
    for export in binary.dyld_info.show_exports():
        print(f"  {export.symbol_name} @ 0x{export.address:x}")

# Check modern chained fixups
if binary.dyld_chained_fixups:
    print("Chained fixups:")
    for binding in binary.dyld_chained_fixups.bindings():
        print(f"  0x{binding.address:x}: {binding.symbol_name}")

Code Signing

Analyze Mach-O code signatures and entitlements for security validation.

class CodeSignature(LoadCommand):
    data_offset: int
    data_size: int
    
    def content(self) -> memoryview

class LinkerOptHint(LoadCommand):
    data_offset: int
    data_size: int

class EncryptionInfo(LoadCommand):
    crypt_offset: int
    crypt_size: int
    crypt_id: int

class EncryptionInfo64(EncryptionInfo):
    pad: int

Usage example:

binary = fat_binary.at(0)

# Find code signature
for command in binary.commands:
    if command.command == MachO.LOAD_COMMAND_TYPES.LC_CODE_SIGNATURE:
        code_sig = MachO.CodeSignature(command)
        print(f"Code signature at offset 0x{code_sig.data_offset:x}")
        print(f"Signature size: {code_sig.data_size} bytes")
        
        # Raw signature data analysis would require additional parsing
        sig_data = code_sig.content()
        print(f"Signature data: {len(sig_data)} bytes")

# Check for encryption
if binary.encryption_info:
    if binary.encryption_info.crypt_id != 0:
        print("Binary is encrypted")
        print(f"Encrypted range: 0x{binary.encryption_info.crypt_offset:x} - {binary.encryption_info.crypt_size}")
    else:
        print("Binary is not encrypted")

Types

class Header(lief.Object):
    magic: MACHO_TYPES
    cpu_type: CPU_TYPE
    cpu_subtype: int
    file_type: FILE_TYPE
    number_of_commands: int
    size_of_commands: int
    flags: int
    reserved: int

enum MACHO_TYPES:
    MH_MAGIC = 0xfeedface
    MH_CIGAM = 0xcefaedfe
    MH_MAGIC_64 = 0xfeedfacf
    MH_CIGAM_64 = 0xcffaedfe
    FAT_MAGIC = 0xcafebabe
    FAT_CIGAM = 0xbebafeca

enum CPU_TYPE:
    ANY = -1
    VAX = 1
    MC680x0 = 6
    X86 = 7
    I386 = 7  # Compatibility
    X86_64 = 0x01000007
    MIPS = 8
    MC98000 = 10
    HPPA = 11
    ARM = 12
    ARM64 = 0x0100000c
    MC88000 = 13
    SPARC = 14
    I860 = 15
    ALPHA = 16
    POWERPC = 18
    POWERPC64 = 0x01000012

enum FILE_TYPE:
    MH_OBJECT = 0x1
    MH_EXECUTE = 0x2
    MH_FVMLIB = 0x3
    MH_CORE = 0x4
    MH_PRELOAD = 0x5
    MH_DYLIB = 0x6
    MH_DYLINKER = 0x7
    MH_BUNDLE = 0x8
    MH_DYLIB_STUB = 0x9
    MH_COMPANION = 0xa
    MH_KEXT_BUNDLE = 0xb

class Symbol(lief.Symbol):
    type: int
    number_of_sections: int
    description: int
    
    def has_export_info(self) -> bool
    def has_binding_info(self) -> bool

class FunctionStarts(LoadCommand):
    data_offset: int
    data_size: int
    functions: List[int]

class DataInCode(LoadCommand):
    data_offset: int
    data_size: int
    entries: Iterator[DataInCodeEntry]

class DataInCodeEntry(lief.Object):
    offset: int
    length: int
    kind: DATA_IN_CODE_TYPES

enum DATA_IN_CODE_TYPES:
    DICE_KIND_DATA = 0x0001
    DICE_KIND_JUMP_TABLE8 = 0x0002
    DICE_KIND_JUMP_TABLE16 = 0x0003
    DICE_KIND_JUMP_TABLE32 = 0x0004
    DICE_KIND_ABS_JUMP_TABLE32 = 0x0005

Install with Tessl CLI

npx tessl i tessl/pypi-lief

docs

android-formats.md

assembly-engine.md

core-operations.md

debug-info.md

elf-format.md

extended-features.md

index.md

macho-format.md

pe-format.md

tile.json