Уклонение от поведенческого детекта AV/EDR: почему оно возможно и как усиливать корреляцию сигналов

Поведенческий детект антивируса и EDR строится на наблюдении за событиями: создание процессов, загрузка образов, создание потоков, обращения к памяти других процессов. Эти события доставляются в ядро через механизм callback-уведомлений. Если атакующий получает возможность модифицировать или отключить эти коллбэки, поведенческий анализ теряет источник данных. Понимание механики уклонения — необходимое условие для построения защиты, которая не зависит от единственной точки отказа.

Как работает поведенческий детект на уровне ядра​


Windows предоставляет драйверам режим ядра три основных типа уведомлений:

  • Process notification callbacks (PsSetCreateProcessNotifyRoutineEx) — срабатывают при создании и завершении процессов.
  • Thread notification callbacks (PsSetCreateThreadNotifyRoutine) — уведомляют о создании и завершении потоков.
  • Image load callbacks (PsSetLoadImageNotifyRoutine) — вызываются при загрузке драйверов и DLL в адресное пространство процесса.

EDR-агент регистрирует свои коллбэки при загрузке драйвера. Массив коллбэков хранится в ядре, и каждый зарегистрированный драйвер получает уведомление о событии. Если коллбэк удалён или его код перезаписан, EDR перестаёт видеть соответствующие события.

Векторы уклонения: что именно атакуют​


Обнуление массива коллбэков​


Наиболее грубый метод: атакующий обнуляет весь массив коллбэков определённого типа. Все зарегистрированные потребители уведомлений теряют видимость событий. Этот подход легко детектируется, потому что исчезновение всех коллбэков — аномалия, которую можно проверить.

Удаление конкретного коллбэка по индексу​


Более точечный подход: из массива удаляется только запись, принадлежащая драйверу EDR. Остальные коллбэки продолжают работать. Для детектирования нужно сравнивать текущее состояние массива с ожидаемым списком зарегистрированных драйверов.

Патчинг кода коллбэка​


Вместо удаления записи из массива атакующий перезаписывает начало функции коллбэка инструкцией RET (0xC3). Формально коллбэк зарегистрирован и вызывается, но немедленно возвращает управление, не выполняя логику анализа. Это сложнее обнаружить, потому что структура массива не нарушена.

Манипуляция с CR0.WP​


Для записи в страницы кода ядра, которые защищены от записи, атакующий может временно сбросить бит Write Protect (WP) в регистре CR0. На x86-64 это выглядит так:

C:
void CR0_WP_OFF_x64() {
    cr0 mycr0;
    mycr0.flags = __readcr0();
    mycr0.write_protect = 0;
    __writecr0(mycr0.flags);
}

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

C:
int LogicalProcessorsCount = KeQueryActiveProcessorCount(NULL);
for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) {
    KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx(
        (KAFFINITY)(1i64 << processorIndex));
    CR0_WP_OFF_x64();
    KeRevertToUserAffinityThreadEx(oldAffinity);
}

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

Загрузка вредоносного драйвера​


Все перечисленные операции требуют выполнения кода в режиме ядра. Типичный путь — загрузка неподписанного или подписанного украденным сертификатом драйвера через менеджер служб:

Код:
sc create evil type= kernel binPath= c:\path\to\file\evildriver.sys
sc start evil

После загрузки драйвер получает полный доступ к структурам ядра и может выполнять любые манипуляции с коллбэками.

Почему это возможно: архитектурные предпосылки​


Несколько факторов делают уклонение принципиально возможным:

  1. Единое адресное пространство ядра. Все драйверы работают в одном адресном пространстве. Драйвер с правами Ring 0 может читать и модифицировать память любого другого драйвера.
  2. Отсутствие изоляции между драйверами. В отличие от пользовательских процессов, между драйверами нет аппаратной изоляции памяти.
  3. Массивы коллбэков — изменяемые структуры данных. Они не защищены криптографически и не верифицируются при каждом обращении.
  4. CR0.WP — глобальный флаг на процессор. Его может изменить любой код, выполняющийся в Ring 0.

Как усиливать защиту: корреляция сигналов и многоуровневый детект​


Мониторинг целостности массивов коллбэков​


EDR может периодически проверять, что его коллбэки по-прежнему зарегистрированы и их код не модифицирован. Это делается путём:

  • Сравнения указателей в массиве с ожидаемыми значениями.
  • Проверки первых байтов функции коллбэка на наличие RET или JMP на неожиданный адрес.
  • Верификации прав страниц через проверку записей в таблице страниц.

Пример вывода !pte в отладчике ядра для страницы коллбэка:

Код:
lkd> !pte 0xfffff80267fdd670
VA fffff80267fdd670
PXE at FFFF85C2E170BF80  PPE at FFFF85C2E17F0048
PDE at FFFF85C2FE0099F8  PTE at FFFF85FC0133FEE8
contains 0000000005108063  contains 0000000005109063
contains 0000000005219063  contains 09000000035C5021
pfn 5108 ---DA--KWEV  pfn 5109 ---DA--KWEV
pfn 5219 ---DA--KWEV  pfn 35c5 ----A--KREV

Флаг KREV (Kernel Read, Execute, Valid) без W означает, что страница защищена от записи. Если страница с кодом коллбэка внезапно получает флаг W — это индикатор атаки.

Контроль загрузки драйверов​


  • Driver Signature Enforcement (DSE) — обязательная проверка подписи драйверов на 64-битных системах. Не является абсолютной защитой, но повышает порог входа.
  • HVCI (Hypervisor-protected Code Integrity) — использует гипервизор для проверки целостности кода ядра. Даже драйвер с правами Ring 0 не может выполнить неподписанный код, если HVCI активна.
  • Аудит sc create — мониторинг создания новых служб типа kernel через Sysmon (Event ID 13) или аналогичные механизмы.
  • WDAC (Windows Defender Application Control) — позволяет задавать политики, ограничивающие загрузку исполняемого кода, включая драйверы. В контексте kernel-mode драйверов WDAC дополняет DSE, позволяя разрешать только драйверы из утверждённого списка издателей или с определёнными хешами.

Детектирование манипуляций с CR0​


Гипервизор может перехватывать запись в CR0 через механизм VM-exit. Если бит WP сбрасывается, гипервизор фиксирует это событие и может:

  • Заблокировать операцию.
  • Сгенерировать алерт.
  • Вернуть исходное значение.

Это один из ключевых аргументов в пользу HVCI и виртуализационных защит.

Корреляция сигналов из разных источников​


Ни один отдельный источник телеметрии не даёт полной картины. Устойчивый детект строится на корреляции:

ИсточникЧто даётОграничение
Kernel callbacksСобытия процессов, потоков, образовМогут быть отключены
ETW (Event Tracing for Windows)Низкоуровневые события ядраТребует активного потребителя
SysmonСоздание процессов, сетевые соединения, изменение реестраРаботает в user mode, может быть остановлен
ГипервизорПерехват MSR, CR, page table changesТребует аппаратной поддержки и привилегий
Сетевая телеметрияАномалии в трафикеНе видит локальные операции

Если коллбэки отключены, но ETW продолжает фиксировать создание процессов, а сетевой сенсор видит подозрительную активность — корреляция этих сигналов позволяет обнаружить атаку, которую один источник пропустил.

Практические меры для SOC и администраторов​


  1. Включить HVCI на всех поддерживаемых системах. Это блокирует патчинг кода ядра даже при наличии вредоносного драйвера.
  2. Мониторить список зарегистрированных коллбэков. Периодическая проверка через программные механизмы, доступные EDR-агенту, или через отладчик ядра в режиме расследования инцидентов.
  3. Контролировать загрузку драйверов. Ограничить список разрешённых драйверов через WDAC и DSE.
  4. Использовать несколько независимых источников телеметрии. Если EDR ослеплён, сетевой сенсор или ETW-потребитель должны продолжить фиксировать события.
  5. Маппить алерты на MITRE ATT&CK. Техники уклонения от детекта соответствуют тактике Defense Evasion (TA0005). Конкретные техники: Impair Defenses (T1562), Rootkit (T1014).

Ограничения защиты​


Полностью исключить уклонение от поведенческого детекта на уровне ядра невозможно без аппаратной изоляции. Даже HVCI не защищает от атак на прошивку или от уязвимостей в самом гипервизоре. Реалистичная цель — поднять стоимость атаки настолько, чтобы она стала нецелесообразной для большинства угроз, и обеспечить детектирование через корреляцию независимых источников.

Проверка текущего состояния системы​


Для быстрой диагностики на Windows-хосте:

  • Проверить статус HVCI: Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard — поле VirtualizationBasedSecurityStatus.
  • Проверить список загруженных драйверов: driverquery /v или через PowerShell Get-WmiObject Win32_SystemDriver.
  • Убедиться, что DSE активна: bcdedit /enum {current} — параметр nointegritychecks должен отсутствовать. Если он присутствует со значением Yes, DSE отключена.
  • Проверить, что EDR-служба работает и её драйвер загружен: наличие в выводе driverquery и отсутствие аномалий в Event Log (Event ID 7045 — установка новой службы).

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

Источники​


 
Назад
Верх Низ