or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

android-formats.mdassembly-engine.mdcore-operations.mddebug-info.mdelf-format.mdextended-features.mdindex.mdmacho-format.mdpe-format.md

macho-format.mddocs/

0

# Mach-O Format

1

2

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.

3

4

## Capabilities

5

6

### Mach-O Parsing

7

8

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

9

10

```python { .api }

11

def parse(filename: str, config: ParserConfig = None) -> Optional[FatBinary]:

12

"""Parse Mach-O file, returns FatBinary even for single architecture."""

13

14

def parse(raw: Sequence[int], config: ParserConfig = None) -> Optional[FatBinary]:

15

"""Parse Mach-O from raw bytes."""

16

17

def parse(obj: Union[io.IOBase, os.PathLike], config: ParserConfig = None) -> Optional[FatBinary]:

18

"""Parse Mach-O from file-like object."""

19

20

def parse_from_memory(address: int, config: ParserConfig = None) -> Optional[FatBinary]:

21

"""Parse Mach-O directly from memory address."""

22

23

def is_fat(file: str) -> bool:

24

"""Check if file is universal binary (fat binary)."""

25

26

def is_64(file: str) -> bool:

27

"""Check if Mach-O is 64-bit architecture."""

28

29

class ParserConfig:

30

parse_dyld_exports: bool

31

parse_dyld_bindings: bool

32

parse_dyld_rebases: bool

33

fix_from_memory: bool

34

full_dyldinfo: bool

35

```

36

37

Usage example:

38

```python

39

import lief.MachO as MachO

40

41

# Parse universal binary

42

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

43

44

if MachO.is_fat("/usr/bin/file"):

45

print("Universal binary detected")

46

47

# Check architecture

48

if MachO.is_64("/usr/bin/file"):

49

print("64-bit binary")

50

51

# Parse with configuration

52

config = MachO.ParserConfig()

53

config.parse_dyld_exports = True

54

config.parse_dyld_bindings = True

55

fat_binary = MachO.parse("/System/Library/Frameworks/Foundation.framework/Foundation", config)

56

```

57

58

### Universal Binary Management

59

60

Handle universal binaries (fat binaries) containing multiple architectures.

61

62

```python { .api }

63

class FatBinary:

64

binaries: Iterator[Binary]

65

66

def size(self) -> int

67

def take(self, arch: Header.CPU_TYPE) -> Optional[Binary]

68

def add(self, binary: Binary) -> None

69

def write(self, output: str) -> None

70

def at(self, index: int) -> Binary

71

72

def check_layout(binary: Union[Binary, FatBinary]) -> Tuple[bool, str]:

73

"""Validate Mach-O binary layout and structure."""

74

```

75

76

Usage example:

77

```python

78

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

79

80

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

81

82

# List all architectures

83

for binary in fat_binary.binaries:

84

print(f"Architecture: {binary.header.cpu_type}")

85

print(f"Subtype: {binary.header.cpu_subtype}")

86

87

# Extract specific architecture

88

x86_64_binary = fat_binary.take(MachO.Header.CPU_TYPE.X86_64)

89

if x86_64_binary:

90

print("Found x86_64 architecture")

91

92

# Validate binary layout

93

is_valid, message = MachO.check_layout(fat_binary)

94

print(f"Layout valid: {is_valid} - {message}")

95

```

96

97

### Mach-O Binary Operations

98

99

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

100

101

