Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
ghidra_kernelcache — um framework Ghidra para engenharia reversa do kernelcache do iOS | Kitploit
Ferramentas/GitHubGitHub/0x36/ghidra_kernelcache
Segurança iOSEngenharia ReversaAnálise de BináriosAnálise de Firmware
GitHub0x36/ghidra_kernelcache

ghidra_kernelcache

um framework Ghidra para engenharia reversa do kernelcache do iOS

Ver Repositório
37037há 4 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

ghidra_kernelcache: um framework de kernelcache iOS para engenharia reversa

Este framework é o produto final da minha experiência em engenharia reversa de Kernelcache. Normalmente procuro por vulnerabilidades auditando manualmente o kernel e suas extensões e automatizei a maioria das coisas que realmente queria ver no Ghidra para acelerar o processo de reversão, o que se mostrou eficaz e economiza muito tempo. O framework funciona em iOS 12/13/14/15 e em macOS 11/12 (tanto kernelcache quanto KEXT único) e foi disponibilizado ao público com a intenção de ajudar pessoas a começar a pesquisar sobre o kernel iOS sem a dificuldade de preparar seu próprio ambiente. Como acredito, este framework (incluindo o conjunto de ferramentas que fornece e com algum conhecimento básico de IOKit) é suficiente para começar a hackear o Kernelcache.

O framework é inteiramente escrito em Python e pode ser estendido para construir outras ferramentas. Ele fornece algumas APIs básicas que você pode usar em quase qualquer projeto e economizar tempo de leitura do manual verboso. Sinta-se à vontade para ler as funcionalidades principais no diretório utils/.

Ghidra é bom quando se trata de analisar Kernelcaches, mas como outras ferramentas de RE, requer algum trabalho manual. ghidra_kernelcache fornece um bom ponto de entrada para corrigir coisas no início e até mesmo durante a engenharia reversa, proporcionando assim uma saída do descompilador com boa aparência.

Existe um projeto semelhante feito por @_bazad no IDAPro chamado ida_kernelcache que fornece um bom ponto de entrada para pesquisadores que desejam trabalhar com a imagem do kernel no IDA. Meu framework se parece um pouco com o trabalho de Brandon e vai além, fornecendo muito mais recursos para tornar o processo de trabalho com o kernelcache menos doloroso.

Recursos:

  • Simbolização do kernelcache iOS.
  • Reconstrução de hierarquias de classes C++ e tabelas virtuais.
  • Referências de chamadas de métodos virtuais.
  • Correção automática da tabela de despacho de métodos externos para ::externalMethod() e ::getTargetAndMethodForIndex().
  • Aplicação de namespaces a métodos de classe.
  • Propagação de nome de símbolo e tipo sobre argumentos de função.
  • Aplicação de assinaturas de função para funções conhecidas do kernel.
  • Importação de estruturas e classes antigas de um projeto antigo para um novo.

Esses recursos são feitos como ferramentas separadas que podem ser executadas por atalhos de teclado ou clicando em seus ícones na barra de ferramentas.

Instalação

Clone o repositório:```sh git clone https://github.com/0x36/ghidra_kernelcache.git

root@kitploit:~
**Nota importante**: O projeto foi testado no Ghidra 10.1_PUBLIC e 10.2_DEV e não é compatível com versões anteriores.

Vá para *`Windows → Script Manager`,* clique em *`script Directory`,* depois adicione *`ghidra_kernelcache`* à lista de diretórios.
Vá para *`Windows → Script Manager`,* na listagem de *scripts*, vá para a categoria *`iOS→kernel`* e marque os plug-ins vistos lá, eles aparecerão na Barra de Ferramentas do GHIDRA.

No diretório [logos/](https://github.com/0x36/ghidra_kernelcache/tree/master/logos), você pode colocar seus próprios logos para cada ferramenta.

## Simbolização do kernelcache do iOS

`ghidra_kernelcache` requer, na primeira etapa, [iometa](https://github.com/Siguza/iometa/) (feito por [@s1guza](https://twitter.com/s1guza)), uma ferramenta poderosa que fornece informações de classes C++ no binário do kernel. O ótimo é que funciona como um binário independente, então a saída pode ser importada para seu framework de RE favorito apenas analisando-a. Meu framework pega a saída do iometa e a analisa para simbolizar e corrigir tabelas virtuais.

### Uso
Após descomprimir o kernel, execute os seguintes comandos:```sh
$ iometa -n -A /tmp/kernel A10-legacy.txt > /tmp/kernel.txt
# if you want also to symbolicate using jtool2
$ jtool2 --analyze /tmp/kernel

Carregue o kernelcache no Ghidra, NÃO USE importação em lote, carregue-o como imagem Mach-O. Após o Kernelcache ser carregado e auto-analisado, clique no ícone mostrado na barra de ferramentas ou pressione Meta-Shift-K, depois coloque o caminho completo da saída do iometa que é /tmp/kernel.txt no nosso caso.

