Поведенческий детект антивируса и EDR строится на наблюдении за событиями: создание процессов, загрузка образов, создание потоков, обращения к памяти других процессов. Эти события доставляются в ядро через механизм callback-уведомлений. Если атакующий получает возможность модифицировать или отключить эти коллбэки, поведенческий анализ теряет источник данных. Понимание механики уклонения — необходимое условие для построения защиты, которая не зависит от единственной точки отказа.
Windows предоставляет драйверам режим ядра три основных типа уведомлений:
EDR-агент регистрирует свои коллбэки при загрузке драйвера. Массив коллбэков хранится в ядре, и каждый зарегистрированный драйвер получает уведомление о событии. Если коллбэк удалён или его код перезаписан, EDR перестаёт видеть соответствующие события.
Наиболее грубый метод: атакующий обнуляет весь массив коллбэков определённого типа. Все зарегистрированные потребители уведомлений теряют видимость событий. Этот подход легко детектируется, потому что исчезновение всех коллбэков — аномалия, которую можно проверить.
Более точечный подход: из массива удаляется только запись, принадлежащая драйверу EDR. Остальные коллбэки продолжают работать. Для детектирования нужно сравнивать текущее состояние массива с ожидаемым списком зарегистрированных драйверов.
Вместо удаления записи из массива атакующий перезаписывает начало функции коллбэка инструкцией
Для записи в страницы кода ядра, которые защищены от записи, атакующий может временно сбросить бит Write Protect (WP) в регистре CR0. На x86-64 это выглядит так:
Поскольку каждый логический процессор имеет собственный регистр CR0, атакующий должен переключить аффинность потока на каждое ядро и сбросить WP на каждом из них:
Это позволяет модифицировать страницы, которые в нормальном режиме доступны только для чтения.
Все перечисленные операции требуют выполнения кода в режиме ядра. Типичный путь — загрузка неподписанного или подписанного украденным сертификатом драйвера через менеджер служб:
После загрузки драйвер получает полный доступ к структурам ядра и может выполнять любые манипуляции с коллбэками.
Несколько факторов делают уклонение принципиально возможным:
EDR может периодически проверять, что его коллбэки по-прежнему зарегистрированы и их код не модифицирован. Это делается путём:
Пример вывода
Флаг
Гипервизор может перехватывать запись в CR0 через механизм VM-exit. Если бит WP сбрасывается, гипервизор фиксирует это событие и может:
Это один из ключевых аргументов в пользу HVCI и виртуализационных защит.
Ни один отдельный источник телеметрии не даёт полной картины. Устойчивый детект строится на корреляции:
Если коллбэки отключены, но ETW продолжает фиксировать создание процессов, а сетевой сенсор видит подозрительную активность — корреляция этих сигналов позволяет обнаружить атаку, которую один источник пропустил.
Полностью исключить уклонение от поведенческого детекта на уровне ядра невозможно без аппаратной изоляции. Даже HVCI не защищает от атак на прошивку или от уязвимостей в самом гипервизоре. Реалистичная цель — поднять стоимость атаки настолько, чтобы она стала нецелесообразной для большинства угроз, и обеспечить детектирование через корреляцию независимых источников.
Для быстрой диагностики на Windows-хосте:
Эти проверки не гарантируют отсутствие компрометации, но позволяют обнаружить наиболее распространённые векторы уклонения на ранней стадии.
Как работает поведенческий детект на уровне ядра
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
После загрузки драйвер получает полный доступ к структурам ядра и может выполнять любые манипуляции с коллбэками.
Почему это возможно: архитектурные предпосылки
Несколько факторов делают уклонение принципиально возможным:
- Единое адресное пространство ядра. Все драйверы работают в одном адресном пространстве. Драйвер с правами Ring 0 может читать и модифицировать память любого другого драйвера.
- Отсутствие изоляции между драйверами. В отличие от пользовательских процессов, между драйверами нет аппаратной изоляции памяти.
- Массивы коллбэков — изменяемые структуры данных. Они не защищены криптографически и не верифицируются при каждом обращении.
- 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 и администраторов
- Включить HVCI на всех поддерживаемых системах. Это блокирует патчинг кода ядра даже при наличии вредоносного драйвера.
- Мониторить список зарегистрированных коллбэков. Периодическая проверка через программные механизмы, доступные EDR-агенту, или через отладчик ядра в режиме расследования инцидентов.
- Контролировать загрузку драйверов. Ограничить список разрешённых драйверов через WDAC и DSE.
- Использовать несколько независимых источников телеметрии. Если EDR ослеплён, сетевой сенсор или ETW-потребитель должны продолжить фиксировать события.
- Маппить алерты на 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или через PowerShellGet-WmiObject Win32_SystemDriver.
- Убедиться, что DSE активна:
bcdedit /enum {current}— параметрnointegritychecksдолжен отсутствовать. Если он присутствует со значениемYes, DSE отключена.
- Проверить, что EDR-служба работает и её драйвер загружен: наличие в выводе
driverqueryи отсутствие аномалий в Event Log (Event ID 7045 — установка новой службы).
Эти проверки не гарантируют отсутствие компрометации, но позволяют обнаружить наиболее распространённые векторы уклонения на ранней стадии.
