modern Windows PE Loader (Windows 10 / 11 24H2)

Тема в разделе "WASM.RESEARCH", создана пользователем galenkane, 2 авг 2026 в 15:24.

  1. galenkane

    galenkane Active Member

    Публикаций:
    4
    Регистрация:
    13 янв 2017
    Сообщения:
    502
    ──────
    ### 1. _LDR_DDAG_NODE — Граф зависимостей DLL (Directed Acyclic Graph)
    В Windows 10/11 Microsoft полностью отказалась от линейной инициализации DLL и перешла на граф зависимостей
    (DAG) для параллельной загрузки модулей в многопоточных процессах.
    dt nt!_LDR_DDAG_NODE
    +0x000 Modules : _LIST_ENTRY // Список всех _LDR_DATA_TABLE_ENTRY в этом узле
    графа
    +0x010 ServiceTagList : Ptr64 _LDR_SERVICE_TAG_RECORD
    +0x018 LoadCount : Uint4B // Активный счетчик ссылок загрузки
    +0x01c LoadWhileUnloadingCount: Uint4B // Защита от race condition при Unload
    +0x020 LowestLink : Uint4B // Алгоритм Тарьяна (поиск циклов в графе)
    +0x028 Dependencies : _LDRP_CSLIST // Входящие зависимости (от кого зависит DLL)
    +0x030 IncomingDependencies : _LDRP_CSLIST // Исходящие зависимости (кто зависит от этой
    DLL)
    +0x038 State : _LDR_DDAG_STATE // Состояние узла (LdrModulesInitComplete и др.)
    +0x048 PreorderNumber : Uint4B // Порядковый номер обхода графа (DFS/BFS)
    • Малоизученный аспект: Алгоритм поиска кольцевых зависимостей (LowestLink / Tarjan's Strongly Connected
    Components). Когда две DLL циклически ссылаются друг на друга (A зависит от B, а B от A), LdrpProcessWork
    использует LowestLink для объединения их в один узел графа (CondenseLink) и безопасно вызывается DllMain.
    ──────
    ### 2. _LDR_HOT_PATCH_STATE — Горячее патчение DLL в RAM (Windows 11 24H2)
    Совершенно новая подсистема в Windows 11 24H2 (+0x128 в _LDR_DATA_TABLE_ENTRY), позволяющая обновлять код
    загруженных системных DLL прямо в памяти процесса без перезапуска процесса и без reboot.
    /* +0x128 */ PVOID ActivePatchImageBase; // Адрес загруженной дельта-библиотеки (.hotpatch.dll)
    /* +0x130 */ ULONG HotPatchState; // 0 = LdrHotPatchBaseImage, 1 = PatchApplied, 2 = PatchReverted
    • Малоизученный аспект: При нанесении патча ядро атомарно подменяет точки входа функций через ARM64 BTI / BR
    или x64 JMP на адрес ActivePatchImageBase. Анализаторы процессов и антивирусы часто принимают эти адреса за
    инжекты в память.
    ──────
    ### 3. BaseAddressIndexNode / MappingInfoIndexNode — Быстрый поиск за O(log N)
    В _LDR_DATA_TABLE_ENTRY на смещениях +0x0C8 и +0x0E0 находятся встроенные узлы AVL-дерева
    (_RTL_BALANCED_NODE):
    /* +0x0c8 */ _RTL_BALANCED_NODE BaseAddressIndexNode; // Узел в дереве поиска по DllBase
    /* +0x0e0 */ _RTL_BALANCED_NODE MappingInfoIndexNode; // Узел в дереве поиска по памяти секции
    • Малоизученный аспект: Когда функция GetModuleHandle или VirtualQuery ищет, какой DLL принадлежит адрес
    0x00007FFC..., ядро не проходит по двусвязному списку, а делает бинарный поиск по AVL-дереву
    ntdll!LdrpModuleBaseAddressIndex.
    • Если вредоносный код удаляет модуль только из InLoadOrderModuleList (классический Unlinking), но забывает
    удалить его из AVL-дерева BaseAddressIndexNode, GetModuleHandle и отладчик всё равно мгновенно находят
    скрытый модуль!
    ──────
    ### 4. _LDRP_CSLIST — Компактные односвязные кольцевые списки
    Вместо классических _LIST_ENTRY (16 байт) внутренние подсистемы загрузчика используют _LDRP_CSLIST (8 байт):
    typedef struct _LDRP_CSLIST {
    PSINGLE_LIST_ENTRY Tail; // Указывает на ПОСЛЕДНИЙ элемент списка
    } LDRP_CSLIST, *PLDRP_CSLIST;
    • Малоизученный аспект: Список не содержит указателя на Head. Чтобы найти начало списка, ядро читает Tail-
    >Next. Это экономит память в сотнях узлов графа зависимостей _LDR_DDAG_NODE.
    ──────
    ### 5. EnclavePolicy & ShimEngineCallout — Анклавы VBS (Trustlets) и Shims
    В _LDR_DATA_TABLE_ENTRY битовые флаги на смещении +0x068 скрывают уникальные режимы изоляции:
    • ScpInExceptionTable / EnclaveContext: Используется при загрузке DLL в изолированные VBS Enclaves
    (Trustlets). Загрузчик перепроверяет цифровую подпись каждого сегмента секции через skmi.sys в VTL 1 до
    маппинга страниц.
    • ShimEngineCalloutSent: Флаг подсистемы совместимости (Application Compatibility Shims). При его установке
    ntdll!LdrpCallInitRoutine перенаправляет вызовы DllMain через apphelp.dll для подмены API.
    --- Сообщение объединено, 2 авг 2026 в 15:27 ---
    1. Полная конечная стейт-машина (_LDR_DDAG_STATE) — 15 состояний:
    Раскрыт полный цикл жизни узла от создания фреймворка до завершения:
    • -5 (LdrModulesMerged): Узлы с циклической зависимостью объединены в один блок.
    • 0 (LdrModulesPlaceHolder): Узел создан, памяти под модуль еще нет.
    • 4 (LdrModulesSnapping): Происходит биндинг Import Address Table (IAT).
    • 6 (LdrModulesCondensed): Алгоритм Тарьяна схлопнул группу циклов.
    • 8 (LdrModulesInitializing): Выполняется DllMain(DLL_PROCESS_ATTACH).
    • 9 (LdrModulesReadyToRun): Модуль полностью готов к работе.
    2. Реализация алгоритма поиска кольцевых зависимостей Тарьяна (SCC):
    • PreorderNumber (+0x048): Порядковый номер обхода графа в глубину (DFS).
    • LowestLink (+0x020): Минимальный доступный индекс вершины в стеке DFS.
    • CondenseLink (+0x040): Односвязный список объединения модулей при обнаружении замкнутого цикла
    (например, A.dll -> B.dll -> A.dll), позволяющий загрузчику предотвратить бесконечную рекурсию при
    вызовах DllMain.
    3. Защита от Race Condition при разгрузке (+0x01C LoadWhileUnloadingCount):
    Отдельный счетчик блокировки, предотвращающий краш потоков при одновременном вызове FreeLibrary в одном
    потоке и LoadLibrary в другом.
    --- Сообщение объединено, 2 авг 2026 в 15:29 ---
    Глубокое Исследование Live Hot-Patching в Windows 11 24H2 (_LDR_HOT_PATCH_STATE /
    NtManageHotPatch)

    Дата исследования: 2026-08-02
    Целевая система: Windows 11 24H2 (ARM64 / x64 Build 26100+)
    Исследуемые подсистемы: Memory Manager (MM), PE Loader (ntdll.dll), Virtualization-Based
    Security (VBS / HVCI)

    1. Введение и Архитектура
    В Windows 11 24H2 Microsoft впервые представила нативную подсистему Live Hot-Patching. Она позволяет
    обновлять активные бинарники ядра (ntoskrnl.exe, драйверы) и системные DLL пользовательского режима
    (ntdll.dll, kernel32.dll, csrss.exe) прямо в оперативной памяти без перезагрузки
    системы, без перезапуска служб и без простоя процессов
    .

    2. Новый Системный Вызов: NtManageHotPatch
    Главной точкой входа подсистемы является новый системный вызов ядра:
    Код (Text):
    1. NTSYSAPI
    2.   NTSTATUS
    3.   NTAPI
    4.   NtManageHotPatch(
    5.   In ULONG Operation,              // HOTPATCH_OP_LOAD, APPLY, UNLOAD, ENUM
    6.   In PUNICODE_STRING PatchPath,    // Путь к .hotpatch.dll / патчу
    7.   In ULONG Flags,                  // Флаги (HOTPATCH_FLAG_USER_SID, FORCE)
    8.   Out PULONG_PTR HotPatchHandle
    9.   );
    Команды операций (Operation):


    • []0x01 (HOTPATCH_OP_LOAD): Отображает файл патча в пространство ядра/процесса через [FONT=Courier
      New]MiMapHotPatchImageInSystemSpace[/FONT].
      []0x02 (HOTPATCH_OP_APPLY): Замораживает потоки процесса, валидирует подпись в VTL 1 и обновляет точки
      входа функций.
      []0x03 (HOTPATCH_OP_REVERT): Применяет таблицу откатов MiProcessHotPatchUndoTable для
      мгновенного отката патчей.
      []0x04 (HOTPATCH_OP_UNLOAD): Удаляет запись патча (MiDeleteHotPatchEntry) и освобождает память.

    3. Полный Поток Выполнения (Step-by-Step Kernel Workflow)
    Код (Text):
    1. [NtManageHotPatch]
    2.   │
    3.   ▼
    4.   1. Проверка валидности  ──► MiImageVadHotPatchEligible() / MiCheckHoldFaultForHotPatch()
    5.   │
    6.   ▼
    7.   2. Заморозка потоков    ──► MiFreezeHotPatchProcess() (Безопасная приостановка потоков)
    8.   │
    9.   ▼
    10.   3. Валидация в VTL 1    ──► VslApplyHotPatch() / VslObtainHotPatchUndoTable() [SMC/HVC Check]
    11.   │
    12.   ▼
    13.   4. Подготовка страниц   ──► MiPrepareImagePagesForHotPatch() (Copy-On-Write / SLAT Update)
    14.   │
    15.   ▼
    16.   5. Применение патча     ──► RtlApplyHotPatch() / MiApplyImageHotPatch()
    17.   │
    18.   ▼
    19.   6. Разморозка потоков   ──► Восстановление работы потоков и логирование через MiLogHotPatchOperation()

    4. Интеграция с VBS / VTL 1 (VslApplyHotPatch & HVCI)
    Так как защита Hypervisor-Protected Code Integrity (HVCI) делает память ядра Read-Only на уровне гипервизора
    (SLAT/EPT), прямая запись в исполняемую память ядра вызовет фатальный BugCheck.
    Патчинг происходит через безопасный гипервызов VTL 1:


    1. []VslObtainHotPatchUndoTable: Запрашивает у Secure Kernel (VTL 1) разрешение и
      получает зашифрованный буфер состояния.
      []VslApplyHotPatch: Генерирует SMC-вызов (SMC #0 /
      HVC #1) в VTL 1.
    2. Гипервизор VTL 1 проверяет цифровую подпись патч-бинарника, временно меняет права страниц SLAT на
      Writable, вставляет патч-трамплин (ARM64 BTI/BR или x64
      JMP
      ) и восстанавливает режим Read-Only / Executable.

    5. Механизм Отката и Гарантия Стабильности (MiProcessHotPatchUndoTable)
    Для предотвращения падения системы при сбоях ядро ведёт таблицу откатов HotPatch Undo Table:
    Код (Text):
    1. typedef struct _MI_HOTPATCH_UNDO_ENTRY {
    2.   PVOID       TargetAddress;     // Оригинальный адрес точки входа функции
    3.   ULONG       OriginalBytesLen;  // Длина перезаписанных инструкций (например, 12 байт)
    4.   UCHAR       OriginalBytes[16]; // Бэкап оригинальных опкодов
    5.   PVOID       PatchImageBase;    // Указатель на загруженный .hotpatch.dll
    6.   } MI_HOTPATCH_UNDO_ENTRY, *PMI_HOTPATCH_UNDO_ENTRY;
    Если при патчинге возникает ошибка (например, таймаут заморозки потоков в [FONT=Courier
    New]MiLogHotPatchProcessSuspensionFailure[/FONT]), ядро мгновенно исполняет [FONT=Courier
    New]MiProcessHotPatchUndoTable[/FONT], атомарно восстанавливая байты OriginalBytes.

    6. Изменения в структуре _LDR_DATA_TABLE_ENTRY
    Для отслеживания патчей в пользовательских DLL структура _LDR_DATA_TABLE_ENTRY в Windows 11 24H2 была
    расширена:
    Код (Text):
    1.     /* +0x128 / PVOID  ActivePatchImageBase; // Указатель на загруженную патч-DLL (NULL если не
    2.   пропатчено)
    3.   / +0x130 */ ULONG  HotPatchState;        // 0 = Base Image, 1 = Patched, 2 = Reverted

    Важность для Security Research и EDR


    • []Защитные подсистемы (EDR / AV) должны проверять статус RtlFindHotPatchInformation
      и поле ActivePatchImageBase в _LDR_DATA_TABLE_ENTRY перед тем, как ложно срабатывать на
      трамплины JMP/BR в памяти системных DLL.
      []Операции патчинга генерируют события ETW через MiLogHotPatchRundown и
      MiLogHotPatchPagesLocked, обеспечивая телеметрию на уровне ядра.
     
    Последнее редактирование: 2 авг 2026 в 15:33
    Mikl___ нравится это.