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

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

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

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

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

Категории

Все категории
Loading categories
difuze — Фаззер для драйверов ядра Linux | Kitploit
Инструменты/GitHubGitHub/ucsb-seclab/difuze
Безопасность AndroidАнализ уязвимостейФаззингАнализ Бинарных Файлов
GitHubucsb-seclab/difuze

difuze

Фаззер для драйверов ядра Linux

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

Популярное

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

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

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

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

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

difuze: Фаззер для драйверов ядра Linux

License

Этот репозиторий содержит все исходные файлы (включая скрипты настройки), необходимые для запуска difuze.

Протестировано на

Ubuntu >= 14.04.5 LTS

0. Запуск difuze из Docker

См. README

Как описано в нашей статье, difuze состоит из двух основных компонентов: Восстановление интерфейса и Движок фаззинга

1. Восстановление интерфейса

Механизм восстановления интерфейса основан на анализах проходов LLVM. Каждый шаг восстановления интерфейса реализован в виде отдельного прохода. Следуйте инструкциям ниже, чтобы запустить Восстановление интерфейса.

1.1 Настройка

Этот шаг устанавливает LLVM и c2xml:

Сначала убедитесь, что у вас установлен libxml (требуется для c2xml):

root@kitploit:~
sudo apt-get install libxml2-dev
sudo pip install lxml

Далее мы подготовили единый скрипт, который загружает и собирает все необходимые инструменты.

root@kitploit:~
cd helper_scripts
python setup_difuze.py --help
usage: setup_difuze.py [-h] [-b TARGET_BRANCH] [-o OUTPUT_FOLDER]

optional arguments:
  -h, --help        show this help message and exit
  -b TARGET_BRANCH  Branch (i.e. version) of the LLVM to setup. Default:
                    release_38 e.g., release_38
  -o OUTPUT_FOLDER  Folder where everything needs to be setup.

Пример:

root@kitploit:~
python setup_difuze.py -o difuze_deps

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

1.2 Сборка

Этот шаг зависит от успешного выполнения Настройки. У нас есть единый скрипт, который собирает всё, пожалуйста.

root@kitploit:~
cd InterfaceHandlers
./build.sh

1.3 Запуск

Этот шаг зависит от успешного выполнения Сборки. Для запуска компонентов восстановления интерфейса на драйверах ядра необходимо сначала преобразовать драйверы в LLVM-биткод.

1.3.1 Сборка ядра

Во-первых, нам нужно собрать ядро. То есть вы должны уметь компилировать ядро с помощью обычной настройки сборки, т.е. make. Сначала мы захватываем вывод команды make, а из этого вывода извлекаем точную команду компиляции.

1.3.1.1 Генерация вывода make
Вариант 1: Использование Bear (РЕКОМЕНДУЕТСЯ)
  1. Установите Bear
  2. Запустите make с помощью Bear:
    root@kitploit:~
    bear make <все опции make>
    
    Пример: bear make -j8

Это создаст файл compile_commands.json в текущем каталоге.

Вариант 2

Просто передайте V=1 и перенаправьте вывод в файл. Пример:

root@kitploit:~
make V=1 O=out ARCH=arm64 > makeout.txt 2>&1

ПРИМЕЧАНИЕ: НЕ ИСПОЛЬЗУЙТЕ НЕСКОЛЬКО ПРОЦЕССОВ, т.е. -j. Работа в многопроцессорном режиме испортит выходной файл, так как несколько процессов попытаются записать в него одновременно.

Вот и всё. Затем на следующем шаге наш скрипт берёт сгенерированный файл makeout.txt и запускает восстановление интерфейса на всех распознанных драйверах.

1.3.2 Запуск анализа восстановления интерфейса

Все различные шаги восстановления интерфейса объединены в единый скрипт helper_scripts/run_all.py Как запустить:

root@kitploit:~
cd helper_scripts
python run_all.py --help

usage: run_all.py [-h] [-l LLVM_BC_OUT] [-a CHIPSET_NUM] [-m MAKEOUT]
                  [-c COMPJSON] [-g COMPILER_NAME] [-n ARCH_NUM] [-o OUT]
                  [-k KERNEL_SRC_DIR] [-isclang] [-clangp CLANG_PATH]
                  [-llvmlinkp LLVMLINK_PATH] [-skb] [-skl] [-skp] [-skP]
                  [-ske] [-skI] [-ski] [-skv] [-skd] [-f IOCTL_FINDER_OUT]