```python { .api }

102

class Binary(lief.Binary):

103

header: Header

104

sections: Iterator[Section]

105

segments: Iterator[Segment]

106

commands: Iterator[LoadCommand]

107

symbols: Iterator[Symbol]

108

relocations: Iterator[Relocation]

109

dyld_info: Optional[DyldInfo]

110

uuid: Optional[UUID]

111

main_command: Optional[Main]

112

dylinker: Optional[DyLinker]

113

function_starts: Optional[FunctionStarts]

114

source_version: Optional[SourceVersion]

115

version_min: Optional[VersionMin]

116

thread_command: Optional[ThreadCommand]

117

rpath: Iterator[RPathCommand]

118

symbol_command: Optional[SymbolCommand]

119

dynamic_symbol_command: Optional[DynamicSymbolCommand]

120

data_in_code: Optional[DataInCode]

121

segment_split_info: Optional[SegmentSplitInfo]

122

sub_framework: Optional[SubFramework]

123

encryption_info: Optional[EncryptionInfo]

124

build_version: Optional[BuildVersion]

125

dyld_chained_fixups: Optional[DyldChainedFixups]

126

dyld_exports_trie: Optional[DyldExportsTrie]

127

two_level_hints: Optional[TwoLevelHints]

128

linker_opt_hint: Optional[LinkerOptHint]

129

130

def add_section(self, section: Section) -> Section

131

def remove_section(self, name: str, clear: bool = False) -> None

132

def add_segment(self, segment: Segment) -> Segment

133

def remove_signature(self) -> None

134

def add_library(self, library: str) -> DylibCommand

135

def remove_library(self, library: str) -> None

136

def get_segment(self, name: str) -> Optional[Segment]

137

def get_section(self, segment_name: str, section_name: str) -> Optional[Section]

138

def has_section(self, section_name: str) -> bool

139

def has_segment(self, segment_name: str) -> bool

140

def can_remove(self, command: LoadCommand) -> bool

141

def can_remove_symbol(self, symbol: Symbol) -> bool

142

def unexport(self, name: str) -> None

143

def remove_command(self, index: int) -> None

144

def extend_segment(self, segment: Segment, size: int) -> Optional[Segment]

145

def add_exported_function(self, address: int, name: str) -> Symbol

146

def add_local_symbol(self, address: int, name: str) -> Symbol

147

```

148

149

Usage example:

150

```python

151

# Extract single architecture for manipulation

152

fat_binary = MachO.parse("/usr/lib/libSystem.dylib")

153

binary = fat_binary.at(0) # Get first architecture

154

155

# Add new library dependency

156

dylib = binary.add_library("libcustom.dylib")

157

print(f"Added library: {dylib.name}")

158

159

# Add new section

160

section = MachO.Section()

161

section.name = "__custom"

162

section.segment_name = "__DATA"

163

section.content = b"Custom data"

164

binary.add_section(section)

165

166

# Symbol manipulation

167

symbol = binary.add_exported_function(0x1000, "_custom_function")

168

print(f"Added symbol: {symbol.name}")

169

170

# Remove code signature (for modification)

171

binary.remove_signature()

172

```

173

174

### Load Commands

175

176

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

177

178