Se quiser usar símbolos do jtool2, pode usar o jsymbol.py localizado na categoria iOS→kernel também.

API do kernelcache iOS

Exemplos completos da API estão em ghidra_kernelcache/kc.py

→ Aqui estão alguns exemplos de manipulação de objetos de 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:~
Como pode ver, pode simbolizar total ou parcialmente o kernelcache; se a simbolização parcial for escolhida, o `ghidra_kernelcache` construirá automaticamente todas as dependências de classe antes de prosseguir.
Se executar o script contra todo o kernelcache (simbolização completa), o `ghidra_kernelcache` levará vários minutos para analisar a imagem do kernel.

Uma vez terminado, o Ghidra fornecerá o seguinte:

→ Uma nova categoria foi adicionada no Filtro de Marcadores chamada "iOS": 

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image1.png" alt="image1" width="200"/>
                    
                    
→ Tabelas virtuais de classes IOKit são adicionadas ao Marcador 'iOS' para uma consulta melhor e mais rápida da tabela virtual; pode procurar por uma kext ou classe fornecendo letras, palavras ou o bundle da kext na barra de busca.

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


→ Corrigindo a tabela virtual: desmonta/compila código desconhecido, corrige namespaces, re-simboliza os métodos da classe e aplica definição de função a cada método:

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

→ Criação de namespaces de classe e coloca cada método no seu próprio namespace correspondente:

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

→ Criando estrutura de classe com respeito à hierarquia de classes:

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

→ Criando vtables de classe, e cada método tem sua própria definição de método para uma melhor saída de descompilação:

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