optional arguments:
  -h, --help            show this help message and exit
  -l LLVM_BC_OUT        Destination directory where all the generated bitcode
                        files should be stored.
  -a CHIPSET_NUM        Chipset number. Valid chipset numbers are:
                        1(mediatek)|2(qualcomm)|3(huawei)|4(samsung)
  -m MAKEOUT            Path to the makeout.txt file.
  -c COMPJSON           Path to the compile_commands_json generated by Bear.
  -g COMPILER_NAME      Name of the compiler used in the makeout.txt, This is
                        needed to filter out compilation commands. Ex: aarch64
                        -linux-android-gcc
  -n ARCH_NUM           Destination architecture, 32 bit (1) or 64 bit (2).
  -o OUT                Path to the out folder. This is the folder, which
                        could be used as output directory during compiling
                        some kernels.
  -k KERNEL_SRC_DIR     Base directory of the kernel sources.
  -isclang              flag to indicate that clang was used to built the
                        kernel
  -clangp CLANG_PATH    Absolute path to the clang binary (if not provided,
                        the one available in the path will be used)
  -llvmlinkp LLVMLINK_PATH
                        Absolute path to the llvm-link binary (if not
                        provided, the one available in the path will be used)
  -skb                  Skip LLVM Build (default: not skipped).
  -skl                  Skip Dr Linker (default: not skipped).
  -skp                  Skip Parsing Headers (default: not skipped).
  -skP                  Skip Generating Preprocessed files (default: not
                        skipped).
  -ske                  Skip Entry point identification (default: not
                        skipped).
  -skI                  Skip Generate Includes (default: not skipped).
  -ski                  Skip IoctlCmdParser run (default: not skipped).
  -skv                  Skip V4L2 ioctl processing (default: not skipped).
  -skd                  Skip Device name finder (default: not skipped).
  -f IOCTL_FINDER_OUT   Path to the output folder where the ioctl command
                        finder output should be stored.


Скрипт собирает, связывает и запускает восстановление интерфейса на всех распознанных драйверах, поэтому это может занять значительное время (45–90 минут).

Приведённый выше скрипт выполняет следующие задачи в многопроцессорном режиме, чтобы задействовать все ядра CPU:

1.3.2.1 Сборка LLVM
  • Включено по умолчанию.

Все сгенерированные файлы биткода будут помещены в папку, указанную в аргументе -l. Этот шаг занимает много времени, в зависимости от количества ядер. Если вы уже выполнили этот шаг, его можно пропустить, передав -skb.

1.3.2.2 Связывание всех файлов биткода драйверов в единый файл биткода.
  • Включено по умолчанию.

Этот этап выполняет связывание: он просматривает все файлы биткода, определяет связанные файлы биткода, которые нужно связать, и связывает их (с помощью llvm-link) в единый файл биткода (который будет сохранён рядом с соответствующим файлом биткода).

Как и на предыдущем шаге, его можно пропустить, передав -skl.

1.3.2.3 Разбор заголовков для определения полей функций входа.
  • Включено по умолчанию.

Этот шаг ищет объявления точек входа в файлах заголовков и сохраняет их конфигурацию в файле: hdr_file_config.txt в каталоге сборки LLVM.

Чтобы пропустить: -skp

1.3.2.4 Определение точек входа во всех объединённых файлах биткода.
  • Включено по умолчанию.

Этот шаг определяет все точки входа во всех объединённых файлах биткода драйверов. Результат будет сохранён в файле: entry_point_out.txt в каталоге сборки LLVM.

Пример содержимого файла entry_point_out.txt:

root@kitploit:~
IOCTL:msm_lsm_ioctl:/home/difuze/kernels/pixel/msm/sound/soc/msm/qdsp6v2/msm-lsm-client.c:msm_lsm_ioctl.txt:/home/difuze/pixel/llvm_out/sound/soc/msm/qdsp6v2/llvm_link_final/final_to_check.bc
IOCTL:msm_pcm_ioctl:/home/difuze/kernels/pixel/msm/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c:msm_pcm_ioctl.txt:/home/difuze/pixel/llvm_out/sound/soc/msm/qdsp6v2/llvm_link_final/final_to_check.bc