```python { .api }

179

class LoadCommand(lief.Object):

180

command: LOAD_COMMAND_TYPES

181

size: int

182

command_offset: int

183

184

class DylibCommand(LoadCommand):

185

name: str

186

timestamp: int

187

current_version: List[int]

188

compatibility_version: List[int]

189

190

class Main(LoadCommand):

191

entrypoint: int

192

stack_size: int

193

194

class UUID(LoadCommand):

195

uuid: List[int]

196

197

class VersionMin(LoadCommand):

198

version: List[int] # [major, minor, patch]

199

sdk: List[int] # [major, minor, patch]

200

201

class SourceVersion(LoadCommand):

202

version: List[int] # [a, b, c, d, e]

203

204

class BuildVersion(LoadCommand):

205

platform: PLATFORMS

206

minos: List[int] # [major, minor, patch]

207

sdk: List[int] # [major, minor, patch]

208

tools: Iterator[BuildToolVersion]

209

210

class RPathCommand(LoadCommand):

211

path: str

212

213

class DyLinker(LoadCommand):

214

name: str

215

216

enum LOAD_COMMAND_TYPES:

217

LC_SEGMENT = 0x1

218

LC_SYMTAB = 0x2

219

LC_SYMSEG = 0x3

220

LC_THREAD = 0x4

221

LC_UNIXTHREAD = 0x5

222

LC_LOADFVMLIB = 0x6

223

LC_IDFVMLIB = 0x7

224

LC_IDENT = 0x8

225

LC_FVMFILE = 0x9

226

LC_PREPAGE = 0xa

227

LC_DYSYMTAB = 0xb

228

LC_LOAD_DYLIB = 0xc

229

LC_ID_DYLIB = 0xd

230

LC_LOAD_DYLINKER = 0xe

231

LC_ID_DYLINKER = 0xf

232

LC_PREBOUND_DYLIB = 0x10

233

LC_ROUTINES = 0x11

234

LC_SUB_FRAMEWORK = 0x12

235

LC_SUB_UMBRELLA = 0x13

236

LC_SUB_CLIENT = 0x14

237

LC_SUB_LIBRARY = 0x15

238

LC_TWOLEVEL_HINTS = 0x16

239

LC_PREBIND_CKSUM = 0x17

240

LC_LOAD_WEAK_DYLIB = 0x80000018

241

LC_SEGMENT_64 = 0x19

242

LC_ROUTINES_64 = 0x1a

243

LC_UUID = 0x1b

244

LC_RPATH = 0x8000001c

245

LC_CODE_SIGNATURE = 0x1d

246

LC_SEGMENT_SPLIT_INFO = 0x1e

247

LC_REEXPORT_DYLIB = 0x8000001f

248

LC_LAZY_LOAD_DYLIB = 0x20

249

LC_ENCRYPTION_INFO = 0x21

250

LC_DYLD_INFO = 0x22

251

LC_DYLD_INFO_ONLY = 0x80000022

252

LC_LOAD_UPWARD_DYLIB = 0x80000023

253

LC_VERSION_MIN_MACOSX = 0x24

254

LC_VERSION_MIN_IPHONEOS = 0x25

255

LC_FUNCTION_STARTS = 0x26

256

LC_DYLD_ENVIRONMENT = 0x27

257

LC_MAIN = 0x80000028

258

LC_DATA_IN_CODE = 0x29

259

LC_SOURCE_VERSION = 0x2A

260

LC_DYLIB_CODE_SIGN_DRS = 0x2B

261

LC_ENCRYPTION_INFO_64 = 0x2C

262

LC_LINKER_OPTION = 0x2D

263

LC_LINKER_OPTIMIZATION_HINT = 0x2E

264

LC_VERSION_MIN_TVOS = 0x2F

265

LC_VERSION_MIN_WATCHOS = 0x30

266

LC_NOTE = 0x31

267

LC_BUILD_VERSION = 0x32

268

LC_DYLD_EXPORTS_TRIE = 0x80000033

269

LC_DYLD_CHAINED_FIXUPS = 0x80000034

270

```

271

272

Usage example:

273

```python

274

binary = fat_binary.at(0)

275

276

print("Load commands:")

277

for command in binary.commands:

278

print(f" {command.command}: size {command.size}")

279

280

# Analyze specific command types

281

if isinstance(command, MachO.DylibCommand):

282

print(f" Library: {command.name}")

283

print(f" Version: {'.'.join(map(str, command.current_version))}")

284

285

elif isinstance(command, MachO.UUID):

286

uuid_str = ''.join(f'{b:02x}' for b in command.uuid)

287

print(f" UUID: {uuid_str}")

288

289

elif isinstance(command, MachO.BuildVersion):

290

print(f" Platform: {command.platform}")

291

print(f" Min OS: {'.'.join(map(str, command.minos))}")

292

print(f" SDK: {'.'.join(map(str, command.sdk))}")

293

```

294

295

### Segment and Section Management

296

297

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

298

299

```python { .api }

300

class Segment(lief.Object):

301

name: str

302

virtual_address: int

303

virtual_size: int

304

file_size: int

305

file_offset: int

306

max_protection: int

307

init_protection: int

308

number_of_sections: int

309

flags: int

310

sections: Iterator[Section]

311

312

def add_section(self, section: Section) -> Section

313

def remove_section(self, name: str) -> None

314

315

class Section(lief.Section):

316

segment_name: str

317

address: int

318

alignment: int

319

relocation_offset: int

320

number_of_relocations: int

321

flags: int

322

type: MACHO_SECTION_TYPES

323

reserved1: int

324

reserved2: int

325

reserved3: int

326

segment: Segment

327

relocations: Iterator[Relocation]

328

329

def has_segment(self) -> bool

330

331

enum MACHO_SECTION_TYPES:

332

S_REGULAR = 0x0

333

S_ZEROFILL = 0x1

334

S_CSTRING_LITERALS = 0x2

335

S_4BYTE_LITERALS = 0x3

336

S_8BYTE_LITERALS = 0x4

337

S_LITERAL_POINTERS = 0x5

338

S_NON_LAZY_SYMBOL_POINTERS = 0x6

339

S_LAZY_SYMBOL_POINTERS = 0x7

340

S_SYMBOL_STUBS = 0x8

341

S_MOD_INIT_FUNC_POINTERS = 0x9

342

S_MOD_TERM_FUNC_POINTERS = 0xa

343

S_COALESCED = 0xb

344

S_GB_ZEROFILL = 0xc

345

S_INTERPOSING = 0xd

346

S_16BYTE_LITERALS = 0xe

347

S_DTRACE_DOF = 0xf

348

S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10

349

S_THREAD_LOCAL_REGULAR = 0x11

350

S_THREAD_LOCAL_ZEROFILL = 0x12

351

S_THREAD_LOCAL_VARIABLES = 0x13

352

S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14

353

S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15

354

```

