macOS IOKit
Informazioni di base
L'IO Kit è un framework di driver di dispositivo orientato agli oggetti open-source nel kernel XNU, gestisce i driver di dispositivo caricati dinamicamente. Consente l'aggiunta di codice modulare al kernel al volo, supportando hardware diversificato.
I driver IOKit esportano fondamentalmente funzioni dal kernel. I tipi di parametri di queste funzioni sono predefiniti e verificati. Inoltre, simile a XPC, IOKit è solo un altro strato sopra i messaggi Mach.
Il codice del kernel IOKit XNU è open source da Apple su https://github.com/apple-oss-distributions/xnu/tree/main/iokit. Inoltre, i componenti IOKit dello spazio utente sono anche open source https://github.com/opensource-apple/IOKitUser.
Tuttavia, nessun driver IOKit è open source. Comunque, di tanto in tanto il rilascio di un driver potrebbe contenere simboli che facilitano il debug. Controlla come ottenere le estensioni del driver dal firmware qui.
È scritto in C++. Puoi ottenere i simboli C++ demangled con:
Le funzioni esposte da IOKit potrebbero eseguire controlli di sicurezza aggiuntivi quando un client tenta di chiamare una funzione, ma è importante notare che le app sono di solito limitate dal sandbox per quanto riguarda le funzioni IOKit con cui possono interagire.
Driver
In macOS sono situati in:
/System/Library/Extensions
File KEXT incorporati nel sistema operativo OS X.
/Library/Extensions
File KEXT installati da software di terze parti
In iOS sono situati in:
/System/Library/Extensions
Fino al numero 9 i driver elencati vengono caricati all'indirizzo 0. Ciò significa che non si tratta di veri driver ma fanno parte del kernel e non possono essere scaricati.
Per trovare le estensioni specifiche puoi utilizzare:
Per caricare e scaricare le estensioni del kernel, eseguire:
IORegistry
L'IORegistry è una parte cruciale del framework IOKit in macOS e iOS che funge da database per rappresentare la configurazione hardware e lo stato del sistema. È una raccolta gerarchica di oggetti che rappresentano tutto l'hardware e i driver caricati sul sistema e le loro relazioni reciproche.
È possibile ottenere l'IORegistry utilizzando la cli ioreg
per ispezionarlo dalla console (particolarmente utile per iOS).
È possibile scaricare IORegistryExplorer
dagli Strumenti Aggiuntivi di Xcode da https://developer.apple.com/download/all/ e ispezionare il macOS IORegistry attraverso un'interfaccia grafica.
In IORegistryExplorer, i "piani" vengono 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:
Piano IOService: Questo è il piano più generale, che visualizza gli oggetti di servizio che rappresentano driver e nubs (canali di comunicazione tra driver). Mostra le relazioni fornitore-cliente tra questi oggetti.
Piano IODeviceTree: Questo piano rappresenta le connessioni fisiche tra i dispositivi mentre sono collegati al sistema. Viene spesso utilizzato per visualizzare l'gerarchia dei dispositivi connessi tramite bus come USB o PCI.
Piano IOPower: Visualizza gli oggetti e le loro relazioni in termini di gestione dell'alimentazione. Può mostrare quali oggetti stanno influenzando lo stato di alimentazione degli altri, utile per il debug di problemi legati all'alimentazione.
Piano IOUSB: Specificamente focalizzato sui dispositivi USB e sulle loro relazioni, mostrando l'gerarchia degli hub USB e dei dispositivi connessi.
Piano IOAudio: Questo piano serve per rappresentare i dispositivi audio e le loro relazioni all'interno del sistema.
...
Esempio di Codice di Comunicazione del Driver
Il seguente codice si connette al servizio IOKit "NomeDelTuoServizioQui"
e chiama la funzione all'interno del selettore 0. Per farlo:
chiama prima
IOServiceMatching
eIOServiceGetMatchingServices
per ottenere il servizio.Stabilisce quindi una connessione chiamando
IOServiceOpen
.E infine chiama una funzione con
IOConnectCallScalarMethod
indicando il selettore 0 (il selettore è il numero assegnato alla funzione che si desidera chiamare).
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
Potresti ottenerli ad esempio da un immagine del firmware (ipsw). Quindi, caricalo nel tuo decompiler preferito.
Potresti iniziare a decompilare la funzione externalMethod
poiché questa è la funzione del driver che riceverà la chiamata e chiamerà la funzione corretta:
Quella chiamata orribile demagled significa:
Nota come nella definizione precedente manchi il parametro self
, la buona definizione sarebbe:
In realtà, puoi trovare la definizione reale su https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
Con queste informazioni puoi riscrivere Ctrl+Destra -> Modifica firma della funzione
e impostare i tipi conosciuti:
Il nuovo codice decompilato sarà simile a:
Per il prossimo passo è necessario avere definita la struttura IOExternalMethodDispatch2022
. È open source in https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, puoi definirla:
Ora, seguendo (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
puoi vedere molti dati:
Cambia il tipo di dati in IOExternalMethodDispatch2022:
dopo il cambiamento:
E poiché ora sappiamo che abbiamo un array di 7 elementi (controlla il codice decompilato finale), clicca per creare un array di 7 elementi:
Dopo aver creato l'array puoi vedere tutte le funzioni esportate:
Se ricordi, per chiamare una funzione esportata dallo spazio utente non è necessario 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