Чтобы пропустить: -ske

1.3.2.5 Запуск Ioctl Cmd Finder для всех определённых точек входа.
  • Включено по умолчанию.

Этот шаг запускает основной компонент восстановления интерфейса (IoctlCmdParser) на всех точках входа из файла entry_point_out.txt. Результат для каждой точки входа будет сохранён в папке, указанной в опции -f.

Чтобы пропустить: -ski

1.4 Пример:

Теперь мы покажем пример от момента, когда у вас есть исходники ядра, до получения результатов восстановления интерфейса.

Мы загрузили ядро mediatek 33.2.A.3.123.tar.bz2. Сначала загрузите и распакуйте указанный выше файл.

Предположим, вы распаковали файл в папку: ~/mediatek_kernel

1.4.1 Сборка

Установите Bear и выполните следующие шаги:

root@kitploit:~
cd ~/mediatek_kernel
source ./env.sh
cd kernel-3.18
# следующий шаг может не потребоваться в зависимости от ядра
mkdir out
make O=out ARCH=arm64 tubads_defconfig
# генерация compile_commands.json
bear make -j8 O=out ARCH=arm64

1.4.2 Запуск восстановления интерфейса

root@kitploit:~
cd <путь_к_репозиторию>/helper_scripts

python run_all.py -l ~/mediatek_kernel/llvm_bitcode_out -a 1 -c ~/mediatek_kernel/kernel-3.18/compile_commands.json -n 2 -o ~/mediatek_kernel/kernel-3.18/out -k ~/mediatek_kernel/kernel-3.18 -f ~/mediatek_kernel/ioctl_finder_out

Приведённая выше команда занимает довольно много времени (30 мин – 1 час).

1.4.3 Понимание вывода

Во-первых, все результаты анализа будут находиться в папке: ~/mediatek_kernel/ioctl_finder_out (аргумент, переданный опции -f), для каждой точки входа будет создан файл .txt, содержащий всю информацию о восстановленном интерфейсе.

Если вас интересует только информация об интерфейсе, и вам не нужно ничего остальное, мы рекомендуем использовать скрипт parse_interface_output.py. Этот скрипт преобразует сложный вывод прохода восстановления интерфейса в удобные JSON-файлы с чистым и единообразным форматом.

root@kitploit:~
cd <путь_к_репозиторию>/helper_scripts
python parse_interface_output.py <каталог_ioctl_finder_out> <каталог_для_JSON_файлов>

Здесь <каталог_ioctl_finder_out> должен совпадать с папкой, которую вы передали опции -f, а <каталог_для_JSON_файлов> — это папка, где будут созданы JSON-файлы.

Вы можете использовать соответствующие JSON-файлы для восстановления интерфейса соответствующего ioctl.

1.4.4 Примечания:

1.4.4.1 Значение для опции -g (только если вы используете makeout.txt)

Чтобы указать значение для опции -g, вам нужно знать имя бинарного файла *-gcc, используемого для компиляции ядра. Простой способ узнать это — выполнить grep gcc makeout.txt, и вы увидите команды компиляции, из которых можно узнать имя бинарного файла *-gcc.

Для нашего примера выше, если вы выполните grep gcc makeout.txt для примера сборки, вы увидите много строк, подобных этой:

root@kitploit:~
aarch64-linux-android-gcc -Wp,-MD,fs/jbd2/.transaction.o.d  -nostdinc -isystem ...

Итак, значением для -g должно быть aarch64-linux-android-gcc.

Если ядро собирается как 32-битное, то бинарный файл, скорее всего, будет arm-eabi-gcc

Для чипсетов Qualcomm (или msm) вы можете увидеть *gcc-wrapper.py вместо *.gcc, в этом случае следует указать *gcc-wrapper.py.

1.4.4.2 Значение для опции -a

В зависимости от типа чипсета необходимо указать соответствующий номер.

1.4.4.3 Значение для опции -o

Это путь к папке, переданной опции O= команды make во время сборки ядра.

Не все ядра требуют отдельного пути вывода. Вы можете собрать ядро, не передавая опцию O, и в этом случае НЕ СЛЕДУЕТ указывать значение для этой опции при запуске run_all.py.

Ядра, собранные с помощью clang

Для ядер, собранных с помощью clang, в дополнение к указанным выше опциям укажите следующие (предполагая, что вы использовали compile_commands.json):

