BugChecker
Введение
BugChecker — это отладчик ядра и пользовательского режима для Windows 11 (а также Windows XP: поддерживаются версии Windows от XP до 11, как x86, так и x64), напоминающий SoftICE. В отличие от WinDbg и KD, BugChecker не требует второй машины, подключенной к отлаживаемой системе. Эта версия BugChecker (в отличие от оригинальной версии, разработанной 20 лет назад) использует внутреннее и недокументированное KD API в NTOSKRNL. KD API позволяет WinDbg/KD выполнять такие вызовы, как чтение/запись виртуальной памяти, чтение/запись регистров, установка точки останова по адресу и т. д.
Напротив, оригинальный BugChecker, как и SoftICE, «захватывал» систему, перехватывая несколько API ядра (как экспортируемых, так и частных), беря под контроль APIC, отправляя IPI и т. д. Такой подход экспоненциально увеличивает сложность (и снижает стабильность системы), поскольку реализация должна быть совместима со всеми поддерживаемыми версиями и подверсиями Windows (на уровне сигнатур функций), а также со всеми возможными поддерживаемыми конфигурациями оборудования. Более того, спустя 20 лет PatchGuard делает такое решение невозможным.
Напротив, эта версия BugChecker, перехватывая вызовы KdSendPacket и KdReceivePacket в ядре, представляется отлаживаемой машине как вторая система, запускающая внешний отладчик ядра, но на самом деле всё происходит на той же машине. Обычно это достигается заменой KDCOM.DLL (модуля, реализующего последовательное соединение для KD API в Windows) и запуском системы в режиме отладки ядра. Этот подход (вдохновлённый VirtualKD) снижает сложность, повышает стабильность и совместимость (а также переносимость, например, на ARM — и модульность, поскольку низкоуровневые возможности отладчика реализованы за KdXxxPacket и могут быть заменены пользовательской реализацией). Кроме того, наличие отладчика ядра во время загрузки (хотя и «поддельного») заставляет Windows отключать PatchGuard.
На данный момент BugChecker требует клавиатуру PS/2 для ввода и линейный буфер кадров для вывода. Обратите внимание, что встроенная клавиатура многих современных ноутбуков по-прежнему является PS/2.
Возможности
- Поддержка Windows от XP до Windows 11, x86 и x64, и SMP-ядер. Поддержка процессов WOW64 на x64.
- Интеграция QuickJSPP — порта QuickJS для MSVC++. Перед вызовом QuickJS BugChecker сохраняет состояние FPU (на x86) и переключается на расширенный стек размером 128 КБ.
- Команды принимают JS-выражения. Например, "U rip+rax*4" и "U MyJsFn(rax+2)" являются допустимыми командами. Пользовательские функции можно определить в окне скриптов. Регистры ЦП автоматически объявляются как переменные глобальной области видимости с помощью BugChecker.
- Поддержка PDB-файлов символов. PDB-файлы можно указать вручную, либо Symbol Loader может загрузить их с сервера символов.
- JavaScript-код может вызывать следующие асинхронные функции: WriteReg, ReadMem, WriteMem.
- Точки останова могут иметь JS-условие: если условие равно 0, «breakin» не происходит. Это позволяет устанавливать «Логпоинты» и точки останова, которые могут изменять поток выполнения.
- Окно лога показывает сообщения, отправленные отладчику ядра (например, сообщения DbgPrint).
- Окно JavaScript с подсветкой синтаксиса.
- Клавиша Tab позволяет по нескольким цифрам циклически перебирать все шестнадцатеричные числа на экране или по нескольким символам — все символы, содержащие эти символы.
- EASTL и корутины C++20 делают создание новых команд лёгким. Не стесняйтесь отправлять свои pull request'ы!
Видео (YouTube)
Демонстрация BugChecker на Windows 11 22H2, внутри VirtualBox 7.0.4. Написано условие точки останова на JavaScript, изменяющее поток выполнения в потоке пользовательского режима.

BugChecker, работающий в очень ограниченной среде: Raspberry Pi 4 (4 ГБ ОЗУ) через QEMU на Windows XP (512 МБ ОЗУ). Точка останова используется для журналирования всех вызовов SYSENTER из пользовательского режима в ядро. Индекс службы сохраняется в массиве JavaScript.

BugChecker, запущенный непосредственно на «голом железе» на HP Pavilion Dv2000 — старом ПК с клавиатурой PS/2. ОС — Windows 7 Home 32-бит.

Инструкции по установке
Введение
Убедитесь, что Secure Boot отключён при установке и использовании BugChecker. Обычно его можно снова включить позже. Если вы используете VMware или VirtualBox, Secure Boot можно отключить в настройках виртуальной машины.
Также рассмотрите возможность включения устаревшего меню загрузки, если используется Windows 8, 10 или 11, с помощью команды: bcdedit /set "{current}" bootmenupolicy legacy. Это обеспечивает более плавный процесс загрузки, позволяя одновременно выбрать параметр загрузки BugChecker и отключить проверку подписи драйверов.
Инструкции
Первый шаг — запустить Symbol Loader:

