macOS IOKit
Grundinformationen
Das I/O Kit ist ein Open-Source, objektorientiertes Gerätetreiber-Framework im XNU-Kernel, das dynamisch geladene Gerätetreiber verwaltet. Es ermöglicht, modulare Codes dynamisch zum Kernel hinzuzufügen und unterstützt verschiedene Hardware.
IOKit-Treiber exportieren Funktionen aus dem Kernel. Diese Funktionsparameter typen sind vordefiniert und werden überprüft. Darüber hinaus ist IOKit, ähnlich wie XPC, nur eine weitere Schicht oberhalb von Mach-Nachrichten.
IOKit XNU-Kernelcode ist von Apple unter https://github.com/apple-oss-distributions/xnu/tree/main/iokit als Open Source veröffentlicht. Darüber hinaus sind auch die IOKit-Komponenten im Benutzerspeicher Open Source https://github.com/opensource-apple/IOKitUser.
Allerdings sind keine IOKit-Treiber Open Source. Dennoch kann von Zeit zu Zeit eine Veröffentlichung eines Treibers mit Symbolen kommen, die das Debuggen erleichtern. Überprüfen Sie, wie Sie die Treibererweiterungen aus der Firmware hier erhalten.
Es ist in C++ geschrieben. Sie können demanglierte C++-Symbole mit:
IOKit exponierte Funktionen könnten zusätzliche Sicherheitsprüfungen durchführen, wenn ein Client versucht, eine Funktion aufzurufen, aber beachten Sie, dass die Apps normalerweise durch den Sandbox eingeschränkt sind, mit welchen IOKit-Funktionen sie interagieren können.
Treiber
In macOS befinden sie sich in:
/System/Library/Extensions
KEXT-Dateien, die in das OS X-Betriebssystem integriert sind.
/Library/Extensions
KEXT-Dateien, die von Drittanbieter-Software installiert wurden.
In iOS befinden sie sich in:
/System/Library/Extensions
Bis zur Nummer 9 werden die aufgeführten Treiber an der Adresse 0 geladen. Das bedeutet, dass es sich nicht um echte Treiber handelt, sondern Teil des Kernels sind und sie nicht entladen werden können.
Um spezifische Erweiterungen zu finden, können Sie Folgendes verwenden:
Um Kernel-Erweiterungen zu laden und zu entladen, tun Sie Folgendes:
IORegistry
Der IORegistry ist ein entscheidender Teil des IOKit-Frameworks in macOS und iOS, der als Datenbank zur Darstellung der Hardwarekonfiguration und des Zustands des Systems dient. Es ist eine hierarchische Sammlung von Objekten, die alle auf dem System geladenen Hardware und Treiber darstellen und deren Beziehungen zueinander.
Sie können den IORegistry mit dem CLI ioreg
abrufen, um ihn von der Konsole aus zu inspizieren (besonders nützlich für iOS).
Sie können IORegistryExplorer
von Xcode Additional Tools von https://developer.apple.com/download/all/ herunterladen und das macOS IORegistry über eine grafische Benutzeroberfläche inspizieren.
In IORegistryExplorer werden "Planes" verwendet, um die Beziehungen zwischen verschiedenen Objekten im IORegistry zu organisieren und darzustellen. Jeder Plane repräsentiert eine spezifische Art von Beziehung oder eine bestimmte Ansicht der Hardware- und Treiberkonfiguration des Systems. Hier sind einige der gängigen Planes, die Sie in IORegistryExplorer antreffen könnten:
IOService Plane: Dies ist der allgemeinste Plane, der die Dienstobjekte anzeigt, die Treiber und Nubs (Kommunikationskanäle zwischen Treibern) repräsentieren. Er zeigt die Anbieter-Kunden-Beziehungen zwischen diesen Objekten.
IODeviceTree Plane: Dieser Plane repräsentiert die physischen Verbindungen zwischen Geräten, wie sie an das System angeschlossen sind. Er wird oft verwendet, um die Hierarchie der über Busse wie USB oder PCI verbundenen Geräte zu visualisieren.
IOPower Plane: Zeigt Objekte und deren Beziehungen im Hinblick auf das Energiemanagement an. Er kann zeigen, welche Objekte den Energiezustand anderer beeinflussen, was nützlich ist, um energiebezogene Probleme zu debuggen.
IOUSB Plane: Fokussiert sich speziell auf USB-Geräte und deren Beziehungen und zeigt die Hierarchie von USB-Hubs und angeschlossenen Geräten.
IOAudio Plane: Dieser Plane dient der Darstellung von Audiogeräten und deren Beziehungen innerhalb des Systems.
...
Driver Comm Code Example
Der folgende Code verbindet sich mit dem IOKit-Dienst "YourServiceNameHere"
und ruft die Funktion im Selektor 0 auf. Dafür:
wird zuerst
IOServiceMatching
undIOServiceGetMatchingServices
aufgerufen, um den Dienst zu erhalten.Dann wird eine Verbindung hergestellt, indem
IOServiceOpen
aufgerufen wird.Und schließlich wird eine Funktion mit
IOConnectCallScalarMethod
aufgerufen, wobei der Selektor 0 angegeben wird (der Selektor ist die Nummer, die der Funktion, die Sie aufrufen möchten, zugewiesen wurde).
Es gibt andere Funktionen, die verwendet werden können, um IOKit-Funktionen aufzurufen, abgesehen von IOConnectCallScalarMethod
, wie IOConnectCallMethod
, IOConnectCallStructMethod
...
Rückwärtsanalyse des Treiber-Einstiegspunkts
Sie könnten diese beispielsweise aus einem Firmware-Image (ipsw) erhalten. Laden Sie es dann in Ihren bevorzugten Decompiler.
Sie könnten mit der Dekompilierung der externalMethod
-Funktion beginnen, da dies die Treiberfunktion ist, die den Aufruf empfängt und die richtige Funktion aufruft:
Dieser schreckliche Aufruf demangled bedeutet:
Beachten Sie, dass im vorherigen Definition der self
Parameter fehlt, die gute Definition wäre:
Tatsächlich finden Sie die echte Definition unter https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
Mit diesen Informationen können Sie Ctrl+Rechts -> Edit function signature
umschreiben und die bekannten Typen festlegen:
Der neue dekompilierte Code wird folgendermaßen aussehen:
Für den nächsten Schritt müssen wir die IOExternalMethodDispatch2022
Struktur definiert haben. Sie ist Open Source in https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, Sie könnten sie definieren:
Jetzt, folgend der (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
können Sie viele Daten sehen:
Ändern Sie den Datentyp in IOExternalMethodDispatch2022:
nach der Änderung:
Und wie wir jetzt wissen, haben wir ein Array von 7 Elementen (überprüfen Sie den endgültigen dekompilierten Code), klicken Sie, um ein Array von 7 Elementen zu erstellen:
Nachdem das Array erstellt wurde, können Sie alle exportierten Funktionen sehen:
Wenn Sie sich erinnern, um eine exportierte Funktion aus dem Benutzerspeicher zu rufen, müssen wir nicht den Namen der Funktion aufrufen, sondern die Selector-Nummer. Hier können Sie sehen, dass der Selector 0 die Funktion initializeDecoder
ist, der Selector 1 ist startDecoder
, der Selector 2 initializeEncoder
...
Last updated