Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ghidra_kernelcache — un framework Ghidra per il reverse engineering del kernelcache di iOS | Kitploit
Strumenti/GitHubGitHub/0x36/ghidra_kernelcache
Sicurezza iOSReverse EngineeringAnalisi di BinariAnalisi del Firmware
GitHub0x36/ghidra_kernelcache

ghidra_kernelcache

un framework Ghidra per il reverse engineering del kernelcache di iOS

Vedi Repository
370374 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

ghidra_kernelcache: un framework Ghidra per kernelcache iOS per il reverse engineering

Questo framework è il prodotto finale della mia esperienza nel reverse engineering dei kernelcache. Di solito cerco vulnerabilità controllando manualmente il kernel e le sue estensioni e ho automatizzato la maggior parte delle cose che volevo vedere in Ghidra per velocizzare il processo di reverse engineering, e questo si è dimostrato efficace e fa risparmiare molto tempo. Il framework funziona su iOS 12/13/14/15 e su macOS 11/12 (sia kernelcache che singolo KEXT) ed è stato reso pubblico con l'intenzione di aiutare le persone a iniziare a fare ricerca sul kernel iOS senza la fatica di preparare il proprio ambiente. Secondo me, questo framework (incluso il set di strumenti che fornisce e con una conoscenza di base di IOKit) è sufficiente per iniziare a fare hacking nel Kernelcache.

Il framework è interamente scritto in Python e può essere esteso per costruire altri strumenti; fornisce alcune API di base che puoi usare in quasi tutti i progetti e risparmiare tempo leggendo il manuale verboso. Sei invitato a leggere le funzionalità principali nella directory utils/.

Ghidra è bravo nell'analisi dei kernelcache, ma come altri strumenti di reverse engineering richiede un po' di lavoro manuale. ghidra_kernelcache fornisce un buon punto di partenza per sistemare le cose all'inizio e anche durante il reverse engineering, fornendo quindi un output del decompilatore di bell'aspetto.

Esiste un progetto simile realizzato da @_bazad in IDAPro chiamato ida_kernelcache che fornisce un buon punto di partenza per i ricercatori che vogliono lavorare con l'immagine del kernel in IDA. Il mio framework assomiglia un po' al lavoro di Brandon e va oltre fornendo molte più funzionalità per rendere meno doloroso il processo di lavoro con il kernelcache.

Caratteristiche :

  • Simbolizzazione del kernelcache *OS.
  • Ricostruzione della gerarchia delle classi C++ e delle tabelle virtuali.
  • Riferimenti a chiamate di metodi virtuali.
  • Correzione automatica della tabella di dispatch dei metodi esterni sia per ::externalMethod() che per ::getTargetAndMethodForIndex().
  • Applicazione di namespace ai metodi di classe.
  • Propagazione di nomi di simboli e tipi sugli argomenti delle funzioni.
  • Applicazione di firme di funzioni per funzioni note del kernel.
  • Importazione di strutture e classi vecchie da un progetto vecchio a un progetto nuovo.

Queste caratteristiche sono realizzate come strumenti separati che possono essere eseguiti tramite scorciatoie da tastiera o facendo clic sulle loro icone nella barra degli strumenti.

Installazione

Clona il repository :```sh git clone https://github.com/0x36/ghidra_kernelcache.git

root@kitploit:~
**Nota importante**: Il progetto è stato testato su Ghidra 10.1_PUBLIC e 10.2_DEV e non è retrocompatibile.

Vai su *`Windows → Script Manager`,*  clicca su  *`script Directory` ,* quindi aggiungi *`ghidra_kernelcache`* all'elenco dei percorsi delle directory.
Vai su *`Windows → Script Manager`,* nell'elenco degli *scripts*, vai alla categoria *`iOS→kernel`* e seleziona i plugin che vedi lì; appariranno nella barra degli strumenti di GHIDRA .

nella directory [logos/](https://github.com/0x36/ghidra_kernelcache/tree/master/logos), puoi inserire i tuoi loghi per ogni strumento.

## Simbolizzazione del kernelcache iOS

`ghidra_kernelcache` richiede nella prima fase [iometa](https://github.com/Siguza/iometa/) (realizzato da [@s1guza](https://twitter.com/s1guza)), un potente strumento che fornisce informazioni sulle classi C++ nel binario del kernel. La cosa grandiosa è che funziona come binario autonomo, quindi l'output può essere importato nel tuo framework di reverse engineering preferito semplicemente analizzandolo. Il mio framework prende l'output di iometa e lo analizza per simbolizzare e correggere le tabelle virtuali.

### Utilizzo

Dopo aver decompresso il kernel, esegui i seguenti comandi :```sh
$ iometa -n -A /tmp/kernel A10-legacy.txt > /tmp/kernel.txt
# if you want also to symbolicate using jtool2
$ jtool2 --analyze /tmp/kernel