355

356

Usage example:

357

```python

358

binary = fat_binary.at(0)

359

360

# Analyze segments

361

for segment in binary.segments:

362

print(f"Segment: {segment.name}")

363

print(f" Address: 0x{segment.virtual_address:x}")

364

print(f" Size: {segment.virtual_size}")

365

print(f" Sections: {segment.number_of_sections}")

366

367

# Analyze sections in segment

368

for section in segment.sections:

369

print(f" Section: {section.name}")

370

print(f" Type: {section.type}")

371

print(f" Address: 0x{section.address:x}")

372

print(f" Size: {section.size}")

373

374

# Find specific segment/section

375

text_segment = binary.get_segment("__TEXT")

376

if text_segment:

377

text_section = binary.get_section("__TEXT", "__text")

378

if text_section:

379

print(f"__text section at 0x{text_section.address:x}")

380

```

381

382

### Dynamic Linking Information

383

384

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

385

386

```python { .api }

387

class DyldInfo(LoadCommand):

388

rebase: memoryview

389

bind: memoryview

390

weak_bind: memoryview

391

lazy_bind: memoryview

392

export_info: memoryview

393

394

def show_rebases(self) -> Iterator[DyldBindingInfo]

395

def show_bindings(self) -> Iterator[DyldBindingInfo]

396

def show_lazy_bindings(self) -> Iterator[DyldBindingInfo]

397

def show_weak_bindings(self) -> Iterator[DyldBindingInfo]

398

def show_exports(self) -> Iterator[ExportInfo]

399

400

class DyldBindingInfo(lief.Object):

401

address: int

402

library_ordinal: int

403

symbol_name: str

404

symbol_flags: int

405

original_offset: int

406

407

def has_segment(self) -> bool

408

def has_library(self) -> bool

409

410

class ExportInfo(lief.Object):

411

node_offset: int

412

flags: int

413

address: int

414

other: int

415

symbol_name: str

416

417

class DyldChainedFixups(LoadCommand):

418

fixups_version: int

419

starts_offset: int

420

imports_offset: int

421

symbols_offset: int

422

imports_count: int

423

imports_format: DYLD_CHAINED_FORMAT

424

symbols_format: int

425

426

def bindings(self) -> Iterator[ChainedBindingInfo]

427

428

class DyldExportsTrie(LoadCommand):

429

data_offset: int

430

data_size: int

431

432

def exports(self) -> Iterator[ExportInfo]

433

```

434

435

Usage example:

436

```python

437

binary = fat_binary.at(0)

438

439

# Analyze dyld information

440

if binary.dyld_info:

441

print("Dyld rebases:")

442

for rebase in binary.dyld_info.show_rebases():

443

print(f" 0x{rebase.address:x}: {rebase.symbol_name}")

444

445

print("Dyld bindings:")

446

for binding in binary.dyld_info.show_bindings():

447

print(f" 0x{binding.address:x}: {binding.symbol_name} (lib {binding.library_ordinal})")

448

449

print("Dyld exports:")

450

for export in binary.dyld_info.show_exports():

451

print(f" {export.symbol_name} @ 0x{export.address:x}")

452

453

# Check modern chained fixups

454

if binary.dyld_chained_fixups:

455

print("Chained fixups:")

456

for binding in binary.dyld_chained_fixups.bindings():

457

print(f" 0x{binding.address:x}: {binding.symbol_name}")

458

```

