Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
ghidra_kernelcache — фреймворк Ghidra для реверс-инжиниринга kernelcache iOS | Kitploit
Инструменты/GitHubGitHub/0x36/ghidra_kernelcache
Безопасность iOSОбратная инженерияАнализ Бинарных ФайловАнализ Прошивок
GitHub0x36/ghidra_kernelcache

ghidra_kernelcache

фреймворк Ghidra для реверс-инжиниринга kernelcache iOS

Репозиторий
370374 лет назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

ghidra_kernelcache: фреймворк для Ghidra для реверс-инжиниринга iOS kernelcache

Этот фреймворк является конечным продуктом моего опыта в реверс-инжиниринге Kernelcache. Обычно я ищу уязвимости путем ручного аудита ядра и его расширений и автоматизировал большинство вещей, которые действительно хотел видеть в Ghidra, чтобы ускорить процесс реверсинга, и это оказалось эффективным и экономит много времени. Фреймворк работает на iOS 12/13/14/15 и на macOS 11/12 (как kernelcache, так и одиночные KEXT) и был опубликован с намерением помочь людям начать исследования ядра iOS без необходимости готовить собственное окружение. Как я считаю, этот фреймворк (включая набор инструментов, которые он предоставляет, и некоторые базовые знания IOKit) достаточен для начала взлома Kernelcache.

Фреймворк полностью написан на Python и может быть расширен для создания других инструментов. Он предоставляет несколько базовых API, которые можно использовать практически в любом проекте, экономя время на чтение многословной документации. Вы можете ознакомиться с основными функциями в каталоге utils/.

Ghidra хорош при анализе Kernelcache, но, как и другие инструменты RE, требует некоторой ручной работы. ghidra_kernelcache предоставляет хорошую отправную точку для исправления проблем как в начале, так и в процессе реверс-инжиниринга, обеспечивая качественный вывод декомпилятора.

Существует похожий проект, созданный @_bazad в IDAPro под названием ida_kernelcache, который предоставляет хорошую отправную точку для исследователей, желающих работать с образом ядра в IDA. Мой фреймворк немного похож на работу Брэндона, но выходит за ее рамки, предлагая гораздо больше возможностей, чтобы сделать процесс работы с kernelcache менее болезненным.

Возможности:

  • Символизация iOS kernelcache.
  • Восстановление иерархии классов C++ и виртуальных таблиц.
  • Ссылки на вызовы виртуальных методов.
  • Автоматическое исправление диспетчерских таблиц внешних методов как для ::externalMethod(), так и для ::getTargetAndMethodForIndex().
  • Применение пространств имен к методам классов.
  • Распространение имен символов и типов по аргументам функций.
  • Применение сигнатур функций для известных функций ядра.
  • Импорт старых структур и классов из старого проекта в новый.

Эти возможности реализованы в виде отдельных инструментов, которые можно запускать либо с помощью горячих клавиш, либо щелчком по их значкам на панели инструментов.

Установка

Клонируйте репозиторий:```sh git clone https://github.com/0x36/ghidra_kernelcache.git

root@kitploit:~
**Важное примечание**: Проект протестирован на Ghidra 10.1_PUBLIC и 10.2_DEV и не является обратно совместимым.

Перейдите в *`Windows → Script Manager`*, нажмите на *`script Directory`*, затем добавьте *`ghidra_kernelcache`* в список путей к каталогам.
Перейдите в *`Windows → Script Manager`*, в списке *scripts* перейдите в категорию *`iOS→kernel`* и отметьте плагины, которые там видны, они появятся на панели инструментов GHIDRA.

В каталоге [logos/](https://github.com/0x36/ghidra_kernelcache/tree/master/logos) вы можете разместить свои собственные логотипы для каждого инструмента.

## Символизация iOS kernelcache

`ghidra_kernelcache` на первом этапе требует [iometa](https://github.com/Siguza/iometa/) (создан [@s1guza](https://twitter.com/s1guza)), мощный инструмент, предоставляющий информацию о классах C++ в двоичном файле ядра. Замечательно то, что он работает как отдельный бинарный файл, поэтому вывод можно импортировать в вашу любимую среду обратной разработки, просто проанализировав его. Моя среда берет вывод iometa и анализирует его для символизации и исправления виртуальных таблиц.

### Использование
После распаковки ядра выполните следующие команды:```sh
$ iometa -n -A /tmp/kernel A10-legacy.txt > /tmp/kernel.txt
# if you want also to symbolicate using jtool2
$ jtool2 --analyze /tmp/kernel

Загрузите kernelcache в Ghidra, НЕ ИСПОЛЬЗУЙТЕ BATCH import, загрузите его как образ Mach‑O.
После загрузки и автоматического анализа Kernelcache нажмите на иконку на панели инструментов или просто нажмите Meta‑Shift‑K, затем укажите полный путь к выводу iometa, который в нашем случае — /tmp/kernel.txt.