Carica il kernelcache in Ghidra, NON USARE l'importazione BATCH, caricalo come immagine Mach-O. Dopo che il kernelcache è stato caricato e analizzato automaticamente, fai clic sull'icona mostrata nella barra degli strumenti o premi Meta-Shift-K, quindi inserisci il percorso completo dell'output di iometa che, nel nostro caso, è /tmp/kernel.txt.

Se vuoi utilizzare i simboli di jtool2, puoi usare anche jsymbol.py situato nella categoria iOS→kernel.

API del kernelcache iOS

Esempi completi dell'API sono in ghidra_kernelcache/kc.py

→ Ecco alcuni esempi di manipolazione di oggetti classe:```py from utils.helpers import * from utils.class import * from utils.iometa import ParseIOMeta

ff = "/Users/mg/ghidra_ios/kernel.txt" iom = ParseIOMeta(ff) Obj = iom.getObjects() kc = kernelCache(Obj)

symbolicate the kernel

kc.process_all_classes()

symbolicate the classes under com.apple.iokit.IOSurface bundle

kc.process_classes_for_bundle("com.apple.iokit.IOSurface")

symbolicate the classes under kernel bundle

kc.process_classes_for_bundle("kernel")

Process one class (including its parents)

kc.process_class("IOGraphicsAccelerator2")

Clears the content of the class structures (vtables are excluded)

kc.clear_class_structures()

Overwrite the old vtable structure definition and resymbolicate it again

kc.update_classes_vtable()

Reconstructing function call trees by enumerating all pac references and find their corresponding virtual method call

kc.explore_pac()

root@kitploit:~
Come puoi vedere, puoi simbolizzare completamente o parzialmente il kernelcache; se viene scelta la simbolizzazione parziale, `ghidra_kernelcache` costruirà automaticamente tutte le dipendenze delle classi prima di procedere.
Se esegui lo script sull'intero kernelcache (simbolizzazione completa), `ghidra_kernelcache` impiegherà diversi minuti per analizzare l'immagine del kernel.

Una volta terminato, Ghidra fornirà quanto segue:

→ Una nuova categoria è stata aggiunta in Bookmark Filter chiamata "iOS":

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image1.png" alt="image1" width="200"/>
                    
                    
→ Le tabelle virtuali delle classi IOKit vengono aggiunte al segnalibro 'iOS' per una ricerca delle tabelle virtuali più rapida e semplice; puoi semplicemente cercare un kext o una classe inserendo lettere, parole o il bundle del kext nella barra di ricerca.

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image2.png" alt="image2"/>


→ Correzione della tabella virtuale: disassembla/compila codice sconosciuto, corregge i namespace, risimbolizza i metodi della classe e applica la definizione di funzione a ciascun metodo:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image3.png" alt="image3"/>

→ Creazione dei namespace delle classi e inserimento di ciascun metodo nel proprio namespace corrispondente:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image4.png" alt="image4"/>

→ Creazione della struttura della classe rispettando la gerarchia delle classi:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image5.png" alt="image5"/>

→ Creazione delle vtable delle classi, e ciascun metodo ha la propria definizione di metodo per un miglior output di decompilazione:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image6.png" alt="image6"/>

L'implementazione completa si trova in [`utils/class.py.`](https://github.com/0x36/ghidra_kernelcache/blob/master/utils/class.py)

Ecco alcuni screenshot di prima/dopo la simbolizzazione con `ghidra_kernelcache`:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image7.png" alt="image7"/>

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image8.png" alt="image8"/>




## Simbolizzazione di KEXT su macOS
---
Il supporto macOS di `ghidra_kernelcache` è sia per la simbolizzazione del kernelcache che di singoli KEXT per le architetture ARM64e e x86_64.
**IMPORTANTE:** Al momento della scrittura, Ghidra non è in grado di analizzare l'intero kernelcache di macOS, ma è possibile caricarlo in IDA per un'analisi iniziale e poi importare il database (idb in xml) in Ghidra successivamente, ma questo esula dallo scopo. Se riesci a farlo, `ghidra_kernelcache` si occuperà del resto.

Ci sono alcuni passaggi da eseguire prima di simbolizzare qualsiasi estensione del kernel macOS, poiché l'obiettivo principale di `ghidra_kernelcache` è ricostruire la gerarchia delle classi e gestire tutte le strutture delle classi in un unico database; un'estensione del kernel non soddisfa questi requisiti, il che significa che la simbolizzazione di un singolo KEXT richiede una simbolizzazione del kernel e forse di altre estensioni del kernel da cui dipende, quindi è necessario un lavoro extra.
`ghidra_kernelcache` ora fornisce un potente modo per simbolizzare le estensioni del kernel, incluso il kernel, gestendo e condividendo le strutture delle classi e le definizioni dei metodi virtuali tramite il potente *DataType Project Archive* di Ghidra.

### Passaggi per simbolizzare un'estensione del kernel
- Crea una nuova cartella nel tuo progetto Ghidra, quindi carica `/System/Library/Kernels/kernel.release.XXXXX` in quella cartella e lascia che Ghidra lo analizzi.
- Crea un nuovo *Project Archive*: Vai a `DataType Provider` → Clicca sulla freccia in alto a destra della finestra → `New Project Archive` → Posizionalo all'interno della cartella appena creata → Dagli un nome (ad esempio macOS_12.1).
- Ora simbolizza il kernel usando `ghidra_kernelcache`; il processo è abbastanza simile alla simbolizzazione del *kernelcache* di iOS.```bash
$ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt

In python console, oppure puoi trovare l'implementazione completa dello script in KM.py script :```py

from utils.helpers import * from utils.kext import * iom = ParseIOMeta("/tmp/kernel.txt") Obj = iom.getObjects() kc = Kext(Obj,shared_p="macOS_12.1") kc.process_kernel_kext()

root@kitploit:~
- Una volta terminato, è stata creata un'associazione di database tra l'archivio del kernel e l'archivio `macOS_12.1`. Ora, fai clic destro su `kernel.release.t8001` → `Commit DataTypes To` → `macOS_12.1`.
- Quindi `Right Click` → `Select All` → `Commit`.
- Salva l'archivio del progetto: `Right click` → `Save Archive`.

Abbiamo appena creato un archivio di progetto che può essere condiviso tra tutte le estensioni del kernel.

Prendiamo come esempio il Kext `IOSurface` per Apple Silicon:```bash
$ lipo /System/Library/Extensions/IOSurface.kext/Contents/MacOS/IOSurface -thin arm64e -output /tmp/iosurface.arm64e
$ iometa -n -A /tmp/iosurface.arm64e > /tmp/iosurface.txt
  • Carica il Kext nella stessa cartella in cui si trovano il database del kernel e l'archivio del progetto e lascia che Ghidra completi l'analisi
  • Carica l'archivio del progetto che abbiamo creato in precedenza macOS_12.1: vai su Data Type Manager → Open Project Archive, quindi seleziona macOS_12.1
  • Esegui i seguenti metodi, lo script completo si trova in KM.py:```python from utils.helpers import * from utils.kext import *

kc = Kext(Obj,shared_p="macOS_12.1")

This method fixes LC_DYLD_CHAINED_FIXUPS for M1 Kernel extension

kc.depac()

This method reconstructs class hierarchy and builds virtual table for each class

kc.process_kernel_kext()

root@kitploit:~
**Nota importante** : a volte `kc.process_kernel_kext()` fallisce perché Ghidra non è riuscito a demancherare alcuni simboli C++. Per risolvere, vai nel gestore degli script ed esegui lo script `DemangleAllScript.java`, quindi  riavvia  `kc.process_kernel_kext()`  di nuovo. 

### Classi personalizzate 
Ci sono alcuni casi in cui alcune classi C++ che `ghidra_kernelcache`  e `iometa` non possono simbolizzare, quindi è stata aggiunta una nuova funzionalità per gestire questo.
La ricostruzione della classe `Custom()` itera attraverso tutti i simboli `::vtable` e verifica se la classe è già definita o meno; in caso contrario, crea automaticamente una struttura di classe, definizioni di funzioni per ogni metodo di classe identificato, un namespace e una tabella virtuale per ogni  classe. 

La creazione di classi personalizzate è supportata al momento solo su macOS.```bash
$ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt
$ iometa -n -A <kext_path> >> /tmp/kernel.txt

Nessun contenuto da tradurre.```py

from utils.helpers import * from utils.custom_kc import *

if name == "main": default = "/tmp/kernel.txt" ff = askString("iometa symbol file","Symbol file: ",default) iom = ParseIOMeta(ff) Obj = iom.getObjects()

root@kitploit:~
kc = Custom(Obj)

