macOS Apps - Inspecting, debugging and Fuzzing
Analyse statique
otool
objdump
jtool2
L'outil peut être utilisé comme un remplacement pour codesign, otool, et objdump, et offre quelques fonctionnalités supplémentaires. Téléchargez-le ici ou installez-le avec brew
.
Codesign / ldid
Codesign
peut être trouvé dans macOS tandis que ldid
peut être trouvé dans iOS
SuspiciousPackage
SuspiciousPackage est un outil utile pour inspecter les fichiers .pkg (installateurs) et voir ce qu'ils contiennent avant de les installer.
Ces installateurs ont des scripts bash preinstall
et postinstall
que les auteurs de logiciels malveillants utilisent généralement pour persister le logiciel malveillant.
hdiutil
Cet outil permet de monter les images disque Apple (.dmg) pour les inspecter avant d'exécuter quoi que ce soit:
Il sera monté dans /Volumes
Objective-C
Métadonnées
Notez que les programmes écrits en Objective-C conservent leurs déclarations de classe lorsqu'ils sont compilés en binaires Mach-O. Ces déclarations de classe incluent le nom et le type de :
La classe
Les méthodes de classe
Les variables d'instance de classe
Vous pouvez obtenir ces informations en utilisant class-dump :
Appel de fonction
Lorsqu'une fonction est appelée dans un binaire qui utilise Objective-C, le code compilé, au lieu d'appeler directement cette fonction, appellera objc_msgSend
. Ce dernier appellera la fonction finale :
Les paramètres attendus par cette fonction sont les suivants :
Le premier paramètre (self) est "un pointeur qui pointe vers l'instance de la classe qui doit recevoir le message". En d'autres termes, il s'agit de l'objet sur lequel la méthode est invoquée. Si la méthode est une méthode de classe, il s'agira d'une instance de l'objet de la classe (dans son ensemble), tandis que pour une méthode d'instance, self pointera vers une instance instanciée de la classe en tant qu'objet.
Le deuxième paramètre, (op), est "le sélecteur de la méthode qui gère le message". En termes plus simples, il s'agit simplement du nom de la méthode.
Les paramètres restants sont toutes les valeurs requises par la méthode (op).
Découvrez comment obtenir ces informations facilement avec lldb
en ARM64 sur cette page :
x64 :
Argument
Registre
(pour) objc_msgSend
1er argument
rdi
self : objet sur lequel la méthode est invoquée
2e argument
rsi
op : nom de la méthode
3e argument
rdx
1er argument de la méthode
4e argument
rcx
2e argument de la méthode
5e argument
r8
3e argument de la méthode
6e argument
r9
4e argument de la méthode
7e+ argument
rsp+ (sur la pile)
5e+ argument de la méthode
Swift
Avec les binaires Swift, étant donné la compatibilité avec Objective-C, il est parfois possible d'extraire des déclarations en utilisant class-dump, mais pas toujours.
Avec les lignes de commande jtool -l
ou otool -l
, il est possible de trouver plusieurs sections qui commencent par le préfixe __swift5
:
Vous pouvez trouver plus d'informations sur les informations stockées dans cette section dans ce billet de blog.
De plus, les binaires Swift peuvent avoir des symboles (par exemple, les bibliothèques doivent stocker des symboles pour que leurs fonctions puissent être appelées). Les symboles ont généralement des informations sur le nom de la fonction et les attributs de manière peu attrayante, donc ils sont très utiles et il existe des "démangleurs" qui peuvent obtenir le nom d'origine:
Binaires packagés
Vérifiez l'entropie élevée
Vérifiez les chaînes (s'il n'y a presque aucune chaîne compréhensible, c'est empaqueté)
Le packer UPX pour MacOS génère une section appelée "__XHDR"
Analyse dynamique
Notez que pour déboguer les binaires, SIP doit être désactivé (csrutil disable
ou csrutil enable --without debug
) ou copier les binaires dans un dossier temporaire et supprimer la signature avec codesign --remove-signature <chemin-binaire>
ou autoriser le débogage du binaire (vous pouvez utiliser ce script)
Notez que pour instrumenter les binaires système (comme cloudconfigurationd
) sur macOS, SIP doit être désactivé (simplement supprimer la signature ne fonctionnera pas).
Journaux unifiés
MacOS génère beaucoup de journaux qui peuvent être très utiles lors de l'exécution d'une application pour comprendre ce qu'elle fait.
De plus, il y a des journaux qui contiendront la balise <private>
pour cacher certaines informations identifiables par l'utilisateur ou l'ordinateur. Cependant, il est possible d'installer un certificat pour divulguer ces informations. Suivez les explications ici.
Hopper
Panneau de gauche
Dans le panneau de gauche de Hopper, il est possible de voir les symboles (Labels) du binaire, la liste des procédures et fonctions (Proc) et les chaînes (Str). Ce ne sont pas toutes les chaînes, mais celles définies dans plusieurs parties du fichier Mac-O (comme _cstring ou objc_methname
).
Panneau central
Dans le panneau central, vous pouvez voir le code désassemblé. Et vous pouvez le voir en désassemblage brut, en graphique, en décompilé et en binaire en cliquant sur l'icône respective :
En cliquant avec le bouton droit sur un objet de code, vous pouvez voir les références vers/depuis cet objet ou même changer son nom (cela ne fonctionne pas dans le pseudocode décompilé) :
De plus, dans le bas du panneau central, vous pouvez écrire des commandes python.
Panneau de droite
Dans le panneau de droite, vous pouvez voir des informations intéressantes telles que l'historique de navigation (pour savoir comment vous êtes arrivé à la situation actuelle), le graphique d'appel où vous pouvez voir toutes les fonctions qui appellent cette fonction et toutes les fonctions que cette fonction appelle, et des informations sur les variables locales.
dtrace
Il permet aux utilisateurs d'accéder aux applications à un niveau extrêmement bas et offre un moyen aux utilisateurs de tracer les programmes et même de modifier leur flux d'exécution. Dtrace utilise des sondes qui sont placées dans tout le noyau et se trouvent à des endroits tels que le début et la fin des appels système.
DTrace utilise la fonction dtrace_probe_create
pour créer une sonde pour chaque appel système. Ces sondes peuvent être déclenchées au point d'entrée et de sortie de chaque appel système. L'interaction avec DTrace se fait via /dev/dtrace qui n'est disponible que pour l'utilisateur root.
Pour activer Dtrace sans désactiver complètement la protection SIP, vous pouvez exécuter en mode de récupération : csrutil enable --without dtrace
Vous pouvez également dtrace
ou dtruss
des binaires que vous avez compilés.
Les sondes disponibles de dtrace peuvent être obtenues avec :
Le nom de la sonde se compose de quatre parties : le fournisseur, le module, la fonction et le nom (fbt:mach_kernel:ptrace:entry
). Si vous ne spécifiez pas une partie du nom, Dtrace appliquera cette partie comme un joker.
Pour configurer DTrace afin d'activer les sondes et de spécifier les actions à effectuer lorsqu'elles se déclenchent, nous devrons utiliser le langage D.
Une explication plus détaillée et plus d'exemples peuvent être trouvés dans https://illumos.org/books/dtrace/chp-intro.html
Exemples
Exécutez man -k dtrace
pour lister les scripts DTrace disponibles. Exemple : sudo dtruss -n binary
En ligne
script
dtruss
ktrace
Vous pouvez utiliser celui-ci même avec SIP activé
ProcessMonitor
ProcessMonitor est un outil très utile pour vérifier les actions liées aux processus qu'un processus effectue (par exemple, surveiller les nouveaux processus qu'un processus crée).
SpriteTree
SpriteTree est un outil qui affiche les relations entre les processus.
Vous devez surveiller votre mac avec une commande comme sudo eslogger fork exec rename create > cap.json
(le terminal lançant cela nécessite FDA). Ensuite, vous pouvez charger le json dans cet outil pour voir toutes les relations :
FileMonitor
FileMonitor permet de surveiller les événements liés aux fichiers (comme les créations, modifications et suppressions) en fournissant des informations détaillées sur ces événements.
Crescendo
Crescendo est un outil GUI avec l'apparence que les utilisateurs de Windows peuvent connaître de Procmon de Microsoft Sysinternal. Cet outil permet de démarrer et d'arrêter l'enregistrement de différents types d'événements, de filtrer ces événements par catégories telles que fichier, processus, réseau, etc., et offre la fonctionnalité de sauvegarder les événements enregistrés au format json.
Apple Instruments
Apple Instruments font partie des outils de développement Xcode - utilisés pour surveiller les performances des applications, identifier les fuites de mémoire et suivre l'activité du système de fichiers.
fs_usage
Permet de suivre les actions effectuées par les processus :
TaskExplorer
Taskexplorer est utile pour voir les bibliothèques utilisées par un binaire, les fichiers qu'il utilise et les connexions réseau. Il vérifie également les processus binaires avec virustotal et affiche des informations sur le binaire.
PT_DENY_ATTACH
Dans cet article de blog, vous pouvez trouver un exemple sur la façon de déboguer un démon en cours d'exécution qui utilise PT_DENY_ATTACH
pour empêcher le débogage même si SIP était désactivé.
lldb
lldb est l'outil de débogage binaire macOS de facto.
Vous pouvez définir le style Intel lors de l'utilisation de lldb en créant un fichier appelé .lldbinit
dans votre dossier personnel avec la ligne suivante :
À l'intérieur de lldb, dump un processus avec process save-core
(lldb) Commande
Description
run (r)
Démarrer l'exécution, qui se poursuivra jusqu'à ce qu'un point d'arrêt soit atteint ou que le processus se termine.
continue (c)
Continuer l'exécution du processus en cours de débogage.
nexti (n / ni)
Exécuter l'instruction suivante. Cette commande sautera les appels de fonction.
stepi (s / si)
Exécuter l'instruction suivante. Contrairement à la commande nexti, cette commande entrera dans les appels de fonction.
finish (f)
Exécuter le reste des instructions dans la fonction actuelle ("frame") et s'arrêter.
control + c
Mettre en pause l'exécution. Si le processus a été exécuté (r) ou continué (c), cela provoquera l'arrêt du processus ... où qu'il soit actuellement en cours d'exécution.
breakpoint (b)
b main #Toute fonction appelée main
b <nom_du_binaire>`main #Fonction principale du binaire
b set -n main --shlib <nom_lib> #Fonction principale du binaire indiqué
b -[NSDictionary objectForKey:]
b -a 0x0000000100004bd9
br l #Liste des points d'arrêt
br e/dis <num> #Activer/Désactiver le point d'arrêt
breakpoint delete <num>
help
help breakpoint #Obtenir de l'aide sur la commande de point d'arrêt
help memory write #Obtenir de l'aide pour écrire dans la mémoire
reg
x/s <adresse_reg/mémoire
Afficher la mémoire sous forme de chaîne terminée par un caractère nul.
x/i <adresse_reg/mémoire
Afficher la mémoire sous forme d'instruction d'assemblage.
x/b <adresse_reg/mémoire
Afficher la mémoire sous forme d'octet.
print object (po)
Cela affichera l'objet référencé par le paramètre
po $raw
{
dnsChanger = {
"affiliate" = "";
"blacklist_dns" = ();
Remarquez que la plupart des API ou méthodes Objective-C d'Apple renvoient des objets et doivent donc être affichées via la commande "print object" (po). Si po ne produit pas de sortie significative, utilisez x/b
memory
memory read 0x000.... memory read $x0+0xf2a memory write 0x100600000 -s 4 0x41414141 #Écrire AAAA à cette adresse memory write -f s $rip+0x11f+7 "AAAA" #Écrire AAAA à l'adresse
disassembly
dis #Désassembler la fonction actuelle
dis -n <nom_de_la_fonction> #Désassembler la fonction
dis -n <nom_de_la_fonction> -b <nom_de_base> #Désassembler la fonction dis -c 6 #Désassembler 6 lignes dis -c 0x100003764 -e 0x100003768 # De une adresse à l'autre dis -p -c 4 # Commencer à l'adresse actuelle de désassemblage
parray
parray 3 (char **)$x1 # Vérifier le tableau de 3 composants dans le registre x1
Lors de l'appel de la fonction objc_sendMsg
, le registre rsi contient le nom de la méthode sous forme de chaîne terminée par un caractère nul ("C"). Pour afficher le nom via lldb, faites :
(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:"
Analyse dynamique anti
Détection de VM
La commande
sysctl hw.model
renvoie "Mac" lorsque l'hôte est un MacOS mais quelque chose de différent lorsqu'il s'agit d'une VM.En jouant avec les valeurs de
hw.logicalcpu
ethw.physicalcpu
, certains malwares tentent de détecter s'il s'agit d'une VM.Certains malwares peuvent également détecter si la machine est basée sur VMware en fonction de l'adresse MAC (00:50:56).
Il est également possible de savoir si un processus est en cours de débogage avec un code simple tel que :
if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //processus en cours de débogage }
Il est également possible d'invoquer l'appel système
ptrace
avec le drapeauPT_DENY_ATTACH
. Cela empêche un débuggeur de se connecter et de tracer.Vous pouvez vérifier si la fonction
sysctl
ouptrace
est importée (mais le malware pourrait l'importer dynamiquement)Comme indiqué dans cet article, “Déjouer les techniques anti-débogage : variantes de ptrace sur macOS” : "Le message Processus # a quitté avec le statut = 45 (0x0000002d) est généralement un signe révélateur que la cible de débogage utilise PT_DENY_ATTACH"
Fuzzing
ReportCrash analyse les processus qui plantent et enregistre un rapport de plantage sur le disque. Un rapport de plantage contient des informations qui peuvent aider un développeur à diagnostiquer la cause d'un plantage.
Pour les applications et autres processus fonctionnant dans le contexte de lancement par utilisateur, ReportCrash s'exécute en tant que LaunchAgent et enregistre les rapports de plantage dans ~/Library/Logs/DiagnosticReports/
de l'utilisateur.
Pour les démons, les autres processus fonctionnant dans le contexte de lancement système et d'autres processus privilégiés, ReportCrash s'exécute en tant que LaunchDaemon et enregistre les rapports de plantage dans /Library/Logs/DiagnosticReports
du système.
Si vous êtes préoccupé par les rapports de plantage envoyés à Apple, vous pouvez les désactiver. Sinon, les rapports de plantage peuvent être utiles pour comprendre comment un serveur a planté.
Sommeil
Lors du fuzzing dans un MacOS, il est important de ne pas permettre au Mac de se mettre en veille :
systemsetup -setsleep Never
pmset, Préférences Système
Déconnexion SSH
Si vous faites du fuzzing via une connexion SSH, il est important de s'assurer que la session ne se termine pas. Modifiez donc le fichier sshd_config avec :
TCPKeepAlive Yes
ClientAliveInterval 0
ClientAliveCountMax 0
Gestionnaires internes
Consultez la page suivante pour découvrir comment vous pouvez trouver quelle application est responsable de la gestion du schéma ou du protocole spécifié :
macOS File Extension & URL scheme app handlersÉnumération des processus réseau
Ou utilisez netstat
ou lsof
Libgmalloc
Fuzzers
Fonctionne pour les outils en ligne de commande
Il "fonctionne simplement" avec les outils GUI macOS. Notez que certaines applications macOS ont des exigences spécifiques telles que des noms de fichiers uniques, la bonne extension, la nécessité de lire les fichiers à partir du sandbox (~/Library/Containers/com.apple.Safari/Data
)...
Quelques exemples:
Plus d'informations sur le fuzzing MacOS
Références
Last updated