macOS Apps - Inspecting, debugging and Fuzzing
Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Statische Analyse
otool & objdump & nm
jtool2 & Disarm
Sie können disarm von hier herunterladen.
Sie können jtool2 hier herunterladen oder es mit brew
installieren.
jtool ist zugunsten von disarm veraltet
Codesign / ldid
Codesign
ist in macOS zu finden, während ldid
in iOS zu finden ist
SuspiciousPackage
SuspiciousPackage ist ein nützliches Tool, um .pkg-Dateien (Installer) zu inspizieren und zu sehen, was darin enthalten ist, bevor man sie installiert.
Diese Installer haben preinstall
und postinstall
Bash-Skripte, die von Malware-Autoren häufig missbraucht werden, um die Malware persistieren zu lassen.
hdiutil
Dieses Tool ermöglicht es, Apple-Disk-Images (.dmg) zu mounten, um sie zu inspizieren, bevor man etwas ausführt:
Es wird in /Volumes
gemountet
Gepackte Binärdateien
Überprüfen Sie die hohe Entropie
Überprüfen Sie die Strings (wenn es fast keinen verständlichen String gibt, gepackt)
Der UPX-Packer für MacOS generiert einen Abschnitt namens "__XHDR"
Statische Objective-C-Analyse
Metadaten
Beachten Sie, dass Programme, die in Objective-C geschrieben sind, ihre Klassendeklarationen beibehalten, wenn sie in Mach-O-Binärdateien kompiliert werden. Solche Klassendeklarationen beinhaltet den Namen und Typ von:
Den definierten Schnittstellen
Den Schnittstellenmethoden
Den Instanzvariablen der Schnittstelle
Den definierten Protokollen
Beachten Sie, dass diese Namen obfuskiert sein könnten, um das Reverse Engineering der Binärdatei zu erschweren.
Funktionsaufruf
Wenn eine Funktion in einer Binärdatei aufgerufen wird, die Objective-C verwendet, wird der kompilierte Code anstelle des Aufrufs dieser Funktion objc_msgSend
aufrufen. Dies wird die endgültige Funktion aufrufen:
Die Parameter, die diese Funktion erwartet, sind:
Der erste Parameter (self) ist "ein Zeiger, der auf die Instanz der Klasse zeigt, die die Nachricht empfangen soll". Einfacher ausgedrückt, es ist das Objekt, auf dem die Methode aufgerufen wird. Wenn die Methode eine Klassenmethode ist, wird dies eine Instanz des Klassenobjekts (als Ganzes) sein, während bei einer Instanzmethode self auf eine instanziierte Instanz der Klasse als Objekt zeigt.
Der zweite Parameter (op) ist "der Selektor der Methode, die die Nachricht verarbeitet". Einfacher ausgedrückt, dies ist nur der Name der Methode.
Die verbleibenden Parameter sind alle Werte, die von der Methode benötigt werden (op).
Siehe, wie Sie diese Informationen einfach mit lldb
in ARM64 erhalten auf dieser Seite:
x64:
Argument | Register | (für) objc_msgSend |
1. Argument | rdi | self: Objekt, auf dem die Methode aufgerufen wird |
2. Argument | rsi | op: Name der Methode |
3. Argument | rdx | 1. Argument für die Methode |
4. Argument | rcx | 2. Argument für die Methode |
5. Argument | r8 | 3. Argument für die Methode |
6. Argument | r9 | 4. Argument für die Methode |
7. Argument und mehr | rsp+ (auf dem Stack) | 5. Argument und mehr für die Methode |
Dump ObjectiveC-Metadaten
Dynadump
Dynadump ist ein Tool zum Klassendump von Objective-C-Binärdateien. Das GitHub gibt dylibs an, aber dies funktioniert auch mit ausführbaren Dateien.
Zum Zeitpunkt des Schreibens ist dies derzeit der, der am besten funktioniert.
Reguläre Werkzeuge
class-dump
class-dump ist das ursprüngliche Tool, das Deklarationen für die Klassen, Kategorien und Protokolle im Objective-C formatierten Code generiert.
Es ist alt und wird nicht mehr gewartet, daher wird es wahrscheinlich nicht richtig funktionieren.
ICDump
iCDump ist ein modernes und plattformübergreifendes Objective-C-Klassendump. Im Vergleich zu bestehenden Tools kann iCDump unabhängig vom Apple-Ökosystem ausgeführt werden und bietet Python-Bindings.
Statische Swift-Analyse
Mit Swift-Binärdateien, da es eine Kompatibilität zu Objective-C gibt, kann man manchmal Deklarationen mit class-dump extrahieren, aber nicht immer.
Mit den jtool -l
oder otool -l
Befehlen ist es möglich, mehrere Abschnitte zu finden, die mit dem Präfix __swift5
beginnen:
Sie finden weitere Informationen über die Informationen, die in diesem Abschnitt gespeichert sind, in diesem Blogbeitrag.
Darüber hinaus könnten Swift-Binärdateien Symbole haben (zum Beispiel müssen Bibliotheken Symbole speichern, damit ihre Funktionen aufgerufen werden können). Die Symbole enthalten normalerweise Informationen über den Funktionsnamen und Attribute auf eine unansehnliche Weise, sodass sie sehr nützlich sind, und es gibt "Demangler", die den ursprünglichen Namen wiederherstellen können:
Dynamische Analyse
Beachten Sie, dass zum Debuggen von Binärdateien SIP deaktiviert sein muss (csrutil disable
oder csrutil enable --without debug
) oder die Binärdateien in einen temporären Ordner kopiert und die Signatur entfernt werden muss mit codesign --remove-signature <binary-path>
oder das Debuggen der Binärdatei erlaubt werden muss (Sie können dieses Skript verwenden).
Beachten Sie, dass zum Instrumentieren von System-Binärdateien (wie cloudconfigurationd
) auf macOS SIP deaktiviert sein muss (das Entfernen der Signatur funktioniert nicht).
APIs
macOS stellt einige interessante APIs zur Verfügung, die Informationen über die Prozesse geben:
proc_info
: Dies ist die Haupt-API, die viele Informationen über jeden Prozess liefert. Sie müssen root sein, um Informationen über andere Prozesse zu erhalten, benötigen jedoch keine speziellen Berechtigungen oder Mach-Ports.libsysmon.dylib
: Es ermöglicht, Informationen über Prozesse über XPC-exponierte Funktionen zu erhalten, jedoch ist es erforderlich, die Berechtigungcom.apple.sysmond.client
zu haben.
Stackshot & Mikrostackshots
Stackshotting ist eine Technik, die verwendet wird, um den Zustand der Prozesse zu erfassen, einschließlich der Aufrufstapel aller laufenden Threads. Dies ist besonders nützlich für Debugging, Leistungsanalyse und das Verständnis des Verhaltens des Systems zu einem bestimmten Zeitpunkt. Auf iOS und macOS kann Stackshotting mit mehreren Tools und Methoden wie den Tools sample
und spindump
durchgeführt werden.
Sysdiagnose
Dieses Tool (/usr/bini/ysdiagnose
) sammelt im Wesentlichen viele Informationen von Ihrem Computer, indem es Dutzende verschiedener Befehle wie ps
, zprint
... ausführt.
Es muss als root ausgeführt werden, und der Daemon /usr/libexec/sysdiagnosed
hat sehr interessante Berechtigungen wie com.apple.system-task-ports
und get-task-allow
.
Seine plist befindet sich in /System/Library/LaunchDaemons/com.apple.sysdiagnose.plist
, die 3 MachServices deklariert:
com.apple.sysdiagnose.CacheDelete
: Löscht alte Archive in /var/rmpcom.apple.sysdiagnose.kernel.ipc
: Spezialport 23 (Kernel)com.apple.sysdiagnose.service.xpc
: Benutzeroberflächen-Schnittstelle über dieLibsysdiagnose
Obj-C-Klasse. Drei Argumente in einem Dict können übergeben werden (compress
,display
,run
)
Vereinheitlichte Protokolle
MacOS generiert viele Protokolle, die sehr nützlich sein können, wenn Sie eine Anwendung ausführen und versuchen zu verstehen, was sie tut.
Darüber hinaus gibt es einige Protokolle, die das Tag <private>
enthalten, um einige Benutzer- oder Computer-identifizierbare Informationen zu verbergen. Es ist jedoch möglich, ein Zertifikat zu installieren, um diese Informationen offenzulegen. Folgen Sie den Erklärungen hier.
Hopper
Linke Spalte
In der linken Spalte von Hopper ist es möglich, die Symbole (Labels) der Binärdatei, die Liste der Prozeduren und Funktionen (Proc) und die Strings (Str) zu sehen. Dies sind nicht alle Strings, sondern die, die in verschiedenen Teilen der Mac-O-Datei definiert sind (wie cstring oder objc_methname
).
Mittlere Spalte
In der mittleren Spalte können Sie den disassemblierten Code sehen. Und Sie können ihn als rohen Disassemble, als Grafik, als dekompiliert und als Binärdatei anzeigen, indem Sie auf das jeweilige Symbol klicken:
Wenn Sie mit der rechten Maustaste auf ein Codeobjekt klicken, können Sie Referenzen zu/von diesem Objekt sehen oder sogar seinen Namen ändern (dies funktioniert nicht im dekompilierten Pseudocode):
Darüber hinaus können Sie in der mittleren unteren Ecke Python-Befehle schreiben.
Rechte Spalte
In der rechten Spalte können Sie interessante Informationen wie die Navigationshistorie sehen (damit Sie wissen, wie Sie zur aktuellen Situation gekommen sind), das Aufrufdiagramm, in dem Sie alle Funktionen sehen können, die diese Funktion aufrufen, und alle Funktionen, die diese Funktion aufruft, sowie Informationen zu lokalen Variablen.
dtrace
Es ermöglicht Benutzern den Zugriff auf Anwendungen auf einem extrem niedrigen Niveau und bietet eine Möglichkeit für Benutzer, Programme zu verfolgen und sogar ihren Ausführungsfluss zu ändern. Dtrace verwendet Proben, die im gesamten Kernel platziert sind und sich an Orten wie dem Anfang und Ende von Systemaufrufen befinden.
DTrace verwendet die Funktion dtrace_probe_create
, um eine Probe für jeden Systemaufruf zu erstellen. Diese Proben können am Einstiegs- und Austrittspunkt jedes Systemaufrufs ausgelöst werden. Die Interaktion mit DTrace erfolgt über /dev/dtrace, das nur für den Root-Benutzer verfügbar ist.
Um Dtrace zu aktivieren, ohne den SIP-Schutz vollständig zu deaktivieren, können Sie im Wiederherstellungsmodus ausführen: csrutil enable --without dtrace
Sie können auch dtrace
oder dtruss
Binärdateien verwenden, die Sie kompiliert haben.
Die verfügbaren Proben von dtrace können mit:
Der Probenname besteht aus vier Teilen: dem Anbieter, dem Modul, der Funktion und dem Namen (fbt:mach_kernel:ptrace:entry
). Wenn Sie einen Teil des Namens nicht angeben, wird Dtrace diesen Teil als Platzhalter anwenden.
Um DTrace zu konfigurieren, um Proben zu aktivieren und anzugeben, welche Aktionen ausgeführt werden sollen, wenn sie ausgelöst werden, müssen wir die D-Sprache verwenden.
Eine detailliertere Erklärung und weitere Beispiele finden Sie unter https://illumos.org/books/dtrace/chp-intro.html
Beispiele
Führen Sie man -k dtrace
aus, um die verfügbaren DTrace-Skripte aufzulisten. Beispiel: sudo dtruss -n binary
Skript
dtruss
kdebug
Es ist eine Kernel-Trace-Einrichtung. Die dokumentierten Codes finden sich in /usr/share/misc/trace.codes
.
Tools wie latency
, sc_usage
, fs_usage
und trace
verwenden es intern.
Um mit kdebug
zu interagieren, wird sysctl
über den kern.kdebug
-Namespace verwendet, und die MIBs, die verwendet werden können, finden sich in sys/sysctl.h
, wobei die Funktionen in bsd/kern/kdebug.c
implementiert sind.
Um mit kdebug über einen benutzerdefinierten Client zu interagieren, sind dies normalerweise die Schritte:
Entfernen vorhandener Einstellungen mit KERN_KDSETREMOVE
Trace mit KERN_KDSETBUF und KERN_KDSETUP setzen
Verwenden Sie KERN_KDGETBUF, um die Anzahl der Puffer-Einträge zu erhalten
Den eigenen Client aus dem Trace mit KERN_KDPINDEX abrufen
Tracing mit KERN_KDENABLE aktivieren
Den Puffer lesen, indem KERN_KDREADTR aufgerufen wird
Um jeden Thread mit seinem Prozess abzugleichen, rufen Sie KERN_KDTHRMAP auf.
Um diese Informationen zu erhalten, ist es möglich, das Apple-Tool trace
oder das benutzerdefinierte Tool kDebugView (kdv)** zu verwenden.**
Beachten Sie, dass Kdebug nur für 1 Kunden gleichzeitig verfügbar ist. Daher kann nur ein k-debug-gestütztes Tool zur gleichen Zeit ausgeführt werden.
ktrace
Die ktrace_*
APIs stammen von libktrace.dylib
, die die von Kdebug
umhüllen. Ein Client kann dann einfach ktrace_session_create
und ktrace_events_[single/class]
aufrufen, um Rückrufe für spezifische Codes festzulegen und es dann mit ktrace_start
zu starten.
Sie können dies sogar mit SIP aktiviert verwenden.
Sie können als Clients das Dienstprogramm ktrace
verwenden:
Or tailspin
.
kperf
Dies wird verwendet, um ein Kernel-Level-Profiling durchzuführen und ist mit Kdebug
-Aufrufen erstellt.
Grundsätzlich wird die globale Variable kernel_debug_active
überprüft und wenn sie gesetzt ist, wird kperf_kdebug_handler
mit dem Kdebug
-Code und der Adresse des aufrufenden Kernel-Frames aufgerufen. Wenn der Kdebug
-Code mit einem ausgewählten übereinstimmt, werden die als Bitmap konfigurierten "Aktionen" abgerufen (siehe osfmk/kperf/action.h
für die Optionen).
Kperf hat auch eine sysctl MIB-Tabelle: (als root) sysctl kperf
. Diese Codes sind in osfmk/kperf/kperfbsd.c
zu finden.
Darüber hinaus befindet sich ein Teil der Funktionalität von Kperf in kpc
, das Informationen über Maschinenleistungszähler bereitstellt.
ProcessMonitor
ProcessMonitor ist ein sehr nützliches Tool, um die prozessbezogenen Aktionen zu überprüfen, die ein Prozess ausführt (zum Beispiel, um zu überwachen, welche neuen Prozesse ein Prozess erstellt).
SpriteTree
SpriteTree ist ein Tool, das die Beziehungen zwischen Prozessen ausgibt.
Sie müssen Ihren Mac mit einem Befehl wie sudo eslogger fork exec rename create > cap.json
überwachen (das Terminal, das dies startet, benötigt FDA). Und dann können Sie die JSON in diesem Tool laden, um alle Beziehungen anzuzeigen:
FileMonitor
FileMonitor ermöglicht es, Dateiereignisse (wie Erstellung, Änderungen und Löschungen) zu überwachen und bietet detaillierte Informationen über solche Ereignisse.
Crescendo
Crescendo ist ein GUI-Tool, das das Aussehen und das Gefühl hat, das Windows-Benutzer von Microsoft Sysinternal’s Procmon kennen. Dieses Tool ermöglicht es, verschiedene Ereignistypen zu starten und zu stoppen, ermöglicht das Filtern dieser Ereignisse nach Kategorien wie Datei, Prozess, Netzwerk usw. und bietet die Funktionalität, die aufgezeichneten Ereignisse im JSON-Format zu speichern.
Apple Instruments
Apple Instruments sind Teil der Entwicklerwerkzeuge von Xcode – verwendet zur Überwachung der Anwendungsleistung, zur Identifizierung von Speicherlecks und zur Verfolgung der Dateisystemaktivität.
fs_usage
Ermöglicht das Verfolgen von Aktionen, die von Prozessen ausgeführt werden:
TaskExplorer
Taskexplorer ist nützlich, um die Bibliotheken zu sehen, die von einer Binärdatei verwendet werden, die Dateien, die sie verwendet, und die Netzwerk-Verbindungen. Es überprüft auch die Binärprozesse gegen virustotal und zeigt Informationen über die Binärdatei an.
PT_DENY_ATTACH
In diesem Blogbeitrag finden Sie ein Beispiel, wie man einen laufenden Daemon debuggt, der PT_DENY_ATTACH
verwendet, um das Debuggen zu verhindern, selbst wenn SIP deaktiviert war.
lldb
lldb ist das de facto Tool für macOS Binär-Debugging.
Sie können den Intel-Geschmack festlegen, wenn Sie lldb verwenden, indem Sie eine Datei mit dem Namen .lldbinit
in Ihrem Home-Verzeichnis mit der folgenden Zeile erstellen:
Innerhalb von lldb, dumpen Sie einen Prozess mit process save-core
(lldb) Befehl | Beschreibung |
run (r) | Startet die Ausführung, die ununterbrochen fortgesetzt wird, bis ein Haltepunkt erreicht wird oder der Prozess beendet wird. |
process launch --stop-at-entry | Startet die Ausführung und stoppt am Einstiegspunkt |
continue (c) | Setzt die Ausführung des debugged Prozesses fort. |
nexti (n / ni) | Führt die nächste Anweisung aus. Dieser Befehl überspringt Funktionsaufrufe. |
stepi (s / si) | Führt die nächste Anweisung aus. Im Gegensatz zum nexti-Befehl wird dieser Befehl in Funktionsaufrufe eintreten. |
finish (f) | Führt den Rest der Anweisungen in der aktuellen Funktion (“Frame”) aus, gibt zurück und stoppt. |
control + c | Pause die Ausführung. Wenn der Prozess ausgeführt (r) oder fortgesetzt (c) wurde, wird dies den Prozess anhalten ...wo auch immer er sich gerade befindet. |
breakpoint (b) |
breakpoint delete <num> |
help | help breakpoint #Hilfe zum Breakpoint-Befehl erhalten help memory write #Hilfe zum Schreiben in den Speicher erhalten |
reg | |
x/s <reg/memory address> | Zeigt den Speicher als nullterminierten String an. |
x/i <reg/memory address> | Zeigt den Speicher als Assemblieranweisung an. |
x/b <reg/memory address> | Zeigt den Speicher als Byte an. |
print object (po) | Dies wird das Objekt drucken, auf das der Parameter verweist po $raw
Beachten Sie, dass die meisten von Apples Objective-C APIs oder Methoden Objekte zurückgeben und daher über den Befehl “print object” (po) angezeigt werden sollten. Wenn po keine sinnvolle Ausgabe erzeugt, verwenden Sie |
memory | memory read 0x000.... memory read $x0+0xf2a memory write 0x100600000 -s 4 0x41414141 #Schreibt AAAA in diese Adresse memory write -f s $rip+0x11f+7 "AAAA" #Schreibt AAAA in die Adresse |
disassembly | dis #Disassembliert die aktuelle Funktion dis -n <funcname> #Disassembliert die Funktion dis -n <funcname> -b <basename> #Disassembliert die Funktion dis -c 6 #Disassembliert 6 Zeilen dis -c 0x100003764 -e 0x100003768 # Von einer Adresse bis zur anderen dis -p -c 4 # Beginnt an der aktuellen Adresse mit dem Disassemblieren |
parray | parray 3 (char **)$x1 # Überprüft das Array von 3 Komponenten im x1-Register |
image dump sections | Gibt eine Karte des aktuellen Prozessspeichers aus |
image dump symtab <library> |
|
Beim Aufrufen der objc_sendMsg
-Funktion hält das rsi-Register den Namen der Methode als nullterminierten (“C”) String. Um den Namen über lldb auszugeben, tun Sie:
(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:"
Anti-Dynamic Analyse
VM-Erkennung
Der Befehl
sysctl hw.model
gibt "Mac" zurück, wenn der Host ein MacOS ist, aber etwas anderes, wenn es sich um eine VM handelt.Durch das Spielen mit den Werten von
hw.logicalcpu
undhw.physicalcpu
versuchen einige Malware, zu erkennen, ob es sich um eine VM handelt.Einige Malware kann auch erkennen, ob die Maschine VMware basiert ist, basierend auf der MAC-Adresse (00:50:56).
Es ist auch möglich zu finden, ob ein Prozess debuggt wird mit einem einfachen Code wie:
if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //prozess wird debuggt }
Es kann auch den
ptrace
Systemaufruf mit demPT_DENY_ATTACH
-Flag aufrufen. Dies verhindert, dass ein Debugger sich anheftet und verfolgt.Sie können überprüfen, ob die
sysctl
oderptrace
Funktion importiert wird (aber die Malware könnte sie dynamisch importieren)Wie in diesem Bericht erwähnt, “Defeating Anti-Debug Techniques: macOS ptrace variants” : “Die Nachricht Process # exited with status = 45 (0x0000002d) ist normalerweise ein sicheres Zeichen dafür, dass das Debug-Ziel PT_DENY_ATTACH verwendet.”
Core Dumps
Core Dumps werden erstellt, wenn:
kern.coredump
sysctl auf 1 gesetzt ist (standardmäßig)Wenn der Prozess nicht suid/sgid war oder
kern.sugid_coredump
auf 1 gesetzt ist (standardmäßig 0)Das
AS_CORE
-Limit die Operation erlaubt. Es ist möglich, die Erstellung von Core Dumps zu unterdrücken, indem Sieulimit -c 0
aufrufen und sie mitulimit -c unlimited
wieder aktivieren.
In diesen Fällen wird der Core Dump gemäß dem kern.corefile
sysctl generiert und normalerweise in /cores/core/.%P
gespeichert.
Fuzzing
ReportCrash analysiert abstürzende Prozesse und speichert einen Absturzbericht auf der Festplatte. Ein Absturzbericht enthält Informationen, die einem Entwickler helfen können, die Ursache eines Absturzes zu diagnostizieren.
Für Anwendungen und andere Prozesse, die im benutzerspezifischen launchd-Kontext ausgeführt werden, läuft ReportCrash als LaunchAgent und speichert Absturzberichte im ~/Library/Logs/DiagnosticReports/
des Benutzers.
Für Daemons, andere Prozesse, die im systemweiten launchd-Kontext und andere privilegierte Prozesse ausgeführt werden, läuft ReportCrash als LaunchDaemon und speichert Absturzberichte im /Library/Logs/DiagnosticReports
des Systems.
Wenn Sie sich Sorgen über Absturzberichte machen, die an Apple gesendet werden, können Sie sie deaktivieren. Andernfalls können Absturzberichte nützlich sein, um herauszufinden, wie ein Server abgestürzt ist.
Schlaf
Beim Fuzzing auf einem MacOS ist es wichtig, den Mac nicht in den Schlafmodus zu versetzen:
systemsetup -setsleep Never
pmset, Systemeinstellungen
SSH-Trennung
Wenn Sie über eine SSH-Verbindung fuzzing, ist es wichtig sicherzustellen, dass die Sitzung nicht abbricht. Ändern Sie daher die sshd_config-Datei mit:
TCPKeepAlive Yes
ClientAliveInterval 0
ClientAliveCountMax 0
Internal Handlers
Überprüfen Sie die folgende Seite, um herauszufinden, welche App für die Verarbeitung des angegebenen Schemas oder Protokolls verantwortlich ist:
macOS File Extension & URL scheme app handlersEnumerating Network Processes
Es ist interessant, Prozesse zu finden, die Netzwerkdaten verwalten:
Oder verwenden Sie netstat
oder lsof
Libgmalloc
Fuzzers
Funktioniert für CLI-Tools
Es "funktioniert einfach"