macOS Apps - Inspecting, debugging and Fuzzing
Análisis Estático
otool & objdump & nm
jtool2 & Disarm
Puedes descargar disarm desde aquí.
Puedes descargar jtool2 aquí o instalarlo con brew
.
jtool está en desuso a favor de disarm
Codesign / ldid
Codesign
se puede encontrar en macOS mientras que ldid
se puede encontrar en iOS
SuspiciousPackage
SuspiciousPackage es una herramienta útil para inspeccionar archivos .pkg (instaladores) y ver qué hay dentro antes de instalarlos.
Estos instaladores tienen scripts bash preinstall
y postinstall
que los autores de malware suelen abusar para persistir el malware.
hdiutil
Esta herramienta permite montar imágenes de disco de Apple (.dmg) para inspeccionarlas antes de ejecutar cualquier cosa:
It will be mounted in /Volumes
Binaries empaquetados
Verificar alta entropía
Verificar las cadenas (si casi no hay cadenas comprensibles, empaquetado)
El empaquetador UPX para MacOS genera una sección llamada "__XHDR"
Análisis estático de Objective-C
Metadatos
Tenga en cuenta que los programas escritos en Objective-C retienen sus declaraciones de clase cuando se compilan en binaries Mach-O. Tales declaraciones de clase incluyen el nombre y tipo de:
Las interfaces definidas
Los métodos de la interfaz
Las variables de instancia de la interfaz
Los protocolos definidos
Tenga en cuenta que estos nombres podrían estar ofuscados para dificultar la reversión del binario.
Llamada a funciones
Cuando se llama a una función en un binario que utiliza Objective-C, el código compilado en lugar de llamar a esa función, llamará a objc_msgSend
. Que llamará a la función final:
Los parámetros que esta función espera son:
El primer parámetro (self) es "un puntero que apunta a la instancia de la clase que debe recibir el mensaje". O más simplemente, es el objeto sobre el cual se invoca el método. Si el método es un método de clase, esto será una instancia del objeto de la clase (en su totalidad), mientras que para un método de instancia, self apuntará a una instancia instanciada de la clase como un objeto.
El segundo parámetro, (op), es "el selector del método que maneja el mensaje". Nuevamente, más simplemente, esto es solo el nombre del método.
Los parámetros restantes son cualquier valor que requiera el método (op).
Vea cómo obtener esta información fácilmente con lldb
en ARM64 en esta página:
x64:
Argumento | Registro | (para) objc_msgSend |
1er argumento | rdi | self: objeto sobre el cual se invoca el método |
2do argumento | rsi | op: nombre del método |
3er argumento | rdx | 1er argumento al método |
4to argumento | rcx | 2do argumento al método |
5to argumento | r8 | 3er argumento al método |
6to argumento | r9 | 4to argumento al método |
7mo+ argumento | rsp+ (en la pila) | 5to+ argumento al método |
Volcar metadatos de ObjectiveC
Dynadump
Dynadump es una herramienta para volcar clases de binarios de Objective-C. El github especifica dylibs pero esto también funciona con ejecutables.
En el momento de la escritura, este es actualmente el que mejor funciona.
Herramientas regulares
class-dump
class-dump es la herramienta original que genera declaraciones para las clases, categorías y protocolos en código formateado en ObjetiveC.
Es antigua y no se mantiene, por lo que probablemente no funcionará correctamente.
ICDump
iCDump es un volcado de clases de Objective-C moderno y multiplataforma. En comparación con las herramientas existentes, iCDump puede ejecutarse de forma independiente del ecosistema de Apple y expone enlaces de Python.
Análisis estático de Swift
Con los binarios de Swift, dado que hay compatibilidad con Objective-C, a veces puedes extraer declaraciones usando class-dump pero no siempre.
Con los comandos jtool -l
o otool -l
es posible encontrar varias secciones que comienzan con el prefijo __swift5
:
Puedes encontrar más información sobre la información almacenada en esta sección en esta publicación de blog.
Además, los binarios de Swift pueden tener símbolos (por ejemplo, las bibliotecas necesitan almacenar símbolos para que sus funciones puedan ser llamadas). Los símbolos generalmente tienen la información sobre el nombre de la función y atributos de una manera poco legible, por lo que son muy útiles y hay "demanglers" que pueden obtener el nombre original:
Análisis Dinámico
Tenga en cuenta que para depurar binarios, SIP debe estar deshabilitado (csrutil disable
o csrutil enable --without debug
) o copiar los binarios a una carpeta temporal y eliminar la firma con codesign --remove-signature <binary-path>
o permitir la depuración del binario (puede usar este script)
Tenga en cuenta que para instrumentar binarios del sistema, (como cloudconfigurationd
) en macOS, SIP debe estar deshabilitado (simplemente eliminar la firma no funcionará).
APIs
macOS expone algunas APIs interesantes que brindan información sobre los procesos:
proc_info
: Este es el principal que proporciona mucha información sobre cada proceso. Necesita ser root para obtener información de otros procesos, pero no necesita derechos especiales o puertos mach.libsysmon.dylib
: Permite obtener información sobre procesos a través de funciones expuestas por XPC, sin embargo, es necesario tener el derechocom.apple.sysmond.client
.
Stackshot y microstackshots
Stackshotting es una técnica utilizada para capturar el estado de los procesos, incluidos los stacks de llamadas de todos los hilos en ejecución. Esto es particularmente útil para la depuración, análisis de rendimiento y comprensión del comportamiento del sistema en un momento específico. En iOS y macOS, el stackshotting se puede realizar utilizando varias herramientas y métodos como las herramientas sample
y spindump
.
Sysdiagnose
Esta herramienta (/usr/bini/ysdiagnose
) básicamente recopila mucha información de su computadora ejecutando decenas de comandos diferentes como ps
, zprint
...
Debe ejecutarse como root y el daemon /usr/libexec/sysdiagnosed
tiene derechos muy interesantes como com.apple.system-task-ports
y get-task-allow
.
Su plist se encuentra en /System/Library/LaunchDaemons/com.apple.sysdiagnose.plist
que declara 3 MachServices:
com.apple.sysdiagnose.CacheDelete
: Elimina archivos antiguos en /var/rmpcom.apple.sysdiagnose.kernel.ipc
: Puerto especial 23 (kernel)com.apple.sysdiagnose.service.xpc
: Interfaz de modo usuario a través de la clase Obj-CLibsysdiagnose
. Se pueden pasar tres argumentos en un dict (compress
,display
,run
)
Registros Unificados
MacOS genera muchos registros que pueden ser muy útiles al ejecutar una aplicación tratando de entender qué está haciendo.
Además, hay algunos registros que contendrán la etiqueta <private>
para ocultar información identificable de usuario o computadora. Sin embargo, es posible instalar un certificado para divulgar esta información. Siga las explicaciones de aquí.
Hopper
Panel izquierdo
En el panel izquierdo de Hopper es posible ver los símbolos (Etiquetas) del binario, la lista de procedimientos y funciones (Proc) y las cadenas (Str). No son todas las cadenas, sino las definidas en varias partes del archivo Mac-O (como cstring o objc_methname
).
Panel medio
En el panel medio puede ver el código desensamblado. Y puede verlo en un desensamblado crudo, como gráfico, como decompilado y como binario haciendo clic en el ícono respectivo:
Al hacer clic derecho en un objeto de código, puede ver referencias a/desde ese objeto o incluso cambiar su nombre (esto no funciona en pseudocódigo decompilado):
Además, en la parte media inferior puede escribir comandos de python.
Panel derecho
En el panel derecho puede ver información interesante como el historial de navegación (para que sepa cómo llegó a la situación actual), el gráfico de llamadas donde puede ver todas las funciones que llaman a esta función y todas las funciones que esta función llama, y la información de variables locales.
dtrace
Permite a los usuarios acceder a aplicaciones a un nivel muy bajo y proporciona una forma para que los usuarios rastreen programas e incluso cambien su flujo de ejecución. Dtrace utiliza probes que están colocadas a lo largo del kernel y están en ubicaciones como el inicio y el final de las llamadas al sistema.
DTrace utiliza la función dtrace_probe_create
para crear un probe para cada llamada al sistema. Estos probes pueden activarse en el punto de entrada y salida de cada llamada al sistema. La interacción con DTrace ocurre a través de /dev/dtrace, que solo está disponible para el usuario root.
Para habilitar Dtrace sin deshabilitar completamente la protección SIP, podría ejecutar en modo de recuperación: csrutil enable --without dtrace
También puede dtrace
o dtruss
binarios que ha compilado.
Los probes disponibles de dtrace se pueden obtener con:
El nombre de la sonda consta de cuatro partes: el proveedor, módulo, función y nombre (fbt:mach_kernel:ptrace:entry
). Si no especificas alguna parte del nombre, Dtrace aplicará esa parte como un comodín.
Para configurar DTrace para activar sondas y especificar qué acciones realizar cuando se disparen, necesitaremos usar el lenguaje D.
Una explicación más detallada y más ejemplos se pueden encontrar en https://illumos.org/books/dtrace/chp-intro.html
Ejemplos
Ejecuta man -k dtrace
para listar los scripts de DTrace disponibles. Ejemplo: sudo dtruss -n binary
En línea
script
dtruss
kdebug
Es una instalación de trazado del kernel. Los códigos documentados se pueden encontrar en /usr/share/misc/trace.codes
.
Herramientas como latency
, sc_usage
, fs_usage
y trace
la utilizan internamente.
Para interactuar con kdebug
, se usa sysctl
sobre el espacio de nombres kern.kdebug
y los MIBs que se pueden encontrar en sys/sysctl.h
, teniendo las funciones implementadas en bsd/kern/kdebug.c
.
Para interactuar con kdebug con un cliente personalizado, estos son generalmente los pasos:
Eliminar configuraciones existentes con KERN_KDSETREMOVE
Establecer traza con KERN_KDSETBUF y KERN_KDSETUP
Usar KERN_KDGETBUF para obtener el número de entradas del búfer
Obtener el propio cliente de la traza con KERN_KDPINDEX
Habilitar el trazado con KERN_KDENABLE
Leer el búfer llamando a KERN_KDREADTR
Para emparejar cada hilo con su proceso, llamar a KERN_KDTHRMAP.
Para obtener esta información, es posible usar la herramienta de Apple trace
o la herramienta personalizada kDebugView (kdv).
Nota que Kdebug solo está disponible para 1 cliente a la vez. Así que solo se puede ejecutar una herramienta impulsada por k-debug al mismo tiempo.
ktrace
Las APIs ktrace_*
provienen de libktrace.dylib
, que envuelven las de Kdebug
. Luego, un cliente puede simplemente llamar a ktrace_session_create
y ktrace_events_[single/class]
para establecer callbacks en códigos específicos y luego iniciarlo con ktrace_start
.
Puedes usar este incluso con SIP activado
Puedes usar como clientes la utilidad ktrace
:
Or tailspin
.
kperf
Esto se utiliza para hacer un perfil a nivel de kernel y está construido utilizando llamadas Kdebug
.
Básicamente, se verifica la variable global kernel_debug_active
y si está configurada, llama a kperf_kdebug_handler
con el código Kdebug
y la dirección del marco del kernel que llama. Si el código Kdebug
coincide con uno seleccionado, obtiene las "acciones" configuradas como un bitmap (consulta osfmk/kperf/action.h
para las opciones).
Kperf también tiene una tabla MIB de sysctl: (como root) sysctl kperf
. Estos códigos se pueden encontrar en osfmk/kperf/kperfbsd.c
.
Además, un subconjunto de la funcionalidad de Kperf reside en kpc
, que proporciona información sobre los contadores de rendimiento de la máquina.
ProcessMonitor
ProcessMonitor es una herramienta muy útil para verificar las acciones relacionadas con el proceso que un proceso está realizando (por ejemplo, monitorear qué nuevos procesos está creando un proceso).
SpriteTree
SpriteTree es una herramienta que imprime las relaciones entre procesos.
Necesitas monitorear tu mac con un comando como sudo eslogger fork exec rename create > cap.json
(el terminal que lanza esto requiere FDA). Y luego puedes cargar el json en esta herramienta para ver todas las relaciones:
FileMonitor
FileMonitor permite monitorear eventos de archivos (como creación, modificaciones y eliminaciones) proporcionando información detallada sobre dichos eventos.
Crescendo
Crescendo es una herramienta GUI con la apariencia y sensación que los usuarios de Windows pueden conocer de Procmon de Microsoft Sysinternal. Esta herramienta permite que la grabación de varios tipos de eventos se inicie y detenga, permite filtrar estos eventos por categorías como archivo, proceso, red, etc., y proporciona la funcionalidad para guardar los eventos grabados en un formato json.
Apple Instruments
Apple Instruments son parte de las herramientas de desarrollador de Xcode – utilizadas para monitorear el rendimiento de aplicaciones, identificar fugas de memoria y rastrear la actividad del sistema de archivos.
fs_usage
Permite seguir las acciones realizadas por los procesos:
TaskExplorer
Taskexplorer es útil para ver las bibliotecas utilizadas por un binario, los archivos que está usando y las conexiones de red. También verifica los procesos binarios contra virustotal y muestra información sobre el binario.
PT_DENY_ATTACH
En esta publicación del blog puedes encontrar un ejemplo sobre cómo depurar un daemon en ejecución que utilizó PT_DENY_ATTACH
para prevenir la depuración incluso si SIP estaba deshabilitado.
lldb
lldb es la herramienta de facto para la depuración de binarios en macOS.
Puedes establecer el sabor de intel al usar lldb creando un archivo llamado .lldbinit
en tu carpeta de inicio con la siguiente línea:
Dentro de lldb, volcar un proceso con process save-core
(lldb) Comando | Descripción |
run (r) | Iniciar la ejecución, que continuará sin interrupciones hasta que se alcance un punto de interrupción o el proceso termine. |
process launch --stop-at-entry | Iniciar la ejecución deteniéndose en el punto de entrada |
continue (c) | Continuar la ejecución del proceso depurado. |
nexti (n / ni) | Ejecutar la siguiente instrucción. Este comando omitirá las llamadas a funciones. |
stepi (s / si) | Ejecutar la siguiente instrucción. A diferencia del comando nexti, este comando entrará en las llamadas a funciones. |
finish (f) | Ejecutar el resto de las instrucciones en la función actual (“frame”) y detenerse. |
control + c | Pausar la ejecución. Si el proceso ha sido ejecutado (r) o continuado (c), esto hará que el proceso se detenga ...donde sea que esté ejecutándose actualmente. |
breakpoint (b) |
breakpoint delete <num> |
help | help breakpoint #Obtener ayuda sobre el comando de punto de interrupción help memory write #Obtener ayuda para escribir en la memoria |
reg | |
x/s <reg/dirección de memoria> | Mostrar la memoria como una cadena terminada en nulo. |
x/i <reg/dirección de memoria> | Mostrar la memoria como instrucción de ensamblador. |
x/b <reg/dirección de memoria> | Mostrar la memoria como byte. |
print object (po) | Esto imprimirá el objeto referenciado por el parámetro po $raw
Nota que la mayoría de las APIs o métodos de Objective-C de Apple devuelven objetos, y por lo tanto deben ser mostrados a través del comando “print object” (po). Si po no produce una salida significativa, usa |
memory | memory read 0x000.... memory read $x0+0xf2a memory write 0x100600000 -s 4 0x41414141 #Escribir AAAA en esa dirección memory write -f s $rip+0x11f+7 "AAAA" #Escribir AAAA en la dirección |
disassembly | dis #Desensamblar la función actual dis -n <funcname> #Desensamblar función dis -n <funcname> -b <basename> #Desensamblar función dis -c 6 #Desensamblar 6 líneas dis -c 0x100003764 -e 0x100003768 # Desde una dirección hasta la otra dis -p -c 4 # Comenzar en la dirección actual desensamblando |
parray | parray 3 (char **)$x1 # Verificar array de 3 componentes en el registro x1 |
image dump sections | Imprimir el mapa de la memoria del proceso actual |
image dump symtab <library> |
|
Al llamar a la función objc_sendMsg
, el registro rsi contiene el nombre del método como una cadena terminada en nulo (“C”). Para imprimir el nombre a través de lldb haz:
(lldb) x/s $rsi: 0x1000f1576: "startMiningWithPort:password:coreCount:slowMemory:currency:"
(lldb) print (char*)$rsi:
(char *) $1 = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"
(lldb) reg read $rsi: rsi = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"
Análisis Anti-Dinámico
Detección de VM
El comando
sysctl hw.model
devuelve "Mac" cuando el host es un MacOS pero algo diferente cuando es una VM.Jugando con los valores de
hw.logicalcpu
yhw.physicalcpu
, algunos malwares intentan detectar si es una VM.Algunos malwares también pueden detectar si la máquina está basada en VMware según la dirección MAC (00:50:56).
También es posible encontrar si un proceso está siendo depurado con un código simple como:
if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //proceso siendo depurado }
También puede invocar la llamada al sistema
ptrace
con la banderaPT_DENY_ATTACH
. Esto previene que un depurador se adjunte y trace.Puedes verificar si la función
sysctl
optrace
está siendo importada (pero el malware podría importarla dinámicamente)Como se señala en este informe, “Defeating Anti-Debug Techniques: macOS ptrace variants” : “El mensaje Process # exited with status = 45 (0x0000002d) es generalmente una señal clara de que el objetivo de depuración está usando PT_DENY_ATTACH”
Volcados de Núcleo
Los volcados de núcleo se crean si:
kern.coredump
sysctl está configurado en 1 (por defecto)Si el proceso no era suid/sgid o
kern.sugid_coredump
es 1 (por defecto es 0)El límite
AS_CORE
permite la operación. Es posible suprimir la creación de volcados de núcleo llamando aulimit -c 0
y reactivarlos conulimit -c unlimited
.
En esos casos, el volcado de núcleo se genera de acuerdo con kern.corefile
sysctl y se almacena generalmente en /cores/core/.%P
.
Fuzzing
ReportCrash analiza procesos que fallan y guarda un informe de fallos en el disco. Un informe de fallos contiene información que puede ayudar a un desarrollador a diagnosticar la causa de un fallo.
Para aplicaciones y otros procesos que se ejecutan en el contexto de launchd por usuario, ReportCrash se ejecuta como un LaunchAgent y guarda informes de fallos en ~/Library/Logs/DiagnosticReports/
del usuario.
Para demonios, otros procesos que se ejecutan en el contexto de launchd del sistema y otros procesos privilegiados, ReportCrash se ejecuta como un LaunchDaemon y guarda informes de fallos en /Library/Logs/DiagnosticReports
del sistema.
Si te preocupa que los informes de fallos se envíen a Apple, puedes desactivarlos. Si no, los informes de fallos pueden ser útiles para averiguar cómo se cayó un servidor.
Sueño
Mientras se realiza fuzzing en un MacOS, es importante no permitir que el Mac entre en modo de suspensión:
systemsetup -setsleep Never
pmset, Preferencias del Sistema
Desconexión de SSH
Si estás realizando fuzzing a través de una conexión SSH, es importante asegurarte de que la sesión no se desconecte. Así que cambia el archivo sshd_config con:
TCPKeepAlive Yes
ClientAliveInterval 0
ClientAliveCountMax 0
Internal Handlers
Consulta la siguiente página para descubrir cómo puedes encontrar qué aplicación es responsable de manejar el esquema o protocolo especificado:
macOS File Extension & URL scheme app handlersEnumerating Network Processes
Esto es interesante para encontrar procesos que están gestionando datos de red:
O use netstat
o lsof
Libgmalloc
Fuzzers
Funciona para herramientas de línea de comandos
Simplemente "funciona" con herramientas GUI de macOS. Tenga en cuenta que algunas aplicaciones de macOS tienen requisitos específicos, como nombres de archivos únicos, la extensión correcta, necesitan leer los archivos desde el sandbox (~/Library/Containers/com.apple.Safari/Data
)...
Algunos ejemplos:
Más información sobre Fuzzing en MacOS
Referencias
Last updated