Background
Mach-O binaries (macOS/iOS executables and libraries) embed critical runtime metadata in load commands within the binary header. These commands specify:
- Dynamically linked libraries and frameworks
- Runtime search paths (@rpath, @executable_path, @loader_path)
- Library installation names and version requirements
- Platform minimum version information
Currently, StringyMcStringFace's standard string extraction only scans data sections, missing these header-resident strings that are essential for understanding binary dependencies and runtime behavior.
Problem Statement
Security analysts and reverse engineers need to:
- Map dependency chains: Identify all dynamically loaded libraries and frameworks
- Resolve runtime paths: Understand @rpath resolution order for detecting hijacking opportunities
- Version analysis: Extract minimum platform versions and compatibility constraints
- Installation verification: Compare expected vs actual library locations
Without load command parsing, these critical artifacts remain hidden from analysis workflows.
Proposed Solution
Architecture Changes
Extend src/container/macho.rs to implement a dedicated load command parser that runs before section-level extraction.
Target Load Commands
| Command |
Purpose |
Example Output |
LC_LOAD_DYLIB |
Required dynamic libraries |
/usr/lib/libSystem.B.dylib |
LC_LOAD_WEAK_DYLIB |
Optional dynamic libraries |
/System/Library/Frameworks/Metal.framework/Metal |
LC_REEXPORT_DYLIB |
Re-exported libraries |
@rpath/MyFramework.framework/MyFramework |
LC_ID_DYLIB |
Library installation name |
/usr/local/lib/libcustom.1.dylib |
LC_RPATH |
Runtime search paths |
@executable_path/../Frameworks |
LC_VERSION_MIN_MACOSX |
Platform version |
10.15.0 |
LC_BUILD_VERSION |
Build version info |
Platform + SDK version |
Implementation Steps
- Parse Load Commands - Extend
src/container/macho.rs to iterate through load commands using goblin::mach::load_command APIs
- Extract String Data - Pull path strings from dylib and rpath structures
- Add Extraction Hook - Call load command extraction before
extract_from_sections()
- Tag Classification - Apply tags:
macho-lc, filepath, framework, rpath, version
- Relevance Scoring - Base score 85-90, boost @rpath paths by +5, frameworks +3
Example Output
String: "/System/Library/Frameworks/Foundation.framework/Foundation"
Source: MachOLoadCommand(LC_LOAD_DYLIB, offset=0x1a8)
Score: 90
Tags: [macho-lc, filepath, framework]
String: "@rpath/CustomFramework.framework/CustomFramework"
Source: MachOLoadCommand(LC_LOAD_DYLIB, offset=0x1f0)
Score: 95
Tags: [macho-lc, filepath, framework, rpath]
String: "@executable_path/../Frameworks"
Source: MachOLoadCommand(LC_RPATH, offset=0x238)
Score: 95
Tags: [macho-lc, rpath]
Implementation Considerations
Path Variable Preservation
- DO NOT resolve or expand path variables
- Preserve
@executable_path, @loader_path, @rpath verbatim
- These are runtime-resolved and their literal form is analytically valuable
Multi-Architecture Binaries
- Universal binaries contain multiple Mach-O images
- Extract load commands from each architecture slice independently
- Tag with architecture context (arm64, x86_64, etc.)
Error Handling
- Gracefully handle malformed load commands (corrupted binaries, packers)
- Validate command size fields before string extraction
- Continue extraction on individual command failures
CLI Integration
Add optional filtering: --macho-load-commands flag to show only load command strings
Testing Strategy
Test Cases Required
- Basic Dylib Loading - Test binary with standard system library dependencies
- Framework Dependencies - Binary using Cocoa/UIKit frameworks
- @rpath Usage - Binary with embedded framework using @rpath
- Universal Binary - Fat binary with arm64 + x86_64 slices
- Malformed Commands - Truncated structures, invalid sizes, non-UTF8 data
Test Binaries
Use real-world samples from:
- macOS system binaries (
/bin/ls, /usr/bin/ssh)
- iOS apps (
.ipa extraction)
- Custom test binaries with controlled dependencies
Success Criteria
References
Related Work
This complements existing PE import parsing (if implemented) and provides Mach-O parity with other binary format analyzers.
Background
Mach-O binaries (macOS/iOS executables and libraries) embed critical runtime metadata in load commands within the binary header. These commands specify:
Currently, StringyMcStringFace's standard string extraction only scans data sections, missing these header-resident strings that are essential for understanding binary dependencies and runtime behavior.
Problem Statement
Security analysts and reverse engineers need to:
Without load command parsing, these critical artifacts remain hidden from analysis workflows.
Proposed Solution
Architecture Changes
Extend
src/container/macho.rsto implement a dedicated load command parser that runs before section-level extraction.Target Load Commands
LC_LOAD_DYLIB/usr/lib/libSystem.B.dylibLC_LOAD_WEAK_DYLIB/System/Library/Frameworks/Metal.framework/MetalLC_REEXPORT_DYLIB@rpath/MyFramework.framework/MyFrameworkLC_ID_DYLIB/usr/local/lib/libcustom.1.dylibLC_RPATH@executable_path/../FrameworksLC_VERSION_MIN_MACOSX10.15.0LC_BUILD_VERSIONImplementation Steps
src/container/macho.rsto iterate through load commands usinggoblin::mach::load_commandAPIsextract_from_sections()macho-lc,filepath,framework,rpath,versionExample Output
Implementation Considerations
Path Variable Preservation
@executable_path,@loader_path,@rpathverbatimMulti-Architecture Binaries
Error Handling
CLI Integration
Add optional filtering:
--macho-load-commandsflag to show only load command stringsTesting Strategy
Test Cases Required
Test Binaries
Use real-world samples from:
/bin/ls,/usr/bin/ssh).ipaextraction)Success Criteria
References
Related Work
This complements existing PE import parsing (if implemented) and provides Mach-O parity with other binary format analyzers.