kc.process_all_classes()
kc.explore_pac()
root@kitploit:~
## Script vari
---
### Importazione del Dwarf4 di KDK
Ghidra, per qualche motivo, non riesce a caricare la directory `.dsym` corrispondente; ho creato un piccolo script per risolvere questo problema. Si trova [qui](https://github.com/0x36/ghidra_kernelcache/blob/master/dwarf4_fix.py).
**Utilizzo** : carica il kernel dal tuo percorso KDK, lascia che Ghidra completi l'analisi, poi esegui `dwarf_fix.py`. Caricherà i simboli e il processo potrebbe richiedere diversi minuti.
<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image12.png" alt="image12"/>

### Risoluzione dei riferimenti alle chiamate di metodi virtuali
`ghidra_kernelcache` fornisce due modi per risolvere le chiamate virtuali tramite `kernelCache.explore_pac` o `fix_extra_refs`

**kernelCache.explore_pac()**
Se stai lavorando su un binario arm64e, `ghidra_kernelcache` può riconoscere le chiamate di metodi virtuali cercando il valore del `Pointer Authentication Code`. Il processo è semplice e, a differenza di `fix_extra_refs()`, `kernelCache.explore_pac` non si basa sull'identificazione di `Pcode` o `varnode`; itera semplicemente attraverso tutte le istruzioni nel programma, cerca le istruzioni `MOVK`, recupera il secondo operando e cerca il valore corrispondente nel database.
Utilizzo : 
Crea un'istanza di *KernelCache* tramite **kernelCache**, **Kext** o **Custom**, quindi chiama il metodo `explore_pac()`.```py
from utils.helpers import *
from utils.kext import *

if __name__ == "__main__":
    default = "/tmp/kernel.txt"
    ff = askString("iometa symbol file","Symbol file: ",default)
    iom = ParseIOMeta(ff)
    Obj = iom.getObjects()

    kc = Kext(Obj)

   	 kc.explore_pac()

fix_extra_refs() Questa funzione si basa su un'analisi di flusso dei dati di base per trovare tutti i metodi di chiamata virtuale e risolvere automaticamente le loro implementazioni. Funziona su tutte le architetture ed è in grado di riconoscere il tipo di dato sorgente dall'output del decompilatore e risolvere tutti i riferimenti di chiamata virtuale all'interno della funzione, consentendo all'utente di saltare avanti/indietro direttamente verso/da l'implementazione senza doverla cercare manualmente.

La funzionalità più utile fornita da fix_extra_refs è che mantiene sincronizzati i riferimenti a ogni esecuzione. Ad esempio, se cambi il tipo di dato di una variabile in un tipo di dato di classe, fix_extra_refs riconoscerà automaticamente il cambiamento e attraverserà ricorsivamente tutti i siti di chiamata per risolvere i loro riferimenti, e si fermerà solo quando la coda dei siti di chiamata sarà vuota.

Ci sono alcune altre funzionalità fornite da fix_extra_refs come:

  • Rileva automaticamente le chiamate _ptmf2ptf() e risolve il loro metodo di chiamata sia per gli offset che per l'indirizzo completo della funzione
  • Identifica il namespace di un nome di funzione non risolto (funzioni che iniziano con FUN_ ) e lo risolve inserendo la funzione target nel proprio namespace (ad esempio aggiungendo il puntatore this della classe corrispondente).

Puoi trovare l'implementazione in utils/references.py, fix_extra_refs analizza le operazioni pcode e cerca gli opcode CALLIND e CALL, quindi ottiene tutti i varnodes coinvolti nell'operazione. Una volta identificata una definizione di Varnode, recupera il suo HighVariable per identificare il tipo di oggetto della classe. Se il tipo è sconosciuto (cioè non appare come una struttura di classe) lo ignora; altrimenti prende il nome della classe, cerca la sua tabella di chiamate virtuali e, utilizzando l'offset fornito dal Varnode, può ottenere la corretta chiamata del metodo virtuale e inserisce un riferimento sull'istruzione di chiamata.```py fix_extra_refs(toAddr(address))

root@kitploit:~
Ecco un esempio di output dell'uso di `fix_extra_refs` :

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image9.png" alt="image9"/>

Si noti che ha risolto con successo le chiamate virtuali di **IOService::isOpen()**, **OSArray:getNextIndexOfObject()** e **IOStream::removeBuffer()** senza alcuna modifica manuale.

Successivamente,  `fix_extra_refs` decompilerà **IOStream::removeBuffer()**, otterrà tutti  gli HighVariables di questo metodo, poi risolverà i loro riferimenti come il metodo precedente ... e così via.
<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image10.png" alt="image10"/>

### Correzione automatica delle tabelle dei metodi esterni

Credo che ogni ricercatore abbia qualche script per gestire questa parte, poiché è la principale superficie di attacco di IOKit; farlo manualmente è un peso, e deve essere automatizzato in modo che il ricercatore possa approfondire più tabelle di metodi esterni.
Ci sono due script forniti da`ghidra_kernelcache` : **fix_methodForIndex.py** e **fix_extMethod.py.** Puoi abilitarli come gli altri script mostrati sopra.

***Uso***: Posiziona il cursore all'inizio della tabella di dispatch esterna, esegui lo script: fornisci il target e il numero di selettori.
Esempio per  `IOStreamUserClient::getTargetAndMethodForIndex()` :

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image11.png" alt="image11"/>


### namespace.py :  correzione dei namespace dei metodi …
Questo è uno script utile per popolare il tipo di classe a tutti i metodi incontrati, ed è una dipendenza per lo script `extra_refs.py` per esplorare ricorsivamente le funzioni chiamate e risolvere i loro riferimenti.

***Uso***: Posiziona il cursore nell'output del decompilatore della funzione desiderata, esegui lo script dalla barra degli strumenti o premi **Meta-Shift-N** .

### Propagazione di nomi e tipi di simboli
`ghidra_kernelcache` fornisce supporto per la propagazione dei tipi per le operazioni Pcode di base, ma probabilmente fallirà per alcune variabili che utilizzano casting complessi.
Se qualcuno vuole aiutare, o vuole iniziare a lavorare con cose di basso livello in Ghidra, questa è l'opportunità per farlo.
L'implementazione si trova in [ghidra_kernelcache/propagate.py](https://github.com/0x36/ghidra_kernelcache/blob/master/propagate.py)

### Caricamento delle firme delle funzioni

Non è possibile analizzare i file header C++ in Ghidra, e avere le firme delle funzioni del kernel in kernelcache può migliorare molte cose nell'output del decompilatore.
Ad esempio, supponiamo di aver aggiunto   `virtual IOMemoryMap * map(IOOptionBits options = 0 );`, Ghidra reimposterà automaticamente il tipo di ritorno in puntatore `IOMemoryMap` automaticamente per entrambi la definizione della funzione e le firme delle funzioni.
Puoi aggiungere qualsiasi simbolo C++ nella directory **signatures/** rispettando la sintassi e puoi trovare le firme delle funzioni definite in questa directory.```c++
// Defining an instance class method
IOMemoryDescriptor * withPersistentMemoryDescriptor(IOMemoryDescriptor *originalMD);

// Defining a virtual method, it must start with "virtual" keyword
virtual IOMemoryMap * createMappingInTask(task_t intoTask,  mach_vm_address_t atAddress,  IOOptionBits options,  mach_vm_size_t offset = 0,  mach_vm_size_t length = 0);

// Defining a structure
struct task_t;

// typedef'ing a type
typedef typedef uint IOOptionBits; 

// Lines begining with '//' are ignored 

Utilizzo: Dopo aver simbolizzato il kernel, è altamente consigliato eseguire lo script load_sigatnures.py per caricare tutte le firme di funzioni disponibili. Come per la maggior parte degli strumenti precedenti, esegui questo script aggiungendolo nella barra degli strumenti o dal Plugin manager o premi semplicemente Meta-Shift-S .

Caricamento di vecchie strutture:

Questo script è semplice: importa tutte le strutture, classi, typedef e definizioni di funzioni e tutto ciò che ha SourceType.USER_DEFINED da un vecchio progetto a uno nuovo.

Utilizzo: Apri i progetti Ghidra vecchio e nuovo sullo stesso strumento, vai allo script load_structs.py, inserisci il nome del programma vecchio nella variabile src_prog_string e quello nuovo nella variabile dst_prog_string, quindi esegui lo script.

Contribuisci

Se il progetto ti sembra interessante e vuoi contribuire, fai una PR e la esaminerò; nel frattempo, mi piacerebbe vedere contributi nelle seguenti aree:

  • ghidra_kernelcache/signatures/kernel.txt: continua a importare le funzioni del kernel XNU, è molto semplice: basta copiare/incollare la definizione della funzione.
  • ghidra_kernelcache/propagate.py: supporta opcode non gestiti per una migliore propagazione dei simboli.

Crediti

Vorrei ringraziare @s1guza per il suo fantastico iometa da cui ghidra_kernelcache dipende.

Scarica lo strumento