root@kitploit:~
-isclang -clangp <ПУТЬ_К_CLANG_ИСПОЛЬЗОВАННОМУ_ДЛЯ_СБОРКИ_ЯДРА> -llvmlinkp <ПУТЬ_К_LLVM_LINK (будет в той же папке, что и clang)>

1.5 Постобработка

Прежде чем мы сможем начать фаззинг, необходимо немного обработать вывод с помощью наших (извините) парсеров исследовательского качества.

Они находятся здесь. Основной скрипт для запуска — run_all.py:

root@kitploit:~
$ python run_all.py --help
usage: run_all.py [-h] -f F -o O [-n {manual,auto,hybrid}] [-m M]

run_all options

optional arguments:
  -h, --help            show this help message and exit
  -f F                  Filename of the ioctl analysis output OR the entire
                        output directory created by the system
  -o O                  Output directory to store the results. If this
                        directory does not exist it will be created
  -n {manual,auto,hybrid}
                        Specify devname options. You can choose manual
                        (specify every name manually), auto (skip anything that
                        we don't identify a name for), or hybrid (if we
                        detected a name, we use it, else we ask the user)
  -m M                  Enable multi-device output most ioctls only have one
                        applicable device node, but some may have multiple. (0
                        to disable)

Вам нужно передать -f каталог вывода анализа ioctl, например ~/mediatek_kernel/ioctl_finder_out.

-o — куда вы хотите сохранить результаты постобработки. Это будут легко читаемые XML-файлы (jpits).

-n — задаёт степень, в которой вы хотите полагаться на наше восстановление имени устройства. Если вы не хотите выполнять никакую работу/поиск имён, вы можете указать auto. Конечно, это приведёт к пропуску любого устройства, для которого мы не восстановили имя. Если вы хотите быть параноиком и не доверять ни одному из наших усилий по восстановлению (вполне разумно), вы можете использовать опцию manual, чтобы назвать каждое устройство самостоятельно. hybrid — это комбинация обоих: мы будем называть устройство за вас, когда сможем, и вернёмся к вам, когда потерпим неудачу.

-m — иногда ioctl могут соответствовать более чем одному устройству (это распространено для ioctl v4l2/subdev). Поддержка этого включена по умолчанию, но требует взаимодействия с пользователем для указания количества устройств для каждого устройства. Если это слишком раздражает, вы можете отключить запрос, передав -m 0 (мы будем предполагать одно устройство для каждого ioctl).

После запуска в вашей выходной папке должна появиться папка для каждого ioctl.

2 Фаззинг

2.1 Mango Fuzz

MangoFuzz — это наш простой прототип фаззера, основанный на Peach (в частности, MozPeach).

Это не особенно сложный фаззер, но он находит ошибки. Он также был создан с возможностью лёгкого расширения. У этого фаззера 2 компонента: движок фаззинга и исполнитель. Исполнитель находится здесь, а движок фаззинга — здесь.

2.1.1 Исполнитель

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

Просто скомпилируйте его для архитектуры вашего телефона, выполните adb push на телефон и запустите с указанием порта, который вы хотите слушать!

2.1.2 Движок фаззинга

Взаимодействие с MangoFuzz довольно простое. Вам понадобится объект Engine и объект Parser, в который вы передадите свой движок. Затем вы анализируете jpits с помощью Parser и запускаете Engine. Легко! Мы предоставили несколько простых скриптов для запуска, чтобы вы могли начать.

Чтобы запустить фаззинг для конкретных драйверов, вы можете использовать runner.py на одной из папок ioctl в выходном каталоге (созданном нашими скриптами постобработки).

Например: ./runner.py -f honor8/out/chb -num 1000. Это указывает MangoFuzz выполнить 1000 итераций по всем парам значений команд ioctl, относящихся к драйверу/ioctl chb.

Если вместо этого мы хотим запустить фаззинг для всего устройства (телефона), вы можете использовать dev_runner.py. Например: ./dev_runner.py -f honor8/out -num 100. Это будет циклически перебирать файлы драйверов, случайным образом переключаясь между ними, по 100 итераций каждый.

Обратите внимание, что до того, как движок фаззинга сможет взаимодействовать с телефоном, вам нужно будет настроить перенаправление портов через ADB, например adb forward tcp:2022 tcp:2022.

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