При необходимости отключите драйверы дисплея, нажав кнопку «Disable Display Drvs». То же самое можно сделать в диспетчере устройств Windows. После отключения драйверов дисплея они остаются отключёнными даже после перезагрузки системы. Их можно снова включить в любое время, когда BugChecker не используется.
Суть в том, что BugChecker требует линейный буфер кадров с форматом 32 бита на пиксель для отрисовки интерфейса. При отключении драйверов дисплея Windows отключает аппаратное ускорение для рисования своего интерфейса и переходит в режим совместимости с VGA. При работе на «голом железе» или VMware следует отключить драйверы дисплея. При работе на VirtualBox следует отключить драйверы дисплея или установить параметр vm_screen в BugChecker.dat, как описано ниже. При работе на QEMU отключать драйверы дисплея не нужно, но убедитесь, что указано устройство отображения "-vga std".
Обратите внимание, что режим совместимости с VGA может ограничить максимальное разрешение экрана. VMware ограничен максимальным разрешением 1152x864. QEMU с устройством отображения "-vga std" этим ограничением не страдает.
Интересно, что если BugChecker установлен в системе с более чем одной видеокартой, можно отключить драйверы дисплея только одной видеокарты, которая будет подключена к монитору, отображающему интерфейс BugChecker. Вторая карта (установленная как основной дисплей) сохранит все свои функции 2D- и 3D-ускорения, включая поддержку OpenGL и DirectX (ПРИМЕЧАНИЕ: протестировано на VMware с Windows 11 и дисплеем DisplayLink).
Затем нажмите «Start Driver», затем «Auto Detect» и, наконец, «Save». «Auto Detect» должен автоматически определить ширину, высоту, физический адрес и шаг буфера кадров. Однако вы можете указать эти настройки вручную (не забудьте нажать «Save» по завершении). Если «Stride» равен 0, он автоматически вычисляется как «Width» * 4 при запуске драйвера. «Address» (т.е. физический адрес буфера кадров) можно получить в диспетчере устройств Windows, нажав «Свойства» устройства отображения на вкладке «Ресурсы».
Затем нажмите «Callback» в разделе «KDCOM Hook Method», затем «Copy/Replace Kdcom» и, наконец, можно перезагрузить систему.
Эту процедуру настройки нужно выполнить только один раз, и драйверы дисплея можно снова включить при необходимости. Однако при использовании BugChecker драйверы дисплея должны быть снова отключены, если это требуется вашей конфигурацией.
Параметр vm_screen для VirtualBox (Экспериментально)
Параметр vm_screen в BugChecker.dat позволяет открыть интерфейс отладчика BugChecker в VirtualBox без предварительного указания разрешения экрана в Symbol Loader и без отключения драйверов дисплея.
Идея состоит в том, чтобы напрямую записывать в порты ввода-вывода и буфер команд виртуального устройства отображения, чтобы получить текущее разрешение экрана и уведомлять гипервизор о любых обновлениях в буфере кадров.
Это решение было вдохновлено драйвером X.org xf86-video-vmware.
Это решение работает только для виртуальных машин VirtualBox и требует ручного редактирования файла BugChecker.dat:

