macOS IOKit
Grundlegende Informationen
Das I/O Kit ist ein Open-Source, objektorientiertes Gerätetreiber-Framework im XNU-Kernel, das dynamisch geladene Gerätetreiber verarbeitet. Es ermöglicht die Hinzufügung von modularem Code zum Kernel im laufenden Betrieb und unterstützt vielfältige Hardware.
IOKit-Treiber exportieren im Wesentlichen Funktionen aus dem Kernel. Diese Funktionen haben vordefinierte Parameter und werden überprüft. Darüber hinaus ist IOKit ähnlich wie XPC nur eine weitere Schicht über Mach-Nachrichten.
Der IOKit XNU-Kernelcode wurde von Apple unter https://github.com/apple-oss-distributions/xnu/tree/main/iokit veröffentlicht. Außerdem sind die IOKit-Komponenten im Benutzerbereich ebenfalls Open Source unter https://github.com/opensource-apple/IOKitUser.
Jedoch sind keine IOKit-Treiber Open Source. Gelegentlich wird jedoch ein Treiber-Release mit Symbolen veröffentlicht, die das Debuggen erleichtern. Überprüfen Sie, wie Sie die Treibererweiterungen aus der Firmware hier erhalten können.
Es ist in C++ geschrieben. Sie können demangled C++-Symbole mit:
IOKit exponierte Funktionen könnten zusätzliche Sicherheitsüberprüfungen durchführen, wenn ein Client versucht, eine Funktion aufzurufen, aber beachten Sie, dass Apps in der Regel durch die Sandbox darauf beschrä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 Betriebssystem OS X integriert sind.
/Library/Extensions
KEXT-Dateien, die von Software von Drittanbietern installiert wurden
In iOS befinden sie sich in:
/System/Library/Extensions
Bis zur Nummer 9 werden die aufgelisteten Treiber in der Adresse 0 geladen. Das bedeutet, dass es sich dabei nicht um echte Treiber handelt, sondern Teil des Kernels sind und nicht entladen werden können.
Um spezifische Erweiterungen zu finden, können Sie Folgendes verwenden:
Um Kernel-Erweiterungen zu laden und zu entladen, führen Sie Folgendes aus:
IORegistry
Die IORegistry ist ein entscheidender Bestandteil des IOKit-Frameworks in macOS und iOS, das als Datenbank zur Darstellung der Hardwarekonfiguration und des Zustands des Systems dient. Es handelt sich um eine hierarchische Sammlung von Objekten, die die gesamte Hardware und Treiber auf dem System sowie deren Beziehungen zueinander darstellen.
Sie können die IORegistry mithilfe des Befehlszeilentools ioreg
abrufen, um sie von der Konsole aus zu inspizieren (besonders nützlich für iOS).
Du könntest IORegistryExplorer
von den Zusätzlichen Tools von Xcode von https://developer.apple.com/download/all/ herunterladen und das macOS IORegistry durch eine grafische Benutzeroberfläche inspizieren.
In IORegistryExplorer werden "Ebenen" verwendet, um die Beziehungen zwischen verschiedenen Objekten im IORegistry zu organisieren und anzuzeigen. Jede Ebene repräsentiert einen spezifischen Beziehungstyp oder eine bestimmte Ansicht der Hardware- und Treiberkonfiguration des Systems. Hier sind einige der häufig vorkommenden Ebenen, auf die du in IORegistryExplorer stoßen könntest:
IOService-Ebene: Dies ist die allgemeinste Ebene, die die Serviceobjekte anzeigt, die Treiber und Nubs (Kommunikationskanäle zwischen Treibern) repräsentieren. Es zeigt die Anbieter-Client-Beziehungen zwischen diesen Objekten.
IODeviceTree-Ebene: Diese Ebene repräsentiert die physischen Verbindungen zwischen Geräten, wie sie mit dem System verbunden sind. Sie wird oft verwendet, um die Hierarchie der über Busse wie USB oder PCI verbundenen Geräte zu visualisieren.
IOPower-Ebene: Zeigt Objekte und ihre Beziehungen in Bezug auf das Energiemanagement an. Es kann zeigen, welche Objekte den Energiezustand anderer beeinflussen, was nützlich ist, um Probleme im Zusammenhang mit der Stromversorgung zu debuggen.
IOUSB-Ebene: Speziell auf USB-Geräte und deren Beziehungen fokussiert, zeigt die Hierarchie von USB-Hubs und angeschlossenen Geräten.
IOAudio-Ebene: Diese Ebene dient zur Darstellung von Audiogeräten und deren Beziehungen innerhalb des Systems.
...
Beispiel für Treiberkommunikationscode
Der folgende Code verbindet sich mit dem IOKit-Dienst "DeinServiceNameHier"
und ruft die Funktion im Selektor 0 auf. Dafür:
ruft es zuerst
IOServiceMatching
undIOServiceGetMatchingServices
auf, um den Dienst zu erhalten.Es stellt dann eine Verbindung her, indem es
IOServiceOpen
aufruft.Und ruft schließlich eine Funktion mit
IOConnectCallScalarMethod
auf, wobei der Selektor 0 angegeben ist (der Selektor ist die Nummer, die der Funktion zugewiesen ist, die du aufrufen möchtest).
Es gibt andere Funktionen, die verwendet werden können, um IOKit-Funktionen aufzurufen, abgesehen von IOConnectCallScalarMethod
wie IOConnectCallMethod
, IOConnectCallStructMethod
...
Umkehrung des Treibereinstiegspunkts
Sie könnten diese beispielsweise aus einem Firmware-Image (ipsw) erhalten. Laden Sie es dann in Ihren bevorzugten Decompiler.
Sie könnten mit dem Dekompilieren der externalMethod
-Funktion beginnen, da dies die Treiberfunktion ist, die den Aufruf empfängt und die richtige Funktion aufruft:
Dieser schreckliche Aufruf bedeutet:
Beachten Sie, wie in der vorherigen Definition der self
-Parameter fehlt, die korrekte Definition wäre:
Tatsächlich finden Sie die genaue Definition unter https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
Mit diesen Informationen können Sie Strg+Rechts ->
Funktions-Signatur bearbeiten` neu schreiben und die bekannten Typen festlegen:
Der neue dekompilierte Code wird wie folgt aussehen:
Für den nächsten Schritt müssen wir die IOExternalMethodDispatch2022
Struktur definiert haben. Es ist Open Source unter https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176 verfügbar, Sie könnten es definieren:
Nun, nach dem (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
können Sie viele Daten sehen:
Ändern Sie den Datentyp in IOExternalMethodDispatch2022:
nach der Änderung:
Und da wir jetzt wissen, dass wir ein Array mit 7 Elementen haben (überprüfen Sie den endgültigen dekompilierten Code), klicken Sie, um ein Array mit 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 Benutzerbereich aufzurufen, müssen Sie nicht den Namen der Funktion aufrufen, sondern die Selektornummer. Hier sehen Sie, dass der Selektor 0 die Funktion initializeDecoder
ist, der Selektor 1 ist startDecoder
, der Selektor 2 initializeEncoder
...
Last updated