macOS IOKit
Informazioni di base
L'IO Kit è un framework per driver di dispositivo open-source e orientato agli oggetti nel kernel XNU, gestisce driver di dispositivo caricati dinamicamente. Consente di aggiungere codice modulare al kernel al volo, supportando hardware diversificato.
I driver IOKit esporteranno fondamentalmente funzioni dal kernel. Questi parametri di funzione tipi sono predefiniti e vengono verificati. Inoltre, simile a XPC, IOKit è solo un altro strato sopra i messaggi Mach.
Il codice IOKit del kernel XNU è open-source da Apple in https://github.com/apple-oss-distributions/xnu/tree/main/iokit. Inoltre, i componenti IOKit dello spazio utente sono anch'essi open-source https://github.com/opensource-apple/IOKitUser.
Tuttavia, nessun driver IOKit è open-source. Comunque, di tanto in tanto, un rilascio di un driver potrebbe venire con simboli che rendono più facile il debug. Controlla come ottenere le estensioni del driver dal firmware qui.
È scritto in C++. Puoi ottenere simboli C++ demangled con:
Le funzioni esposte di IOKit potrebbero eseguire controlli di sicurezza aggiuntivi quando un client tenta di chiamare una funzione, ma si noti che le app sono solitamente limitati dal sandbox a cui possono interagire con le funzioni di IOKit.
Driver
In macOS si trovano in:
/System/Library/Extensions
File KEXT integrati nel sistema operativo OS X.
/Library/Extensions
File KEXT installati da software di terze parti
In iOS si trovano in:
/System/Library/Extensions
Fino al numero 9, i driver elencati sono caricati all'indirizzo 0. Questo significa che non sono veri e propri driver ma parte del kernel e non possono essere scaricati.
Per trovare estensioni specifiche puoi usare:
Per caricare e scaricare le estensioni del kernel fare:
IORegistry
Il IORegistry è una parte cruciale del framework IOKit in macOS e iOS che funge da database per rappresentare la configurazione e lo stato dell'hardware del sistema. È una collezione gerarchica di oggetti che rappresentano tutto l'hardware e i driver caricati sul sistema e le loro relazioni tra di loro.
Puoi ottenere l'IORegistry utilizzando il cli ioreg
per ispezionarlo dalla console (particolarmente utile per iOS).
Puoi scaricare IORegistryExplorer
da Xcode Additional Tools da https://developer.apple.com/download/all/ e ispezionare il macOS IORegistry attraverso un'interfaccia grafica.
In IORegistryExplorer, i "piani" sono utilizzati per organizzare e visualizzare le relazioni tra diversi oggetti nell'IORegistry. Ogni piano rappresenta un tipo specifico di relazione o una particolare vista della configurazione hardware e dei driver del sistema. Ecco alcuni dei piani comuni che potresti incontrare in IORegistryExplorer:
IOService Plane: Questo è il piano più generale, che visualizza gli oggetti di servizio che rappresentano driver e nubs (canali di comunicazione tra driver). Mostra le relazioni provider-client tra questi oggetti.
IODeviceTree Plane: Questo piano rappresenta le connessioni fisiche tra i dispositivi mentre sono collegati al sistema. Viene spesso utilizzato per visualizzare la gerarchia dei dispositivi collegati tramite bus come USB o PCI.
IOPower Plane: Visualizza oggetti e le loro relazioni in termini di gestione dell'energia. Può mostrare quali oggetti stanno influenzando lo stato di alimentazione di altri, utile per il debug di problemi legati all'energia.
IOUSB Plane: Focalizzato specificamente sui dispositivi USB e le loro relazioni, mostrando la gerarchia degli hub USB e dei dispositivi connessi.
IOAudio Plane: Questo piano è per rappresentare i dispositivi audio e le loro relazioni all'interno del sistema.
...
Esempio di Codice di Comunicazione Driver
Il seguente codice si connette al servizio IOKit "YourServiceNameHere"
e chiama la funzione all'interno del selettore 0. Per farlo:
prima chiama
IOServiceMatching
eIOServiceGetMatchingServices
per ottenere il servizio.Poi stabilisce una connessione chiamando
IOServiceOpen
.E infine chiama una funzione con
IOConnectCallScalarMethod
indicando il selettore 0 (il selettore è il numero che la funzione che vuoi chiamare ha assegnato).
Ci sono altre funzioni che possono essere utilizzate per chiamare le funzioni IOKit oltre a IOConnectCallScalarMethod
come IOConnectCallMethod
, IOConnectCallStructMethod
...
Inversione del punto di ingresso del driver
Puoi ottenere questi ad esempio da un firmware image (ipsw). Poi, caricalo nel tuo decompilatore preferito.
Puoi iniziare a decompilare la funzione externalMethod
poiché questa è la funzione del driver che riceverà la chiamata e chiamerà la funzione corretta:
Quella terribile chiamata demangled significa:
Nota come nella definizione precedente il parametro self
è mancante, la buona definizione sarebbe:
In realtà, puoi trovare la definizione reale in https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
Con queste informazioni puoi riscrivere Ctrl+Right -> Edit function signature
e impostare i tipi noti:
Il nuovo codice decompilato apparirà così:
Per il passo successivo dobbiamo avere definita la struct IOExternalMethodDispatch2022
. È open source in https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, puoi definirla:
Ora, seguendo il (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
puoi vedere molti dati:
Cambia il tipo di dato in IOExternalMethodDispatch2022:
dopo la modifica:
E come sappiamo, lì abbiamo un array di 7 elementi (controlla il codice decompilato finale), clicca per creare un array di 7 elementi:
Dopo che l'array è stato creato puoi vedere tutte le funzioni esportate:
Se ricordi, per chiamare una funzione esportata dallo spazio utente non dobbiamo chiamare il nome della funzione, ma il numero del selettore. Qui puoi vedere che il selettore 0 è la funzione initializeDecoder
, il selettore 1 è startDecoder
, il selettore 2 initializeEncoder
...
Last updated