
machofile é um módulo para analisar arquivos binários Mach-O
# machofile
[](https://pepy.tech/project/machofile)
**machofile** é um módulo para analisar ficheiros binários Mach-O, com foco em análise de malware e engenharia reversa.
Inspirado no pefile de Ero Carrera, este módulo pretende fornecer capacidades semelhantes, mas para binários Mach-O.
O material de referência e a documentação utilizados para obter o conhecimento do formato de ficheiro, as estruturas básicas e as constantes são provenientes dos recursos listados abaixo.
**machofile** é autossuficiente. O módulo não tem dependências; é independente de endianness; e funciona em macOS, Windows e Linux.
Embora existam outros módulos de análise de Mach-O por aí, as motivações para desenvolver este são:
- antes de mais, para mim foi uma ótima forma de mergulhar fundo e aprender mais sobre o formato e as estruturas Mach-O
- fornecer uma forma simples de analisar ficheiros Mach-O para análise
- não depender de módulos externos (ex.: lief, macholib, macho, etc.), uma vez que tudo é extraído diretamente do ficheiro e é tudo em Python puro.
Deixa-me saber se experimentares ou encontrares bugs, mas também... sê gentil ;) o código será otimizado e mais funcionalidades serão adicionadas.
**Funcionalidades atuais:**
- Analisar o cabeçalho Mach-O
- Analisar Load Commands
- Analisar os segmentos do ficheiro
- Analisar Dylib Commands
- Analisar a lista de Dylibs
- Extrair funções importadas
- Extrair símbolos exportados
- Hashes: hash de dylib, hash de importação, hash de exportação, hash de entitlements, symhash
- Cálculo da entropia dos segmentos
- Extrair ponto de entrada
- Extrair UUID
- Extrair informações de versão
- Analisar informações básicas da Code Signature
- Suporte para binários FAT (Universal)
- Extrair fatias Mach-O individuais de binários FAT (Universal)
- Suporte para saída JSON (tanto em formato legível por humanos como raw)
_Nota: até ao momento, isto foi inicialmente testado em amostras Mach-O x86, x86_64, arm64 e arm64e._
**Próximas funcionalidades a implementar (em ordem aleatória):**
- Strings incorporadas
- Atributos do ficheiro
- flag para bibliotecas suspeitas
- Deteção de packers
- ...
## Uso e exemplos
Podes usá-lo a partir da linha de comandos ou importá-lo como módulo no teu código Python, e chamar cada função individualmente para analisar apenas as estruturas que te interessam. Podes instalá-lo diretamente via `pip` e usá-lo programaticamente ou a partir da linha de comandos, ou usá-lo como script autónomo.
```
pip install machofile
```
### Versão do módulo
Espera que lhe seja fornecido um caminho de ficheiro ou um buffer de dados para analisar.
```python
import machofile
macho = machofile.UniversalMachO(file_path='/path/to/machobinary')
macho.parse()
```
Se o buffer de dados já estiver disponível, pode ser fornecido diretamente com:
```python
import machofile
with open(file_path, 'rb') as f:
data = f.read()
macho = machofile.UniversalMachO(data=data)
macho.parse()
```
Para utilização detalhada da API, consulta a página dedicada de [documentação da API](https://github.com/pstirparo/machofile/blob/main/doc/API_documentation_machofile.md).
### Versão de linha de comandos
Podes usar `machofile` também diretamente como ferramenta CLI se o instalaste via `pip`, ou como ferramenta autónoma com `python3 machofile.py`. Todas as mesmas funcionalidades estão disponíveis como módulo e também como ferramenta de linha de comandos.
```
% 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
```
Exemplo de saída:
```
% 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
```
### Extrair fatias de binários Universal (FAT)
Ao trabalhar com binários Universal (FAT), podes extrair cada fatia de arquitetura para o seu próprio ficheiro Mach-O autónomo usando `--dump-dir`:
```bash
# 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
```
Cada ficheiro extraído é um binário Mach-O autónomo válido. O diretório de saída é criado automaticamente se não existir. Os ficheiros de saída são nomeados `<original_filename>.<arch_name>`.
### Saída JSON
O **machofile** suporta saída JSON para consumo programático dos dados analisados. A saída JSON está disponível em dois formatos:
#### JSON Legível por Humanos (Padrão)
A saída JSON padrão fornece valores legíveis por humanos com formatação adequada aplicada:
```bash
% 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"
]
}
```
#### Saída JSON Raw
Para aplicações que precisam de processar valores numéricos raw, usa a flag `--raw`:
```bash
% 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"
]
}
```
#### Opções de Saída JSON
- `-j, --json`: Envia dados em formato JSON (legível por humanos por padrão)
- `--raw`: Envia valores numéricos raw em vez de strings formatadas (deve ser usado com `-j`)
A saída JSON suporta todas as mesmas opções de análise que a saída padrão (`-a`, `-hd`, `-l`, `-sg`, etc.) e funciona tanto com binários de arquitetura única como com binários Universal (FAT).
## Patrocinado por
<a href="https://rationaledge.io">
<img src="https://assets.kitploit.com/production/public/readmes/48633/7e48b10e205e0fb59eebed5ce6c8dca3f3c3b5e980d3c982a5b72b3619f23932.png" alt="RationalEdge" width="400">
</a>
O desenvolvimento do **machofile** é patrocinado pela [RationalEdge](https://rationaledge.io).
## Créditos
Estas são as pessoas que gostaria de agradecer por serem a inspiração que me levou a escrever este módulo:
- Ero Carrera ([@erocarrera](https://twitter.com/erocarrera)) por escrever e manter o módulo [pefile](https://github.com/erocarrera/pefile/tree/master)
- Patrick Wardle ([@patrickwardle](https://twitter.com/patrickwardle)) pelo excelente trabalho em partilhar a sua análise e investigação de malware em macOS, e por dar vida ao [OBTS](https://objectivebythesea.org/) :)
- Greg Lesnewich ([@greg-l.bsky.social](https://bsky.app/profile/greg-l.bsky.social)) e Jacob Latonis ([@jacoblatonis.me](https://bsky.app/profile/jacoblatonis.me)) pelo seu trabalho em similaridade de Mach-O e pelas sessões contínuas (e geek) e esclarecedoras de brainstorming sobre o formato binário Mach-O. Vejam a apresentação deles no OBTS v7 no YT.
## Links de referência/documentação:
- https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h
- https://github.com/apple-oss-distributions/lldb/blob/10de1840defe0dff10b42b9c56971dbc17c1f18c/llvm/include/llvm/Support/MachO.h
- https://github.com/apple-oss-distributions/dyld/tree/main
- https://iphonedev.wiki/Mach-O_File_Format
- https://lowlevelbits.org/parsing-mach-o-files/
- https://github.com/aidansteele/osx-abi-macho-file-format-reference
- https://lief-project.github.io/doc/latest/tutorials/11_macho_modification.html
- https://github.com/VirusTotal/yara/blob/master/libyara/include/yara/macho.h
- https://github.com/corkami/pics/blob/master/binary/README.md
- https://github.com/qyang-nj/llios/tree/main
- https://github.com/threatstream/symhash