Если вы хотите использовать символы jtool2, вы также можете использовать jsymbol.py, расположенный в категории iOS→kernel.

iOS kernelcache API

Полные примеры API находятся в ghidra_kernelcache/kc.py

→ Вот несколько примеров манипуляции объектами классов:```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:~
Как видите, вы можете полностью или частично символизировать kernelcache, если была выбрана частичная символизация, `ghidra_kernelcache` автоматически построит все зависимости классов перед продолжением.
Если запустить скрипт для всего kernelcache (полная символизация), `ghidra_kernelcache` потратит несколько минут на анализ образа ядра.

После завершения Ghidra предоставит следующее:

→ В фильтр закладок добавлена новая категория под названием «iOS»: 

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image1.png" alt="изображение1" width="200"/>
                    
                    
→ Виртуальные таблицы классов IOKit добавлены в закладку «iOS» для лучшего и более быстрого поиска виртуальных таблиц; вы можете просто искать kext или класс, вводя буквы, слова или пакет kext в строке поиска.

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image2.png" alt="изображение2"/>


→ Исправление виртуальной таблицы: дизассемблирует/компилирует неизвестный код, исправляет пространства имён, повторно символизирует методы класса и применяет определение функции к каждому методу:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image3.png" alt="изображение3"/>

→ Создание пространств имён классов и помещение каждого метода в соответствующее пространство имён:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image4.png" alt="изображение4"/>

→ Создание структуры класса с учётом иерархии классов:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image5.png" alt="изображение5"/>

→ Создание vtable классов, и каждый метод имеет собственное определение метода для лучшего вывода декомпиляции: 

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image6.png" alt="изображение6"/>

Полная реализация находится в [`utils/class.py`.](https://github.com/0x36/ghidra_kernelcache/blob/master/utils/class.py)

Вот несколько скриншотов до и после символизации с помощью `ghidra_kernelcache`:

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image7.png" alt="изображение7"/>

<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image8.png" alt="изображение8"/>




## Символизация Kext в macOS
---
Поддержка macOS в `ghidra_kernelcache` предназначена как для kernelcache, так и для символизации отдельных KEXT для архитектур ARM64e и x86_64. 
**ВАЖНО:** На момент написания Ghidra не может обработать весь macOS kernelcache, но его можно загрузить в IDA для начального анализа, а затем импортировать базу данных (idb в xml) в Ghidra позже, но это выходит за рамки. Если вам удастся это сделать, `ghidra_kernelcache` позаботится обо всём остальном.

Необходимо выполнить несколько шагов перед символизацией любого расширения ядра macOS, так как основная цель `ghidra_kernelcache` — восстановить иерархию классов и управлять всеми структурами классов в единой базе данных; одно расширение ядра не удовлетворяет этим требованиям, что означает, что символизация отдельного KEXT требует символизации ядра и, возможно, других расширений ядра, от которых он зависит, поэтому здесь требуется некоторая дополнительная работа.
`ghidra_kernelcache` теперь предоставляет мощный способ символизировать расширения ядра, включая ядро, управляя и разделяя структуры классов и определения виртуальных методов через мощный *DataType Project Archive* от Ghidra.

### Шаги по символизации расширения ядра
- Создайте новую папку в вашем проекте Ghidra, затем загрузите ` /System/Library/Kernels/kernel.release.XXXXX` в эту папку и позвольте Ghidra проанализировать его.
- Создайте новый *Project Archive*: перейдите в `DataType Provider` → нажмите на стрелку в правом верхнем углу окна → `New Project Archive` → поместите его в только что созданную папку → дайте ему имя (например, macOS_12.1). 
- Теперь символизируйте ядро с помощью `ghidra_kernelcache`, процесс довольно похож на символизацию *kernelcache* для iOS.```bash
$ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt
  • В консоли Python, или вы можете найти полную реализацию скрипта в 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:~
- После завершения создаётся связь между архивом ядра и архивом `macOS_12.1`. Теперь щёлкните правой кнопкой мыши на `kernel.release.t8001` → `Commit DataTypes To` → `macOS_12.1`.
- Затем `Правый клик` → `Выбрать всё` → `Commit`.
- Сохраните архив проекта: `Правый клик` → `Save Archive`.
Мы только что создали архив проекта, который можно использовать во всех расширениях ядра.
Рассмотрим пример Kext `IOSurface` для 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
  • Загрузите Kext в ту же папку, где находятся база данных ядра и архив проекта, и дайте Ghidra завершить анализ
  • Загрузите архив проекта, который мы создали ранее macOS_12.1: перейдите в Data Type Manager → Open Project Archive, затем выберите macOS_12.1
  • Выполните следующие методы, полный скрипт можно найти в 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:~