- В Symbol Loader вручную установите ширину и высоту буфера кадров на максимально возможное разрешение (т.е. размеры вашего компьютерного экрана). Установите шаг (stride) равным 0.
- Файл BugChecker.dat создаётся Symbol Loader в «C:\Windows\BugChecker».
- Параметр vm_screen следует добавить в раздел «settings->framebuffer».
- Иерархия настроек в этом файле определяется символами табуляции (не пробелами).
- Формат параметра: Command_Buffer_Start_Address (запятая) Command_Buffer_End_Address (запятая) I/O_Port_Base
- ВАЖНО: В настройках виртуальной машины, в разделе «Дисплей», выберите «VBoxSVGA» в качестве графического контроллера и снимите флажок «Включить 3D-ускорение».
Это экспериментальная функция. В будущем этот параметр будет автоматически добавляться Symbol Loader.
Реализованные команды
Имя команды и синтаксис выбраны максимально близкими к оригинальному SoftICE для NT:
- ? javascript-expression: Вычислить JavaScript-выражение.
- ADDR eprocess: Переключиться в контекст процесса (возвращает управление ОС).
- BC list|*: Удалить одну или несколько точек останова.
- BD list|*: Отключить одну или несколько точек останова.
- BE list|*: Включить одну или несколько точек останова.
- BL (без параметров): Список всех точек останова.
- BPX address [-t|-p|-kt thread|-kp process] [WHEN js-expression]: Установить точку останова на выполнение.
- CLS (без параметров): Очистить окно лога.
- COLOR [normal bold reverse help line]|[reset]: Отобразить, установить или сбросить цвета экрана.
- DB/DW/DD/DQ [address] [-l len-in-bytes]: Отобразить память как 8/16/32/64-битные значения.
- EB/EW/ED/EQ address -v space-separated-values: Редактировать память как 8/16/32/64-битные значения.
- KL EN|IT: Установить раскладку клавиатуры.
- LINES [rows-num]: Отобразить или установить текущее количество строк на дисплее.
- MOD [-u|-s] [search-string]: Отобразить информацию о модуле.
- P [RET]: Выполнить один шаг программы.
- PAGEIN address: Принудительно подгрузить страницу памяти (возвращает управление ОС).
- PROC [search-string]: Отобразить информацию о процессе.
- R register-name -v value: Изменить значение регистра.
- STACK [stack-ptr]: Сканировать стек в поиске обратных адресов.
- T (без параметров): Трассировать одну инструкцию.
- THREAD [-kt thread|-kp process]: Отобразить информацию о потоке.
- U address|DEST: Дизассемблировать инструкции.
- VER (без параметров): Отобразить информацию о версии.
- WD [window-size]: Переключить окно дизассемблера или установить его размер.
- WIDTH [columns-num]: Отобразить или установить текущее количество столбцов на дисплее.
- WR (без параметров): Переключить окно регистров.
- WS [window-size]: Переключить окно скриптов или установить его размер.
- X (без параметров): Выйти из экрана BugChecker.
Инструкции по сборке
Предварительные требования
- Visual Studio 2019
- Windows Driver Kit 7.1.0
Примечание: WDK должен быть установлен в местоположение по умолчанию, т.е. X:\WinDDK, где X — диск, на котором сохранены исходники BugChecker.
Пошаговое руководство по сборке драйвера ядра доступно здесь.
Описание проектов Visual Studio
- BugChecker: это драйвер ядра BugChecker, в котором реализована вся функциональность отладчика. Выходные файлы «Release|x86» и «Release|x64» включены в финальный пакет. Во время инициализации драйвер загружает свой конфигурационный файл из "\SystemRoot\BugChecker\BugChecker.dat" (в этом же каталоге хранятся все файлы символов), а затем пытается найти «KDCOM.dll» в пространстве ядра. Если найден, вызывается его экспортированная функция «KdSetBugCheckerCallbacks», тем самым перехватывая KdSendPacket и KdReceivePacket.
- SymLoader: это Symbol Loader. В финальный пакет включён только выходной файл «Release|x86». Symbol Loader используется для изменения конфигурации BugChecker (конфигурация записывается в "\SystemRoot\BugChecker\BugChecker.dat"), загрузки PDB-файлов и установки пользовательского модуля KDCOM.dll.
- KDCOM: это пользовательский модуль KDCOM.dll, который загружается NTOSKRNL при запуске системы. Он экспортирует функцию «KdSetBugCheckerCallbacks», которую вызывает драйвер для перехвата KdSendPacket и KdReceivePacket.
- pdb: это проект Ghidra «pdb». Оригинальная версия выводит содержимое PDB-файла в стандартный вывод в формате XML. Код был изменён для генерации вместо этого файла BCS.
- NativeUtil: поскольку Symbol Loader является WOW64-приложением в Windows x64, вызовы тех API, которые должны выполняться из образов нативной архитектуры, были перенесены сюда (например, вызовы API установки устройств и драйверов).
- HttpToHttpsProxy: это приложение ASP.NET Core, функция которого — выступать в качестве интернет-прокси для Symbol Loader при работе в Windows XP. Поскольку в XP устаревшая поддержка TLS, Symbol Loader не может загружать файлы с произвольного сервера символов. После развёртывания этого приложения в IIS в той же сети становится возможным загружать файлы с сервера символов в Windows XP, добавляя "http://<IP-АДРЕС_ВАШЕГО_IIS_СЕРВЕРА>/HttpToHttpsProxy/" к URL сервера в Symbol Loader.
Благодарности
- VirtualKD: первая POC-версия BugChecker была построена на основе модификации VirtualKD.
- BazisLib: код, отвечающий за кнопку «Copy/Replace Kdcom + Add Boot Entry» в Symbol Loader, взят из VirtualKD и использует BazisLib.
- EASTL: Здесь не получится использовать STL от MSVC++. EASTL — отличная альтернатива.
- Ghidra: проект «pdb» в BugChecker взят из Ghidra. Он был изменён для генерации BCS-файлов.
- Zydis: для окна дизассемблера в BugChecker.
- QuickJSPP, порт QuickJS для MSVC++: для JavaScript-движка, встроенного в драйвер ядра.
- ReactOS: для определений внутренних типов Windows KD.
- SerenityOS: для низкоуровневых функций манипуляции растровыми изображениями, используемых распределителем памяти BugChecker. Поскольку я начал BugChecker после того, как посмотрел видео Андреаса (после 10-летнего воздержания от C/C++ и любого низкоуровневого программирования), я захотел включить небольшой кусочек SerenityOS в BugChecker.