════════════════════════════════════════════════════════════ Исследование загрузки DLL/драйверов в ядре Windows ════════════════════════════════════════════════════════════ ─────────────────────────────────── Цель исследования ─────────────────────────────────── Проследить полный путь загрузки драйверов ядра Windows — от перечисления PnP-устройств до валидации PE-заголовков. Определить, какие проверки выполняет ядро при загрузке образа в память. ─────────────────────────────────── Стенд ─────────────────────────────────── • Host: macOS (Apple Silicon) • Target VM: Windows 11 ARM64 (ядро 26100) — Parallels • Debugger VM: Windows 11 ARM64 — Parallels • Транспорт: serial через Unix-сокеты ([ICODE]/tmp/kd.sock[/ICODE] ↔ [ICODE]/tmp/debugger.sock[/ICODE]), socat relay • Удалённое управление: windbg-agent MCP сервер на Debugger VM ([ICODE]0.0.0.0:44444[/ICODE]) ─────────────────────────────────── Цепочка вызовов загрузки драйвера ─────────────────────────────────── Полный путь от перечисления PnP-устройств до чтения PE-файла: Код (Text): PnpDeviceActionWorker └─ PiProcessStartSystemDevices └─ PipProcessDevNodeTree └─ PipCallDriverAddDevice └─ IopLoadDriver └─ MmLoadSystemImageEx └─ MiObtainSectionForDriver └─ MiCreateSectionForDriver └─ MiCreateSystemSection └─ MiCreateSection └─ MiCreateImageOrDataSection └─ MiCreateNewSection └─ MiCreateImageFileMap └─ MiVerifyImageHeader ─────────────────────────────────── Валидация PE-образа ─────────────────────────────────── ► Проверка MZ-сигнатуры (MiCreateImageFileMap+0x148) Первая проверка — чтение первых 2 байт файла и сравнение с сигнатурой [ICODE]MZ[/ICODE] (0x5A4D): Код (Text): ldrh w8,[x2] ; читаем первые 2 байта буфера файла mov w9,#0x5A4D ; 'MZ' = 0x5A4D cmp w8,w9 ; проверяем MZ-сигнатуру bne error ; отклоняем, если не MZ Если первые два байта не [ICODE]MZ[/ICODE] — файл отклоняется немедленно. ► Чтение PE-смещения (e_lfanew) После проверки MZ ядро читает поле [ICODE]e_lfanew[/ICODE] по смещению [ICODE]+0x3C[/ICODE] от начала файла — это указатель на PE-заголовок: Код (Text): ldr w8,[x0,#0x3C] ; e_lfanew — смещение до PE-заголовка ► Проверка границ Ядро проверяет, что: • Смещение [ICODE]e_lfanew[/ICODE] не выходит за пределы файла • Размер PE-заголовка не превышает размер файла • Есть достаточно места для чтения Optional Header ► Проверка PE\0\0-сигнатуры (MiVerifyImageHeader+0x20) Вторая ключевая проверка — чтение 4 байт по смещению [ICODE]e_lfanew[/ICODE] и сравнение с сигнатурой [ICODE]PE\0\0[/ICODE] (0x00004550): Код (Text): ldr w8,[x0] ; читаем 4 байта по смещению e_lfanew mov w9,#0x4550 ; 'PE\0\0' = 0x00004550 cmp w8,w9 ; проверяем PE-сигнатуру bne error ; отклоняем, если не PE ► Извлечение полей PE-заголовка После подтверждения PE-сигнатуры [ICODE]MiVerifyImageHeader[/ICODE] извлекает и проверяет поля: Код (Text): Смещение от PE Поле Проверка ────────────── ───────────────────── ────────────────────────────────────── +0x04 Machine Должно быть ненулевым (0xAA64 = ARM64) +0x16 Characteristics Проверяется бит 1 (IMAGE_FILE_EXECUTABLE_IMAGE) +0x18 Optional Header Magic 0x20B = PE32+ (64-bit) +0x14 SizeOfOptionalHeader Проверяется корректность размера +0x38 SectionAlignment Проверка выравнивания секций +0x50 SizeOfImage Проверка размера образа +0x28 EntryPoint Проверка точки входа ► Сводка констант Код (Text): Константа Значение Назначение ────────── ────────── ────────────────────────────── 0x5A4D 'MZ' Сигнатура DOS-заголовка 0x4550 'PE\0\0' Сигнатура PE-заголовка 0x20B PE32+ Magic для 64-битных образов 0xAA64 ARM64 Machine type для Windows on ARM 0x3C e_lfanew Смещение указателя на PE-заголовок в MZ ─────────────────────────────────── Наблюдаемые драйверы ─────────────────────────────────── При установке точки останова на [ICODE]MiCreateImageFileMap[/ICODE] во время PnP-перечисления наблюдались загрузки: • vmbusr.sys — VMBus Resource Device Driver (Hyper-V) • vmbkmclr.sys — VMBus Kernel CLR Driver (Hyper-V) Оба драйвера являются компонентами интеграции Hyper-V и ожидаемо загружаются в среде Parallels VM. Пример определения загружаемого драйвера через структуру [ICODE]KLDR_DATA_TABLE_ENTRY[/ICODE] в регистре x22: Код (Text): dt nt!_KLDR_DATA_TABLE_ENTRY @x22 Поле [ICODE]BaseDllName[/ICODE] содержит имя загружаемого модуля. ─────────────────────────────────── Структуры данных ─────────────────────────────────── ► KLDR_DATA_TABLE_ENTRY Структура, используемая ядром для учёта загруженных модулей: Код (Text): dt nt!_KLDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY +0x010 ExceptionTable : Ptr64 Void +0x018 EntryPoint : Ptr64 Void +0x028 DllBase : Ptr64 Void +0x030 SizeOfImage : Uint4B +0x038 FullDllName : _UNICODE_STRING +0x048 BaseDllName : _UNICODE_STRING ... ► PsLoadedModuleList Глобальный связный список всех загруженных модулей ядра. Каждый элемент — [ICODE]KLDR_DATA_TABLE_ENTRY[/ICODE], связанный через [ICODE]InLoadOrderLinks[/ICODE]. ─────────────────────────────────── MDL (Memory Descriptor List) ─────────────────────────────────── При маппинге PE-файла в адресное пространство ядра используется MDL: Код (Text): MiCreateImageFileMap → MiCreateMdl → MiCopyHeaderIfResident → проверка MZ MDL описывает физические страницы файла, которые будут отображены в виртуальную память ядрового пространства. ─────────────────────────────────── Выводы ─────────────────────────────────── 1. Двухступенчатая валидация: ядро проверяет MZ-сигнатуру (первые 2 байта) и PE-сигнатуру (4 байта по смещению e_lfanew) как первые два обязательных шага при загрузке любого драйвера. 2. Строгий порядок: сначала [ICODE]MiCreateImageFileMap[/ICODE] проверяет MZ, затем [ICODE]MiVerifyImageHeader[/ICODE] проверяет PE\0\0 и поля заголовка. Нарушение любого условия приводит к отклонению образа. 3. PE32+ только для 64-бит: на ARM64-системах ядро ожидает magic [ICODE]0x20B[/ICODE] (PE32+). 32-битные PE ([ICODE]0x10B[/ICODE]) не принимаются. 4. PnP-перечисление: загрузка драйверов запускается через [ICODE]PnpDeviceActionWorker[/ICODE] → [ICODE]PiProcessStartSystemDevices[/ICODE], что является стандартным механизмом Plug and Play для инициализации устройств. 5. Отладочный стенд: двух-VM конфигурация с socat relay и windbg-agent MCP позволяет эффективно исследовать внутренние механизмы ядра в реальном времени, устанавливая точки останова на конкретных функциях цепочки загрузки. --- Сообщение объединено, 28 май 2026 в 23:33 --- Кому какая тема интересна могу ресерч провести если годное будет)