
machofile is a module to parse Mach-O binary files
machofile ist ein Modul zum Parsen von Mach-O-Binärdateien mit Schwerpunkt auf Malware-Analyse und Reverse Engineering.
Inspiriert von Ero Carreras pefile, zielt dieses Modul darauf ab, ähnliche Fähigkeiten bereitzustellen, jedoch für Mach-O-Binaries. Referenzmaterial und Dokumentationen, die verwendet wurden, um das Wissen über das Dateiformat zu erlangen, die grundlegenden Strukturen und Konstanten stammen aus den unten aufgeführten Ressourcen.
machofile ist in sich geschlossen. Das Modul hat keine Abhängigkeiten; es ist endianness-unabhängig und funktioniert unter macOS, Windows und Linux.
Obwohl es andere Mach-O-Parsing-Module gibt, waren die Beweggründe für die Entwicklung dieses Moduls:
Lass mich wissen, wenn du es ausprobierst oder Fehler findest, aber auch ... sei nachsichtig ;) Der Code wird optimiert und weitere Funktionen werden hinzugefügt.
Aktuelle Funktionen:
Hinweis: Derzeit wurde dies zunächst gegen x86-, x86_64-, arm64- und arm64e-Mach-O-Beispiele getestet.
Nächste zu implementierende Funktionen (in zufälliger Reihenfolge):
Du kannst es entweder über die Befehlszeile verwenden oder als Modul in deinen Python-Code importieren und jede Funktion einzeln aufrufen, um nur die Strukturen zu parsen, die dich interessieren. Du kannst es direkt über pip installieren und programmatisch oder über die Befehlszeile verwenden, oder du nutzt es als eigenständiges Skript
pip install machofile
Es erwartet entweder einen Dateipfad oder einen Datenpuffer zum Parsen.
import machofile
macho = machofile.UniversalMachO(file_path='/path/to/machobinary')
macho.parse()
Wenn der Datenpuffer bereits verfügbar ist, kann er direkt übergeben werden:
import machofile
with open(file_path, 'rb') as f:
data = f.read()
macho = machofile.UniversalMachO(data=data)
macho.parse()
Für eine detaillierte Verwendung der API wirf einen Blick auf die dedizierte API-Dokumentationsseite.
Du kannst machofile auch direkt als CLI-Tool verwenden, wenn du es über pip installiert hast, oder als eigenständiges Tool mit python3 machofile.py. Alle Funktionen sind sowohl als Modul als auch als Kommandozeilentool verfügbar.
% machofile -h
usage: machofile [-h] -f FILE [-j] [--raw] [-a] [-d] [-e] [-ep] [-g]
[-hdr] [-i] [-l] [-seg] [-sig] [-sim] [-u] [-v]
[--arch ARCH] [--dump-dir DUMP_DIR]
Parse Mach-O binary structures. (version 2026.02.04)
options:
-h, --help show this help message and exit
required arguments:
-f, --file FILE Path to the file to be parsed
output format options:
-j, --json Output data in JSON format
--raw Output raw values in JSON format (use with -j/--json)
data extraction options:
-a, --all Print all info about the file
-d, --dylib Print Dylib Command Table and Dylib list
-e, --exports Print exported symbols
-ep, --entry-point Print entry point information
-g, --general_info Print general info about the file
-hdr, --header Print Mach-O header info
-i, --imports Print imported symbols
-l, --load_cmd_t Print Load Command Table and Command list
-seg, --segments Print File Segments info
-sig, --signature Print code signature and entitlements information
-sim, --similarity Print similarity hashes
-u, --uuid Print UUID
-v, --version Print version information
filter options:
--arch ARCH Show info for specific architecture only (for Universal binaries)
dump options:
--dump-dir DUMP_DIR Dump individual Mach-O slices from a FAT/Universal binary
to the specified directory
Beispielausgabe:
% machofile -a -f b4f68a58658ceceb368520dafc35b270272ac27b8890d5b3ff0b968170471e2b
[General File Info]
Filename: b4f68a58658ceceb368520dafc35b270272ac27b8890d5b3ff0b968170471e2b
Filesize: 54240
MD5: 20ffe440e4f557b9e03855b5da2b3c9c
SHA1: 1bf61ecad8568a774f9fba726a254a9603d09f33
SHA256: b4f68a58658ceceb368520dafc35b270272ac27b8890d5b3ff0b968170471e2b
[Mach-O Header]
magic: MH_MAGIC (32-bit), 0xFEEDFACE
cputype: Intel i386
cpusubtype: X86_ALL
filetype: EXECUTE
ncmds: 13
sizeofcmds: 1180
flags: NOUNDEFS, DYLDLINK, TWOLEVEL
[Load Cmd table]
{'cmd': 'LC_SEGMENT', 'cmdsize': 56}
{'cmd': 'LC_SEGMENT', 'cmdsize': 192}
{'cmd': 'LC_SEGMENT', 'cmdsize': 328}
{'cmd': 'LC_SEGMENT', 'cmdsize': 192}
{'cmd': 'LC_SEGMENT', 'cmdsize': 56}
{'cmd': 'LC_SYMTAB', 'cmdsize': 24}
{'cmd': 'LC_DYSYMTAB', 'cmdsize': 80}
{'cmd': 'LC_LOAD_DYLINKER', 'cmdsize': 28}
{'cmd': 'LC_UUID', 'cmdsize': 24}
{'cmd': 'LC_UNIXTHREAD', 'cmdsize': 80}
{'cmd': 'LC_LOAD_DYLIB', 'cmdsize': 52}
{'cmd': 'LC_LOAD_DYLIB', 'cmdsize': 52}
{'cmd': 'LC_CODE_SIGNATURE', 'cmdsize': 16}
[Load Commands]
LC_CODE_SIGNATURE
LC_DYSYMTAB
LC_LOAD_DYLIB
LC_LOAD_DYLINKER
LC_SEGMENT
LC_SYMTAB
LC_UNIXTHREAD
LC_UUID
[File Segments]
SEGNAME VADDR VSIZE OFFSET SIZE MAX_VM_PROTECTION INITIAL_VM_PROTECTION NSECTS FLAGS ENTROPY
------------------------------------------------------------------------------------------------------------
__PAGEZERO 0 4096 0 0 0 0 0 0 0.0
__TEXT 4096 28672 0 28672 7 5 2 0 5.080680410706916
__DATA 32768 4096 28672 4096 7 3 4 0 0.1261649636134924
__IMPORT 36864 4096 32768 4096 7 7 2 0 0.21493796627555234
__LINKEDIT 40960 20480 36864 17376 7 1 0 0 6.637864516225949
[Dylib Commands]
DYLIB_NAME_OFFSET DYLIB_TIMESTAMP DYLIB_CURRENT_VERSION DYLIB_COMPAT_VERSION DYLIB_NAME
----------------------------------------------------------------------------------------------------------
24 2 65536 65536 b'/usr/lib/libgcc_s.1.dylib'
24 2 7274759 65536 b'/usr/lib/libSystem.B.dylib'
[Dylib Names]
b'/usr/lib/libgcc_s.1.dylib'
b'/usr/lib/libSystem.B.dylib'
[UUID]
d691c242-da49-1081-50d5-4f8991924b06
[Entry Point]
type: LC_UNIXTHREAD
entry_address: 9200
thread_data_size: 72
[Version Information]
No version information found
[Code Signature]
signed: True
signing_status: Apple signed
certificates_info:
count: 3
certificates:
index: 0
size: 4815
subject: Contains: Developer ID Certification Authority
issuer: Unable to parse
is_apple_cert: True
type: Developer ID Certification Authority
index: 1
size: 1215
subject: Contains: Apple Root CA
issuer: Unable to parse
is_apple_cert: True
type: Apple Root CA
index: 2
size: 1385
subject: Contains: Developer ID Application:
issuer: Unable to parse
is_apple_cert: False
type: Developer ID Application Certificate
entitlements_info:
count: 0
entitlements:
code_directory:
version: 131328
flags: 0
hash_offset: 144
identifier_offset:48
special_slots: 3
signing_flags:
None
code_slots: 11
hash_size: 44640
hash_type: 335609868
hash_algorithm: Unknown (335609868)
identifier: onmac.unspecified.installer
[Imported Libraries]
/usr/lib/libgcc_s.1.dylib
/usr/lib/libSystem.B.dylib
[Imported Functions]
(Sources: CF=chained_fixups, BO=bind, WB=weak_bind, LB=lazy_bind, ST=symtab)
/usr/lib/libSystem.B.dylib:
__NSGetExecutablePath [ST]
___stderrp [ST]
_dlerror [ST]
_dlopen [ST]
_dlsym [ST]
_exit [ST]
_fclose [ST]
_fopen [ST]
_fprintf [ST]
_fputs$UNIX2003 [ST]
_free [ST]
_fwrite$UNIX2003 [ST]
_getenv [ST]
_getpid [ST]
_getpwnam [ST]
_lstat [ST]
_mbstowcs [ST]
_memcpy [ST]
_memset [ST]
_setenv$UNIX2003 [ST]
_setlocale [ST]
_snprintf [ST]
_stat [ST]
_strchr [ST]
_strdup [ST]
_strlen [ST]
_unsetenv$UNIX2003 [ST]
[Exported Symbols]
<unknown>:
_NXArgc
_NXArgv
___progname
_environ
_main
start
[Similarity Hashes]
dylib_hash: 0556bed5dc31bddaee73f3234b3c577b
export_hash: 824e359e3d0ad7283d0982bd5da2e8fd
import_hash: 0bae89995ad3900987c49c0bea1d17fe
symhash: 15e6c1aeba01be1404901f7152213779
Wenn du mit Universal- (FAT-) Binaries arbeitest, kannst du jeden Architektur-Slice mit --dump-dir in eine eigene eigenständige Mach-O-Datei extrahieren:
# Dump all slices
% machofile -f universal_binary --dump-dir ./output
Dumped x86_64 -> ./output/universal_binary.x86_64
Dumped arm64 -> ./output/universal_binary.arm64
# Dump only a specific architecture (combine with --arch)
% machofile -f universal_binary --dump-dir ./output --arch arm64
Dumped arm64 -> ./output/universal_binary.arm64
Jede extrahierte Datei ist ein gültiges eigenständiges Mach-O-Binary. Das Ausgabeverzeichnis wird automatisch erstellt, falls es nicht existiert. Die Ausgabedateien werden nach <original_filename>.<arch_name> benannt.
machofile unterstützt die JSON-Ausgabe zur programmatischen Nutzung der geparsten Daten. Die JSON-Ausgabe ist in zwei Formaten verfügbar:
Die Standard-JSON-Ausgabe liefert menschenlesbare Werte mit entsprechender Formatierung:
% python3 machofile.py -j -hdr -f dec750b9d596b14aeab1ed6f6d6d370022443ceceb127e7d2468b903c2d9477a
{
"header": {
"x86_64": {
"magic": "MH_MAGIC_64 (64-bit), 0xFEEDFACF",
"cputype": "x86_64",
"cpusubtype": "x86_ALL",
"filetype": "EXECUTE",
"ncmds": 41,
"sizeofcmds": 5024,
"flags": "NOUNDEFS, DYLDLINK, TWOLEVEL, BINDS_TO_WEAK, PIE"
},
"arm64": {
"magic": "MH_MAGIC_64 (64-bit), 0xFEEDFACF",
"cputype": "ARM 64-bit",
"cpusubtype": "ARM_ALL",
"filetype": "EXECUTE",
"ncmds": 41,
"sizeofcmds": 5104,
"flags": "NOUNDEFS, DYLDLINK, TWOLEVEL, BINDS_TO_WEAK, PIE"
}
},
"architectures": [
"x86_64",
"arm64"
]
}
Für Anwendungen, die rohe numerische Werte verarbeiten müssen, verwende das --raw-Flag:
% python3 machofile.py -j --raw -hdr -f dec750b9d596b14aeab1ed6f6d6d370022443ceceb127e7d2468b903c2d9477a
{
"header": {
"x86_64": {
"magic": 4277009103,
"cputype": 16777223,
"cpusubtype": 3,
"filetype": 2,
"ncmds": 41,
"sizeofcmds": 5024,
"flags": 2162821
},
"arm64": {
"magic": 4277009103,
"cputype": 16777228,
"cpusubtype": 0,
"filetype": 2,
"ncmds": 41,
"sizeofcmds": 5104,
"flags": 2162821
}
},
"architectures": [
"x86_64",
"arm64"
]
}
-j, --json: Daten im JSON-Format ausgeben (standardmäßig menschenlesbar)--raw: Rohe numerische Werte anstelle formatierter Zeichenketten ausgeben (muss mit -j verwendet werden)Die JSON-Ausgabe unterstützt alle Analyseoptionen der Standardausgabe (-a, -hd, -l, -sg usw.) und funktioniert sowohl mit Einzelarchitektur- als auch mit Universal- (FAT-) Binaries.
Die Entwicklung von machofile wird von RationalEdge gesponsert.
Das sind die Menschen, bei denen ich mich bedanken möchte, weil sie die Inspiration waren, die mich dazu bewogen hat, dieses Modul zu schreiben: