Mach-O Format
macOS executables and dynamic libraries are compiled into Mach-O (Mach Object) files, a binary format that defines how code and data are organized for execution. Understanding Mach-O is critical for red teaming, as it underpins how binaries load, execute, and persist on macOS systems. This section provides an overview of the Mach-O structure and its role in execution.
Header and File Type¶
The Mach-O header contains metadata about the binary, including:
- CPU type (e.g., x86_64, arm64, or universal binaries with multiple architectures).
- File type (e.g., MH_EXECUTE for executables, MH_DYLIB for dynamic libraries).
- Magic number (e.g., 0xfeedface for 32-bit, 0xfeedfacf for 64-bit).
- Number of load commands (instructions for the loader).
Example:
Load Commands¶
Load commands direct the macOS loader on how to map the binary into memory. Common types include:
- LC_SEGMENT: Defines memory segments (e.g., __TEXT for code, __DATA for data).
- LC_SYMTAB: Symbol table for debugging and linking.
- LC_DYLD_INFO: Dynamic linking information (used by dyld to resolve symbols).
Example:
$ otool -l /bin/ls
...
Load command 1:
cmd LC_SEGMENT_64
cmdsize 140
segname __TEXT
vmaddr 0x0000000000001000
vmsize 0x000000000000f000
fileoff 0x0000000000000000
filesize 0x000000000000f000
maxprot 0x0000000000000007
initprot 0x0000000000000007
nsects 1
flags 0x00000000
Segments and Sections¶
Segments group related sections (e.g., code, data, resources). Key segments include:
- __TEXT: Contains executable code (e.g., .text, .cfi, .objc_methprops).
- __DATA: Holds initialized data (e.g., .data, .rodata) and BSS (uninitialized data).
- __LINKEDIT: Contains dynamic linking information (e.g., symbol tables, relocation data).
Sections within segments define specific roles. For example:
- .text: Machine code.
- .const: Read-only data.
- .bss: Uninitialized global variables.
Execution Flow¶
When a Mach-O binary is executed:
1. The kernel loads the file into memory using load commands.
2. Segments are mapped to virtual memory addresses.
3. The loader resolves symbols and applies relocations.
4. Execution begins at the entry point (specified in the header or LC_MAIN command).
5. Dynamic linking (via dyld) resolves dependencies (e.g., shared libraries).
Example:
Tools for Analysis¶
Use these tools to inspect Mach-O files:
- otool: Disassemble and inspect headers/load commands.
- nm: List symbols (e.g., nm -g /path/to/binary).
- objdump: Disassemble code (e.g., objdump -d /path/to/binary).
- haxm: For advanced memory and execution analysis.
Key takeaways¶
- Mach-O files define how macOS binaries are structured and executed.
- Headers and load commands guide memory mapping and execution.
- Segments and sections organize code, data, and metadata.
- Tools like
otoolandnmare essential for reverse engineering. - Understanding Mach-O is foundational for persistence and evasion techniques.