A implementação completa pode ser encontrada em [`utils/class.py.`](https://github.com/0x36/ghidra_kernelcache/blob/master/utils/class.py)

Aqui estão algumas capturas de tela de antes/depois da simbolização usando `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"/>




## Simbolização de Kext do macOS
---
O suporte do `ghidra_kernelcache` no macOS é tanto para simbolização de kernelcache quanto de KEXT individual para as arquiteturas ARM64e e x86_64. 
**IMPORTANTE:** No momento da escrita, o Ghidra não consegue analisar todo o kernelcache do macOS, mas é possível carregá-lo no IDA para análise inicial e depois importar a base de dados (idb para xml) para o Ghidra mais tarde, mas isso está fora do escopo. Se conseguir fazê-lo, o `ghidra_kernelcache` cuidará do resto.

Existem alguns poucos passos que devem ser tomados antes de simbolizar qualquer Extensão de Kernel do macOS, pois o objetivo principal do `ghidra_kernelcache` é reconstruir a hierarquia de classes e gerenciar todas as estruturas de classe em uma única base de dados; uma extensão de kernel não cumpre esses requisitos, o que significa que a simbolização de um único KEXT requer uma simbolização do kernel e talvez de outras Extensões de Kernel das quais depende, portanto algum trabalho extra precisa ser feito aqui.
O `ghidra_kernelcache` agora fornece uma maneira poderosa de simbolizar Extensões de Kernel, incluindo o kernel, gerenciando e compartilhando estruturas de classe e definições de métodos virtuais através do poderoso *DataType Project Archive* do Ghidra

### Passos para simbolizar uma Extensão de Kernel
- Crie uma nova pasta no seu projeto Ghidra, depois carregue ` /System/Library/Kernels/kernel.release.XXXXX` nessa pasta e deixe o Ghidra analisá-la.
- Crie um novo *Project Archive*: Vá até `DataType Provider` → Clique na seta no canto superior direito da janela → `New Project Archive` → Coloque-o dentro da pasta recém-criada → Dê um nome a ele (ex.: macOS_12.1).
- Agora simbolize o kernel usando `ghidra_kernelcache`; o processo é bastante similar à simbolização do *kernelcache* do iOS.```bash
$ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt
  • No console Python, ou você pode encontrar a implementação completa do script no arquivo KM.py :```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:~
- Uma vez concluído, uma associação de banco de dados foi criada entre o arquivo do kernel e o arquivo `macOS_12.1`. Agora, clique com o botão direito em `kernel.release.t8001` → `Commit DataTypes To` → `macOS_12.1`.
- Em seguida, `Clique com o botão direito` → `Selecionar Tudo` → `Commit`.
- Salve o arquivo do projeto: `Clique com o botão direito` → `Save Archive`.
Acabamos de criar um arquivo de projeto que pode ser compartilhado entre todas as extensões do kernel.
Vamos tomar como exemplo o `IOSurface` Kext para 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
  • Carregue o Kext no mesmo caminho de pasta onde o banco de dados do kernel e o arquivo do projeto estão localizados e deixe o Ghidra terminar a análise
  • Carregue o arquivo do projeto que criamos anteriormente macOS_12.1: vá para Data Type Manager → Open Project Archive, então selecione o macOS_12.1
  • Execute os seguintes métodos, o script completo pode ser encontrado em 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**: às vezes `kc.process_kernel_kext()` falha porque o Ghidra não conseguiu desmistificar alguns símbolos C++. Para corrigir isso, vá ao gerenciador de scripts e execute o script `DemangleAllScript.java`, depois reinicie `kc.process_kernel_kext()` novamente.

### Classes personalizadas
Existem alguns casos em que algumas classes C++ onde `ghidra_kernelcache` e `iometa` não conseguem simbolizar, então um novo recurso foi adicionado para lidar com isso.
A reconstrução da classe `Custom()` itera por todos os símbolos `::vtable` e verifica se a classe já está definida ou não; se não estiver, cria automaticamente uma estrutura de classe, definições de função para cada método de classe identificado, um namespace e uma tabela virtual para cada classe.

A criação de classes personalizadas é suportada apenas no macOS no momento.```bash
$ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt
$ iometa -n -A <kext_path> >> /tmp/kernel.txt

🎨 Projeto Visual

Visualizam de forma inteligente dados complexos de cibersegurança e redes - transforma dados brutos em perspectivas acionáveis.

Visão Geral do Painel

Painel Principal Exemplo do painel do Netscanner mostrando dados de tráfego de rede em tempo real

  • Visão de Tabela Dinâmica: Tabela interativa com dados detalhados de fluxo de tráfego
    • Ordena por qualquer coluna (IP de origem, IP de destino, porta, protocolo, bytes, etc.)
    • Linhas expansíveis que mostram registros de fluxo individuais
    • Filtros de pesquisa em tempo real em todos os campos
  • Painel de Métricas: KPIs de tráfego de alto nível com Cartões de Estatísticas codificados por cores
    • Total de Fluxos, Pacotes, Bytes e Conexões
    • Fluxos TCP, UDP, ICMP e Outros separadamente
    • Bytes Totais de Entrada vs Saída```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:~
## Scripts diversos
---
### Importando o Dwarf4 do KDK
Ghidra de alguma forma não consegue carregar o diretório `.dsym` correspondente, fiz um pequeno script para corrigir isso. Ele pode ser encontrado [aqui](https://github.com/0x36/ghidra_kernelcache/blob/master/dwarf4_fix.py).
**Uso**: carregue o kernel do seu caminho KDK, deixe o Ghidra terminar a análise, então execute `dwarf_fix.py`, ele carregará os símbolos e o processo pode levar vários minutos.
<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image12.png" alt="image12"/>

### Resolvendo referências de chamadas de métodos virtuais
`ghidra_kernelcache` fornece duas maneiras de resolver chamadas virtuais por  `kernelCache.explore_pac` ou `fix_extra_refs`

**kernelCache.explore_pac()**
Se você está trabalhando em um binário arm64e, o `ghidra_kernelcache` pode reconhecer chamadas de métodos virtuais procurando pelo valor `Pointer Authentication Code`. O processo é direto e, diferentemente do `fix_extra_refs()`, o `kernelCache.explore_pac` não depende da identificação de `Pcode` ou `varnode`, ele apenas itera por todas as instruções no programa, procura por instruções `MOVK`, busca o segundo operando e procura seu valor correspondente no banco de dados.
Uso:
Crie uma instância *KernelCache* via **kernelCache** , **Kext** ou **Custom**, então chame o método `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() Esta função baseia-se numa análise básica de fluxo de dados para encontrar todos os métodos de chamada virtual e resolver automaticamente as suas implementações. Funciona em todas as arquiteturas e tem a capacidade de reconhecer o tipo de dados de origem a partir da saída do descompilador, resolvendo todas as referências de chamada virtual dentro da função, de modo que o utilizador possa saltar para a frente/para trás diretamente para/da implementação sem ter de a procurar manualmente.

A funcionalidade mais útil fornecida por fix_extra_refs é que mantém as referências sincronizadas em cada execução. Por exemplo, se alterar um tipo de dados de variável para um tipo de dados de classe, o fix_extra_refs reconhecerá automaticamente a alteração e percorrerá recursivamente todos os locais de chamada para resolver as suas referências, parando apenas quando a fila de locais de chamada ficar vazia.

Existem outras funcionalidades fornecidas por fix_extra_refs, tais como:

  • Deteta automaticamente chamadas _ptmf2ptf() e resolve o seu método de chamada tanto para offsets como para endereços completos de função.
  • Identifica o espaço de nomes de um nome de função não resolvida (funções que começam com FUN_) e resolve-o colocando a função alvo no seu próprio espaço de nomes (por exemplo, adicionando o ponteiro this da classe correspondente).

Pode encontrar a implementação em utils/references.py. O fix_extra_refs analisa as operações pcode e procura por opcodes CALLIND e CALL. Em seguida, obtém todos os varnodes envolvidos na operação. Uma vez identificada a definição de um Varnode, recupera o seu HighVariable para identificar o tipo de objeto da classe. Se o tipo for desconhecido (ou seja, não aparenta ser uma estrutura de classe), ignora-o; caso contrário, pega no nome da classe, procura na sua tabela de chamadas virtuais e, utilizando o offset fornecido pelo Varnode, consegue obter a chamada de método virtual correta e coloca uma referência na instrução de chamada.```py fix_extra_refs(toAddr(address))

root@kitploit:~
Aqui está um exemplo de saída do uso de `fix_extra_refs`:

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

Observe que ele resolveu com sucesso as chamadas virtuais de **IOService::isOpen()**, **OSArray:getNextIndexOfObject()** e **IOStream::removeBuffer()** sem qualquer modificação manual.

Em seguida, `fix_extra_refs` descompilará **IOStream::removeBuffer()**, obterá todas as HighVariables deste método e então resolverá suas referências como no método anterior ... e assim por diante.
<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image10.png" alt="image10"/>

### Correção automática de tabelas de métodos externos

Acredito que todo pesquisador tenha algum script para lidar com esta parte, já que é a principal superfície de ataque do IOKit; fazê-lo manualmente é um fardo, e deve ser automatizado de forma que o pesquisador possa mergulhar em várias tabelas de métodos externos.
Existem dois scripts fornecidos pelo `ghidra_kernelcache`: **fix_methodForIndex.py** e **fix_extMethod.py.** Você pode ativá-los como os outros scripts, conforme mostrado acima.

***Uso***: Coloque o cursor no início da tabela de despacho externa, execute o script: forneça o alvo e o número de seletores.
Exemplo para `IOStreamUserClient::getTargetAndMethodForIndex()`:

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


### namespace.py: corrigir namespaces de métodos…
Este é um script útil para popular o tipo de classe em todos os métodos encontrados, e é uma dependência para o script `extra_refs.py` para explorar recursivamente as funções chamadas e resolver suas referências.

***Uso***: Coloque o cursor na saída do descompilador da função desejada, execute o script a partir da barra de ferramentas ou pressione **Meta-Shift-N**.

### Propagação de nome e tipo de símbolo
O `ghidra_kernelcache` fornece suporte à propagação de tipos para operações básicas de Pcode, mas provavelmente falhará para algumas variáveis que usam casting complexo.
Se alguém quiser ajudar ou quiser começar a trabalhar com coisas de baixo nível no Ghidra, esta é a oportunidade.
A implementação pode ser encontrada em [ghidra_kernelcache/propagate.py](https://github.com/0x36/ghidra_kernelcache/blob/master/propagate.py)

### Carregamento de assinaturas de funções

Analisar arquivos de cabeçalho C++ no Ghidra não é possível, e ter assinaturas de funções do kernel no kernelcache pode melhorar muitas coisas na saída do descompilador.
Por exemplo, suponha que adicionamos `virtual IOMemoryMap * map(IOOptionBits options = 0 );`. O Ghidra irá reatribuir automaticamente o valor de retorno para um ponteiro `IOMemoryMap` tanto para a definição da função quanto para as assinaturas de função.
Você pode adicionar qualquer símbolo C++ no diretório **signatures/** respeitando a sintaxe e pode encontrar assinaturas de função definidas neste diretório.```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 

Uso: Após simbolizar o kernel, é altamente recomendável executar o script load_sigatnures.py para carregar todas as assinaturas de função disponíveis. Como a maioria das ferramentas anteriores, execute este script adicionando-o na barra de ferramentas ou a partir do gerenciador de plugins ou apenas pressione Meta-Shift-S .

Carregando estruturas antigas:

Este script é direto, ele importa todas as estruturas, classes, typedefs, e definições de função e tudo com SourceType.USER_DEFINED de um projeto antigo para um novo.

Uso: Abra os projetos Ghidra antigo e novo na mesma ferramenta, vá para o script load_structs.py, coloque o nome do programa antigo na variável src_prog_string, e o novo na variável dst_prog_string, então execute o script.

Contribuir

Se você acha o projeto interessante e quer contribuir, faça um PR e eu o revisarei; entretanto, gostaria de ver contribuições nas seguintes áreas:

  • ghidra_kernelcache/signatures/kernel.txt: continue importando funções do kernel XNU, é muito simples, basta copiar/colar a definição da função.
  • ghidra_kernelcache/propagate.py : suporte a opcodes não tratados para melhor propagação de símbolos.

Crédito

Gostaria de agradecer a @s1guza pelo seu incrível iometa do qual o ghidra_kernelcache depende.

Baixar ferramenta