**Важное замечание**: иногда `kc.process_kernel_kext()` завершается неудачей, потому что Ghidra не смогла деманглировать некоторые символы C++. Чтобы это исправить, откройте менеджер скриптов и запустите скрипт `DemangleAllScript.java`, затем  снова запустите  `kc.process_kernel_kext()`  снова.

### Пользовательские классы
Бывают случаи, когда некоторые классы C++ не могут быть символизированы `ghidra_kernelcache`  и `iometa`, поэтому была добавлена новая функция для обработки этого.
Реконструкция класса `Custom()` проходит по всем символам `::vtable` и проверяет, определен ли класс уже или нет; если нет, она автоматически создает структуру класса, определения функций для каждого идентифицированного метода класса, пространство имен и виртуальную таблицу для каждого  класса.

Создание пользовательских классов в данный момент поддерживается только в macOS.```bash
$ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt
$ iometa -n -A <kext_path> >> /tmp/kernel.txt

🗂️ Портированные драйверы Windows

Мы собрали список из более чем 200 эксплойтов в виде драйверов Windows для обхода PPL и EDR.

Все драйверы (включая добавленные из хаба Kernel Shellcode) находятся в папке Windows Drivers.

🚀 Добавлен хаб Kernel Shellcode

🔗 Найти его здесь: Kernel Shellcode HUB

🚀 Добавлен хаб Mac Inject

🔗 Найти его здесь: Mac Inject HUB

🚀 Добавлен хаб Linux Inject

🔗 Найти его здесь: Linux Inject HUB

🛡️ Добавлено перечисление EDR/AV с помощью WMI в Windows

🚀 Ветка разработки 🚀

cargo build для текущего Cargo.toml компилирует около 130+ бинарных файлов за раз.
Это стало слишком большим и сложным в поддержке.

Была создана ветка разработки, которая компилирует инструменты по категориям, чтобы сделать поддержку проще и быстрее.

🗒️ На данный момент в ветку разработки добавлены:

  • PIC Shellcode runner - PIC Coffee```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:~
