
Ein IDA-Toolkit zur Analyse von iOS-Kernelcaches.
Dieser Fork wurde aktualisiert, um mit IDA 9.x / Python 3 / iOS 27.0 beta 1 zu funktionieren.
ida_kernelcache ist ein IDAPython-Modul für IDA Pro, das die Arbeit mit iOS-Kernelcaches erleichtert. Das Modul stellt Funktionen bereit, um:
__PRELINK_INFO-Segments des Kernels in ein Python-Wörterbuch.__got-Abschnitten und Stub-Funktionen in __stubs-Abschnitten.Die Hauptverarbeitungsfunktion ist dafür ausgelegt, vor jeder manuellen Analyse oder Reverse Engineering ausgeführt zu werden. Mit den Standardeinstellungen übersieht IDA im Kernelcache viele nützliche Informationen. Diese Skripte helfen IDA, indem sie die bekannte Struktur des Kernelcaches nutzen, um nützliche Informationen automatisch zu verbreiten.
Zusätzlich zur Standardfunktionalität des Moduls enthält ida_kernelcache mehrere Skripte, die die Analyse des iOS-Kernelcaches erleichtern. Beispielsweise kannst du die Skripte verwenden, um von einer Funktion verwendete C-Structs automatisch zu erzeugen.
Viele der in ida_kernelcache verwendeten Techniken wurden für memctl entwickelt und direkt von dort übernommen.
ida_kernelcache wurde mit IDA Pro 6.95 auf Kernelcaches für die iOS-Versionen 10.1.1, 11.0, 11.2, 11.3.1 und 12.0 beta getestet. Derzeit werden nur Arm64-Kernelcaches ab iOS 10 unterstützt.
Du benötigst eine bereits dekomprimierte Kernelcache-Datei, die in IDA geladen ist. Die URL zum Herunterladen eines bestimmten IPSW von Apple findest du online, und es gibt eine Reihe öffentlicher Tools (einschließlich memctl), die den Kernelcache dekomprimieren können.
Wähle in IDA in der Menüleiste „Datei“ -> „Skriptdatei...“ und dann das Skript ida_kernelcache.py im Hauptverzeichnis aus. Dadurch wird das Modul ida_kernelcache unter den Namen ida_kernelcache und kc in den IDAPython-Interpreter geladen. Gib in der IDAPython-Eingabeaufforderung kc.kernelcache_process() ein und drücke die Eingabetaste, um mit der Analyse des Kernelcaches zu beginnen. Diese Funktion führt alle wichtigen Analysen aus, die von ida_kernelcache unterstützt werden. Die Funktion läuft einige Minuten, während IDA neue Funktionen identifiziert und analysiert.
ida_kernelcache versucht, Benutzernamen für Adressen nicht zu überschreiben. Das bedeutet, dass die Ergebnisse möglicherweise nicht so gründlich ausfallen, wenn der Kernelcache vor der Initialisierung mit kernelcache_process manuell analysiert wurde, da benutzerdefinierte Namen die automatische Namensweitergabe blockieren können. Es gibt jedoch auch keine Garantie, dass ida_kernelcache eine frühere Analyse nicht durcheinanderbringt. Wenn du dich also entscheidest, kernelcache_process auf einer bereits analysierten Kernelcache-Datei auszuführen, erstelle zuerst ein Backup.
ida_kernelcache soll über ida_kernelcache.py geladen werden; die Untermodule im Verzeichnis ida_kernelcache sind nicht für das direkte Laden gedacht. ida_kernelcache stellt jedoch die Funktionalität vieler dieser Untermodule bereit. Hier ist, was jedes von ihnen tut:
ida_utilities:
Dieses Modul kapselt einige Funktionen von IDA, um eine benutzerfreundlichere API bereitzustellen. Besonders nützlich sind is_mapped, read_word, read_struct, force_function und ReadWords. is_mapped prüft, ob eine Adresse gemappt ist, und optional, ob sie einen bekannten Wert enthält. read_word liest ein Wort variabler Größe von einer Adresse. read_struct liest einen Strukturtyp in ein Python-Wörterbuch oder ein Python-Accessor-Objekt, was das Parsen von Datenstrukturen erheblich erleichtert. force_function versucht mehrere Tricks, um eine Adresse in IDA in den Anfang einer Funktion zu konvertieren. ReadWords ist ein Generator, um über Datenwörter und ihre Adressen in einem Bereich zu iterieren.
build_struct: Dieses interne Modul enthält Hilfsprogramme, um ein IDA-Struct automatisch anhand einer Folge von Zugriffen auf das Struct zu befüllen.
class_struct:
Dieses Modul stellt Funktionen zur Verfügung, um IDA-Structs zu erzeugen, die C++-virtuelle Methodentabellen und Klassen repräsentieren. initialize_vtable_structs durchsucht die (symbolisierten) virtuellen Methodentabellen und erstellt IDA-Structs für virtuelle Methodenzeiger. initialize_class_structs führt eine Datenflussanalyse an den virtuellen Methoden durch, um Zugriffe auf die Felder jeder Klasse zu identifizieren, und erstellt dann IDA-Structs, die die Klassen repräsentieren. Anweisungen, die offenbar auf ein Feld verweisen, werden ebenfalls in Strukturoffset-Referenzen umgewandelt. Weitere Einzelheiten findest du in der Docstring des Moduls.
classes:
Dieses Modul definiert den Typ ClassInfo, der Informationen über C++-Klassen im Kernelcache speichert, und stellt die Funktion collect_class_info bereit, um den Kernelcache nach Klassen zu durchsuchen und das globale Wörterbuch class_info mit einer Zuordnung von Klassennamen zu ClassInfo-Objekten zu füllen. Der Typ ClassInfo erfasst den Klassennamen, die OSMetaClass-Instanz, die virtuelle Methodentabelle und den Namen der Superklasse für jede C++-Klasse. Zusätzlich speichert jedes ClassInfo-Objekt Verweise auf die ClassInfo der Superklasse und die ClassInfo aller direkten Unterklassen, sodass die Klassenhierarchie leicht untersucht und durchlaufen werden kann. collect_class_info speichert außerdem die Menge aller virtuellen Methodentabellen im globalen Set vtables.
data_flow: Dieses interne Modul enthält Datenflussoperationen, die vom Rest von ida_kernelcache verwendet werden.
kernel:
Dieses Modul stellt die globalen Variablen base und prelink_info bereit. base ist die Basisadresse des Kernel-Images (der Beginn des Mach-O-Headers des Kernels). prelink_info ist das geparste __PRELINK_INFO-Wörterbuch.
kplist:
Dieses Modul stellt die Funktion kplist_parse zum Parsen von Kernel-Plists bereit.
metaclass:
Dieses Modul stellt die Funktion initialize_metaclass_symbols bereit, die für jede bekannte OSMetaClass-Instanz ein Symbol hinzufügt.
offset:
Dieses Modul stellt die Funktionen initialize_data_offsets und initialize_offset_symbols bereit. Erstere durchsucht die Segmente nach Zeigern, die in Offsets umgewandelt werden können. Letztere symbolisiert Offsets im __got-Abschnitt jedes Kexts, wenn das Ziel des Offsets ein Symbol besitzt.