459

460

### Code Signing

461

462

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

463

464

```python { .api }

465

class CodeSignature(LoadCommand):

466

data_offset: int

467

data_size: int

468

469

def content(self) -> memoryview

470

471

class LinkerOptHint(LoadCommand):

472

data_offset: int

473

data_size: int

474

475

class EncryptionInfo(LoadCommand):

476

crypt_offset: int

477

crypt_size: int

478

crypt_id: int

479

480

class EncryptionInfo64(EncryptionInfo):

481

pad: int

482

```

483

484

Usage example:

485

```python

486

binary = fat_binary.at(0)

487

488

# Find code signature

489

for command in binary.commands:

490

if command.command == MachO.LOAD_COMMAND_TYPES.LC_CODE_SIGNATURE:

491

code_sig = MachO.CodeSignature(command)

492

print(f"Code signature at offset 0x{code_sig.data_offset:x}")

493

print(f"Signature size: {code_sig.data_size} bytes")

494

495

# Raw signature data analysis would require additional parsing

496

sig_data = code_sig.content()

497

print(f"Signature data: {len(sig_data)} bytes")

498

499

# Check for encryption

500

if binary.encryption_info:

501

if binary.encryption_info.crypt_id != 0:

502

print("Binary is encrypted")

503

print(f"Encrypted range: 0x{binary.encryption_info.crypt_offset:x} - {binary.encryption_info.crypt_size}")

504

else:

505

print("Binary is not encrypted")

506

```

507

508

## Types

509

510

```python { .api }

511

class Header(lief.Object):

512

magic: MACHO_TYPES

513

cpu_type: CPU_TYPE

514

cpu_subtype: int

515

file_type: FILE_TYPE

516

number_of_commands: int

517

size_of_commands: int

518

flags: int

519

reserved: int

520

521

enum MACHO_TYPES:

522

MH_MAGIC = 0xfeedface

523

MH_CIGAM = 0xcefaedfe

524

MH_MAGIC_64 = 0xfeedfacf

525

MH_CIGAM_64 = 0xcffaedfe

526

FAT_MAGIC = 0xcafebabe

527

FAT_CIGAM = 0xbebafeca

528

529

enum CPU_TYPE:

530

ANY = -1

531

VAX = 1

532

MC680x0 = 6

533

X86 = 7

534

I386 = 7 # Compatibility

535

X86_64 = 0x01000007

536

MIPS = 8

537

MC98000 = 10

538

HPPA = 11

539

ARM = 12

540

ARM64 = 0x0100000c

541

MC88000 = 13

542

SPARC = 14

543

I860 = 15

544

ALPHA = 16

545

POWERPC = 18

546

POWERPC64 = 0x01000012

547

548

enum FILE_TYPE:

549

MH_OBJECT = 0x1

550

MH_EXECUTE = 0x2

551

MH_FVMLIB = 0x3

552

MH_CORE = 0x4

553

MH_PRELOAD = 0x5

554

MH_DYLIB = 0x6

555

MH_DYLINKER = 0x7

556

MH_BUNDLE = 0x8

557

MH_DYLIB_STUB = 0x9

558

MH_COMPANION = 0xa

559

MH_KEXT_BUNDLE = 0xb

560

561

class Symbol(lief.Symbol):

562

type: int

563

number_of_sections: int

564

description: int

565

566

def has_export_info(self) -> bool

567

def has_binding_info(self) -> bool

568

569

class FunctionStarts(LoadCommand):

570

data_offset: int

571

data_size: int

572

functions: List[int]

573

574

class DataInCode(LoadCommand):

575

data_offset: int

576

data_size: int

577

entries: Iterator[DataInCodeEntry]

578

579

class DataInCodeEntry(lief.Object):

580

offset: int

581

length: int

582

kind: DATA_IN_CODE_TYPES

583

584

enum DATA_IN_CODE_TYPES:

585

DICE_KIND_DATA = 0x0001

586

DICE_KIND_JUMP_TABLE8 = 0x0002

587

DICE_KIND_JUMP_TABLE16 = 0x0003

588

DICE_KIND_JUMP_TABLE32 = 0x0004

589

DICE_KIND_ABS_JUMP_TABLE32 = 0x0005

590

```