## Miscellaneous scripts
---
### Importing KDK's Dwarf4 
Ghidra по какой-то причине не может загрузить соответствующую директорию `.dsym`, я написал небольшой скрипт для исправления этого. Его можно найти [здесь](https://github.com/0x36/ghidra_kernelcache/blob/master/dwarf4_fix.py).
**Usage** : Загрузите ядро из вашего пути KDK, дайте Ghidra завершить анализ, затем запустите `dwarf_fix.py`, он загрузит символы, и процесс может занять несколько минут.
<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image12.png" alt="image12"/>

### Resolving virtual method calls references 
`ghidra_kernelcache` предоставляет два способа разрешения виртуальных вызовов: `kernelCache.explore_pac` или `fix_extra_refs` 

**kernelCache.explore_pac()**
Если вы работаете с бинарным файлом arm64e, `ghidra_kernelcache` может распознавать вызовы виртуальных методов, просматривая значение `Pointer Authentication Code`. Процесс прямолинеен и, в отличие от `fix_extra_refs()`, `kernelCache.explore_pac` не полагается на идентификацию `Pcode` или `varnode`, он просто итерирует все инструкции в программе, ищет инструкции `MOVK`, извлекает второй операнд и ищет соответствующее значение в базе данных.
Использование:
Создайте экземпляр *KernelCache* через **kernelCache**, **Kext** или **Custom**, затем вызовите метод `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() Эта функция основана на базовом анализе потоков данных для поиска всех методов виртуальных вызовов и автоматического разрешения их реализаций. Она работает на всех архитектурах и способна распознавать исходный тип данных из вывода декомпилятора, разрешая все ссылки на виртуальные вызовы внутри функции, так что пользователь может переходить вперед/назад непосредственно к/от реализации без ручного поиска.

Наиболее полезная функция, предоставляемая fix_extra_refs, заключается в том, что она синхронизирует ссылки при каждом выполнении. Например, если вы изменили тип данных переменной на тип данных класса, fix_extra_refs автоматически распознает изменение и рекурсивно пройдёт по всем местам вызовов для разрешения их ссылок, останавливаясь только тогда, когда очередь мест вызовов опустеет.

Существуют и другие функции, предоставляемые fix_extra_refs, такие как:

  • Автоопределение вызовов _ptmf2ptf() и разрешение их метода вызова как для смещений, так и для полного адреса функции.
  • Определение пространства имён неразрешённого имени функции (функций, начинающихся с FUN_) и его разрешение путём помещения целевой функции в собственное пространство имён (например, добавление указателя this соответствующего класса).

Вы можете найти реализацию в utils/references.py. fix_extra_refs анализирует операции pcode и ищет опкоды CALLIND и CALL, затем получает все задействованные varnodes в операции. Как только определение Varnode идентифицировано, функция извлекает его HighVariable для определения типа объекта класса. Если тип неизвестен (т.е. не похож на структуру класса), он просто игнорируется; в противном случае берётся имя класса, выполняется поиск в его таблице виртуальных вызовов, и, используя смещение, предоставленное Varnode, можно получить правильный метод виртуального вызова и поставить ссылку на инструкцию вызова.```py fix_extra_refs(toAddr(address))

root@kitploit:~
Вот пример вывода при использовании `fix_extra_refs` :

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

Обратите внимание, что он успешно разрешил виртуальные вызовы **IOService::isOpen()**, **OSArray:getNextIndexOfObject()** и **IOStream::removeBuffer()** без каких-либо ручных изменений.

Затем `fix_extra_refs` декомпилирует **IOStream::removeBuffer()**, получает все HighVariables этого метода, а затем разрешает их ссылки, как и предыдущий метод ... и так далее.
<img src="https://raw.githubusercontent.com/0x36/ghidra_kernelcache/master/screenshots/image10.png" alt="image10"/>

### Автоматическое исправление внешних таблиц методов

Я уверен, что у каждого исследователя есть какой-нибудь скрипт для работы с этой частью, так как это основная поверхность атаки IOKit. Делать это вручную — тяжёлая работа, и это должно быть автоматизировано таким образом, чтобы исследователь мог погрузиться в изучение нескольких внешних таблиц методов. 
В составе `ghidra_kernelcache` предоставлены два скрипта: **fix_methodForIndex.py** и **fix_extMethod.py**. Вы можете включить их, как и другие скрипты, показанные выше.

***Использование***: Поместите курсор в начало внешней таблицы диспетчеризации, запустите скрипт: укажите цель и количество селекторов.
Пример для `IOStreamUserClient::getTargetAndMethodForIndex()` :

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

### namespace.py: исправление пространств имён методов …
Это полезный скрипт для присвоения типа класса всем встреченным методам, и он является зависимостью для скрипта `extra_refs.py`, чтобы рекурсивно исследовать вызываемые функции и разрешать их ссылки.

***Использование***: Поместите курсор в вывод декомпилятора нужной функции, запустите скрипт из панели инструментов или нажмите **Meta-Shift-N** .

### Распространение имён символов и типов
`ghidra_kernelcache` предоставляет поддержку распространения типов для базовых операций Pcode, но, скорее всего, потерпит неудачу для некоторых переменных, использующих сложное приведение типов.
Если кто-то хочет помочь или начать работать с низкоуровневыми вещами в Ghidra, это хорошая возможность.
Реализацию можно найти в [ghidra_kernelcache/propagate.py](https://github.com/0x36/ghidra_kernelcache/blob/master/propagate.py)

### Загрузка сигнатур функций

Разбор заголовочных файлов C++ в Ghidra невозможен, а наличие сигнатур функций ядра в kernelcache может значительно улучшить вывод декомпилятора.
Например, если мы добавили `virtual IOMemoryMap * map(IOOptionBits options = 0 );`, Ghidra автоматически переопределит возвращаемое значение на указатель `IOMemoryMap` как для определения функции, так и для сигнатур функций.
Вы можете добавить любой символ C++ в каталог **signatures/**, соблюдая синтаксис, и в этом каталоге можно найти определённые сигнатуры функций.```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 

Usage: После символизации ядра настоятельно рекомендуется запустить скрипт load_sigatnures.py, чтобы загрузить все доступные сигнатуры функций. Как и большинство предыдущих инструментов, запустите этот скрипт, добавив его на панель инструментов, из менеджера плагинов или просто нажав Meta-Shift-S .

Loading old structures:

Этот скрипт прямолинеен: он импортирует все структуры, классы, typedefs, определения функций и всё с SourceType.USER_DEFINED из старого проекта в новый.

Usage: Откройте старый и новый проекты Ghidra в одном инструменте, перейдите к скрипту load_structs.py, установите имя старой программы в переменную src_prog_string, а новой — в dst_prog_string, затем запустите скрипт.

Внести вклад

Если вы считаете проект интересным и хотите внести свой вклад, просто сделайте PR, и я его рассмотрю. Тем временем я бы хотел увидеть вклад в следующих областях:

  • ghidra_kernelcache/signatures/kernel.txt: продолжайте импортировать функции ядра XNU — это очень просто: просто скопируйте/вставьте определение функции.
  • ghidra_kernelcache/propagate.py : поддержка необработанных опкодов для лучшего распространения символов.

Благодарности

Я хотел бы поблагодарить @s1guza за его потрясающий iometa, от которого зависит ghidra_kernelcache.

Скачать инструмент