Mach-O: Analisis de Binarios macOS e iOS
Estructura del formato Mach-O para macOS e iOS. Header, load commands, segmentos, fat binaries, code signing, dyld y analisis de malware en el ecosistema Apple.
macOS e iOS: un ecosistema diferente
El malware para macOS representa un porcentaje pequeno comparado con Windows, pero esta creciendo de forma constante. Familias como XCSSET, Shlayer, Atomic Stealer, y el tooling de APTs como Lazarus (AppleJeus) y APT28 demuestran que el ecosistema Apple no es inmune.
El formato Mach-O (Mach Object) tiene diferencias significativas con PE y ELF. En lugar de secciones y program headers, usa load commands. En lugar de un solo binario, puede contener multiples arquitecturas en un fat binary. Y el code signing de Apple anade una capa de verificacion que no existe en los otros formatos.
Estructura general de Mach-O
Un archivo Mach-O se organiza en tres partes:
| Componente | Funcion |
|---|---|
| Header | Identifica el archivo, arquitectura y tipo |
| Load Commands | Instrucciones para el loader (segmentos, librerias, entry point) |
| Data | Contenido real de los segmentos (codigo, datos) |
Mach-O Header
El header ocupa 28 bytes (32-bit) o 32 bytes (64-bit):
| Campo | Tamano | Descripcion |
|---|---|---|
| magic | 4 bytes | 0xFEEDFACE (32-bit), 0xFEEDFACF (64-bit) |
| cputype | 4 bytes | Arquitectura: CPU_TYPE_X86_64, CPU_TYPE_ARM64 |
| cpusubtype | 4 bytes | Subtipo especifico |
| filetype | 4 bytes | Tipo de Mach-O |
| ncmds | 4 bytes | Numero de load commands |
| sizeofcmds | 4 bytes | Tamano total de load commands |
| flags | 4 bytes | Flags del binario |
Tipos de archivo Mach-O
| Tipo | Valor | Descripcion | Contexto malware |
|---|---|---|---|
| MH_EXECUTE | 2 | Ejecutable | Aplicaciones maliciosas |
| MH_DYLIB | 6 | Libreria dinamica (.dylib) | DLL hijacking en macOS |
| MH_BUNDLE | 8 | Bundle plugin | Extensiones maliciosas |
| MH_KEXT_BUNDLE | 11 | Kernel extension | Rootkits macOS (legacy) |
| MH_FILESET | 12 | Kernel cache | Analisis de kernel |
Flags relevantes
| Flag | Valor | Significado |
|---|---|---|
| MH_PIE | 0x200000 | Position Independent Executable (ASLR) |
| MH_NO_HEAP_EXECUTION | 0x1000000 | Heap no ejecutable |
| MH_ALLOW_STACK_EXECUTION | 0x20000 | Stack ejecutable (sospechoso) |
| MH_DYLDLINK | 0x4 | Usa dyld (dynamic linker) |
# Examinar header
otool -h sample_macho
# Salida:
# Mach header
# magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
# 0xfeedfacf 16777228 0 0x00 2 19 2120 0x00200085
Load Commands: el corazon de Mach-O
Los load commands son el equivalente combinado de los program headers de ELF y las Data Directories del PE. Cada load command tiene un tipo (cmd) y un tamano (cmdsize), seguido de datos especificos del tipo.
Load commands principales
| Command | Funcion |
|---|---|
| LC_SEGMENT_64 | Define un segmento (equivalente a PT_LOAD en ELF) |
| LC_MAIN | Entry point del ejecutable |
| LC_LOAD_DYLIB | Libreria dinamica requerida |
| LC_LOAD_WEAK_DYLIB | Libreria opcional |
| LC_DYLD_INFO_ONLY | Informacion de binding para dyld |
| LC_SYMTAB | Tabla de simbolos |
| LC_DYSYMTAB | Tabla de simbolos dinamicos |
| LC_CODE_SIGNATURE | Firma de codigo |
| LC_UUID | Identificador unico del binario |
| LC_RPATH | Ruta de busqueda de librerias |
| LC_FUNCTION_STARTS | Offsets de inicio de funciones |
# Listar todos los load commands
otool -l sample_macho
# Solo librerias cargadas
otool -L sample_macho
Segmentos estandar
Los segmentos en Mach-O se definen via LC_SEGMENT_64 y contienen secciones:
| Segmento | Secciones | Contenido |
|---|---|---|
| __TEXT | __text, __stubs, __stub_helper, __cstring | Codigo y strings constantes |
| __DATA | __data, __bss, __la_symbol_ptr, __got | Variables y GOT |
| __DATA_CONST | __const, __got | Datos constantes |
| __LINKEDIT | (sin secciones nombradas) | Simbolos, firmas, binding info |
Diferencia con PE/ELF: En Mach-O, los segmentos contienen secciones. Un segmento define los permisos de memoria, y las secciones dentro de el organizan los datos. En ELF, segmentos y secciones son vistas independientes.
# Secciones del segmento __TEXT
otool -l sample_macho | grep -A5 "__TEXT,__text"
Fat Binaries (Universal Binaries)
Un fat binary combina multiples arquitecturas en un solo archivo. Apple los usa para distribuir aplicaciones que funcionan tanto en Intel (x86_64) como en Apple Silicon (arm64).
Estructura del Fat Header
| Campo | Descripcion |
|---|---|
| magic | 0xCAFEBABE (big-endian) o 0xBEBAFECA (little-endian) |
| nfat_arch | Numero de arquitecturas |
| fat_arch[] | Array con offset, tamano y CPU de cada arquitectura |
# Identificar fat binary
file universal_app
# universal_app: Mach-O universal binary with 2 architectures:
# [x86_64: Mach-O 64-bit executable x86_64]
# [arm64: Mach-O 64-bit executable arm64]
# Listar arquitecturas
lipo -info universal_app
# Architectures in the fat file: universal_app are: x86_64 arm64
# Extraer una arquitectura especifica
lipo universal_app -thin arm64 -output sample_arm64
Relevancia para malware:
El malware puede incluir codigo diferente para cada arquitectura. La version arm64 podria contener el payload real mientras la version x86_64 es benigna, o viceversa. Siempre analizar ambas arquitecturas por separado.
Nota: El magic 0xCAFEBABE es el mismo que usan los archivos .class de Java. La diferencia se resuelve verificando los bytes siguientes.
Code Signing en macOS
macOS usa code signing como mecanismo de confianza. Gatekeeper verifica la firma antes de permitir la ejecucion de aplicaciones descargadas de Internet.
Niveles de firma
| Nivel | Descripcion | Confianza |
|---|---|---|
| Sin firmar | No tiene firma | Gatekeeper bloquea |
| Ad-hoc | Firma local sin certificado | Funciona solo en la maquina que firmo |
| Developer ID | Certificado de Apple | Gatekeeper permite |
| Notarized | Firmado + revisado por Apple | Maximo nivel de confianza |
Verificar firma
# Detalles de la firma
codesign -dvvv sample_app
# Verificar integridad
codesign --verify --verbose sample_app
# Verificar con Gatekeeper
spctl --assess --type execute sample_app
# Ver el certificado
codesign -d --extract-certificates sample_app
openssl x509 -inform DER -in codesign0 -text
Malware y code signing
| Escenario | Tecnica | Ejemplo |
|---|---|---|
| Certificado robado | Firma valida con Developer ID comprometido | XCSSET, OceanLotus |
| Firma ad-hoc | El binario pasa algunas verificaciones | Shlayer variantes |
| Sin firmar | Requiere bypass de Gatekeeper | Malware distribuido via terminal |
| Firma removida | Strip de la firma post-compilacion | Tooling de APT |
dyld: el Dynamic Linker de macOS
dyld (Dynamic Linker/Loader) es el equivalente de ld-linux.so en Linux. Se encarga de:
- Cargar el Mach-O en memoria
- Resolver librerias dinamicas (LC_LOAD_DYLIB)
- Realizar binding de simbolos
- Ejecutar constructores (__mod_init_func)
- Transferir control al entry point (LC_MAIN)
DYLD_INSERT_LIBRARIES: inyeccion en macOS
Similar a LD_PRELOAD en Linux, la variable DYLD_INSERT_LIBRARIES permite inyectar una libreria en cualquier proceso:
DYLD_INSERT_LIBRARIES=malicious.dylib /path/to/app
Apple restringe esto con SIP (System Integrity Protection), pero el malware puede usar esta tecnica contra aplicaciones de terceros o cuando SIP esta deshabilitado.
Hijacking de dylib
El malware puede explotar el orden de busqueda de librerias de dyld:
- Directorio del ejecutable
- Rutas LC_RPATH
- Rutas de sistema (/usr/lib, /usr/local/lib)
Si una aplicacion busca una dylib que no existe en la primera ruta, el malware puede colocar su propia dylib ahi. Herramientas como dylib-hijack-scanner de Patrick Wardle detectan estas oportunidades.
Tecnicas de malware especificas de macOS
Persistencia en macOS
| Mecanismo | Localizacion |
|---|---|
| Launch Agents | ~/Library/LaunchAgents/ (usuario) |
| Launch Daemons | /Library/LaunchDaemons/ (sistema) |
| Login Items | System Preferences o API |
| Cron jobs | crontab |
| at jobs | atq |
| Kernel Extensions | /Library/Extensions/ (legacy, requiere kext signing) |
| System Extensions | Reemplaza kexts en macOS moderno |
Objective-C y Swift: metadatos ricos
Los binarios compilados con Objective-C contienen metadatos de clases, metodos y protocolos que revelan la funcionalidad:
# Extraer interfaces Objective-C
class-dump sample_app
# Buscar metodos sospechosos
class-dump sample_app | grep -i "download\|execute\|keylog\|screenshot"
Analisis de aplicaciones .app
Las aplicaciones macOS son directorios con estructura:
MyApp.app/
Contents/
MacOS/
MyApp (binario Mach-O)
Info.plist (metadatos de la app)
Resources/
Frameworks/ (librerias incluidas)
CodeSignature/
CodeResources (hashes de todos los archivos)
El Info.plist contiene metadatos como el bundle identifier, version, permisos solicitados (entitlements) y la clave LSMinimumSystemVersion.
Herramientas de analisis Mach-O
| Herramienta | Funcion | Plataforma |
|---|---|---|
| otool | Examinar headers, secciones, imports | macOS (incluido en Xcode) |
| jtool2 | Analisis avanzado de Mach-O | macOS |
| MachOView | Visor grafico de estructura Mach-O | macOS (open source) |
| codesign | Verificar y gestionar firmas | macOS |
| class-dump | Extraer metadatos Objective-C | macOS |
| lipo | Manipular fat binaries | macOS |
| Hopper | Desensamblador comercial (excelente soporte Mach-O) | macOS, Linux |
| Ghidra | Decompilacion (soporte Mach-O) | Multiplataforma |
Analisis con otool
# Header
otool -h binary
# Load commands
otool -l binary
# Librerias importadas
otool -L binary
# Desensamblado
otool -tV binary
# Strings (seccion __cstring)
otool -p __cstring binary
Analisis con jtool2
# Informacion general
jtool2 --analyze binary
# Entitlements
jtool2 --ent binary
# Firma de codigo
jtool2 --sig binary
# Simbolos
jtool2 -S binary
Flujo de analisis para malware macOS
- Identificacion:
file,shasum, verificar si es fat binary conlipo. - Firma:
codesign -dvvv,spctl --assess. - Headers:
otool -h,otool -lpara load commands. - Imports:
otool -Lpara librerias,nmpara simbolos. - Strings:
strings -a, buscar URLs, IPs, paths, comandos. - Metadatos ObjC:
class-dumpsi aplica. - Plist: Examinar Info.plist y entitlements.
- Decompilacion: Ghidra o Hopper para analisis profundo.
Conclusion
El formato Mach-O tiene sus propias particularidades que lo distinguen de PE y ELF: load commands en lugar de secciones y program headers, fat binaries para multiples arquitecturas, code signing integrado y la rica metadata de Objective-C. Con el crecimiento del malware para macOS, especialmente stealers (Atomic, Banshee) y herramientas de APTs, dominar el analisis de Mach-O es cada vez mas relevante para los equipos de CTI.
Preguntas frecuentes
Libros recomendados
Artículos relacionados
Formato PE de Windows: Estructura Completa del Ejecutable
Formato ELF de Linux: Estructura y Analisis para Malware
Analisis Estatico Basico: Strings, Hashes y Metadatos
Tecnicas Anti-Analisis: Anti-Debug, Anti-VM y Anti-Sandbox
Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.