- 53
- 61
Заливаю с моего ТГК .Привет. Данный пост я пишу для своего ТГ-канала. Я решил оформить тему в виде статьи на Teletype , так как лимит символов в Telegram немного ограничивает - приходилось делить посты на 2-3 части, что выглядело не очень аккуратно. Возможно, в будущем я куплю Premium.
Кстати. Про ETW я вкратце проходился в своей статье на Хабре, кому интересно - можете почитать. Начнем!
Архитектура ETW включает в себя 4 элемента:
Если вы взгляните на старые антивирусы или антивирусы, которые разрабатывают не очень опытные в данной сфере программисты , то заметите, что им довольно нравится использовать DLL-библиотеки для реализации IAT/EAT-хуков. Впрочем, я не говорю, что этот способ мертв. Например, IAT-хуки можно реализовать непосредственно внутри браузера, перехватывая такие функции, как GetMessage или PeekMessage, и при необходимости изменять обрабатываемые сообщения. Например, это можно использовать, например, для вмешательства в обработку нажатий клавиш и подмены данных, которые получает приложение(а-ля защита от кейлоггера). Но если речь идет об антивирусе, который в 2026 году в большей степени полагается на поведенческий анализ и корреляцию событий, то строить мониторинг исключительно на таких хуках, по мнению автора, довольно сомнительная идея. Ведь есть столь прекрасная технология, как ETW-Ti. Начнем углубляться.
Так , мы знаем, что данный источник телеметрии позволяет отслеживать определенные события. Но какие именно события нас интересуют в первую очередь? В целом, ETW-Ti предоставляет довольно интересный набор данных, связанных с операциями над виртуальной памятью, потоками и другими действиями внутри системы , самое интересное здесь то, что подобные операции могут встречаться как в обычной работе программ, так и при реализации различных техник внедрения кода в чужой процесс. Соответственно, для защитного ПО сама по себе отдельная операция не всегда является чем-то подозрительным, однако в совокупности с другими событиями она уже может представлять определенный интерес. Разберем самые интересные из них(события) -
Непосредственно внутри функции MiReadWriteVirtualMemory и реализуется сбор телеметрии через специальную внутреннюю структуру в ядре, которая называется EtwpThreatIntelProvider. Когда MiReadWriteVirtualMemory делает свою работу, она параллельно вызывает функцию логирования - EtwTiLogReadWriteVm. Та собирает всю необходимую информацию(кто читал, кого читал, сколько байт и какой пользовательский call-стэк при этом был) и пытается передать это добро дальше.
Непосредственно внутри EtwTiLogReadWriteVm вызывается системная функция ядра EtwpEventWriteFull. Она смотрит на этот самый EtwpThreatIntelProvider и проверяет -
Непосредственно такие вызовы осуществляются везде, откуда ETW-Ti собирает телеметрию, также посмотрим внутрь функции MiMapViewOfSectionExCommon и заметим абсолютно тоже самое:
Как видно на скриншоте, в самом конце успешного маппинга секции ядро точно так же вызывает внутренний логгер(выделен красным). На этом со сбором телеметрии закончу. Теперь поговорим касаемо того, как вообще происходит использование ETW-Ti и непосредственно его обход.
Если выбирать вариант с маппером своего драйвера, то все получается в разы проще. От уязвимого драйвера-донора нам нужен самый минимум - условно, просто примитив для выделения и маппинга памяти, чтобы один раз подсунуть и запустить наш собственный код в ядре. А вот во втором случае(пытаться сделать все чисто через IOCTL чужого драйвера, без маппинга своего) начнется геморрой. Там должно совпасть слишком много вещей - нужно найти живой драйвер со специфическими примитивами произвольного чтения-записи произвольной памяти.
Теперь про сам обход. Для начала нужно понять, как ядро администрирует текущие сессии трассировки, в результате чего мы натыкаемся на недокументированную структуру WMI_LOGGER_CONTEXT. Каждая активная сессия описывается данной структурой внутри ядра, манипулируя ее полями, атакующий драйвер может перенастроить правила игры. Внутри данной структуры есть интересные поля, например -
Внутри вы можете наблюдать поле IsEnabled. Когда ядро вызывает функцию EtwProviderEnabled под капотом оно идет в данную структуру и проверяет, равен ли флаг данного поля единице или нет, если нет - весь механизм сбора телеметрии сворачивается до того, как начнет упаковывать данные операции с памятью и т.д.
О чем статья, мистер?
Сегодня в статье я бы хотел обсудить технологию ETW-Ti. Она в корне отличается от классического использования ETW. Когда малварь обходит обычный ETW, она просто патчит пару байт в библиотеке ntdll.dll внутри своего процесса в пространстве пользователя, чтобы перестать слать отчеты. С ETW-Ti такой фокус физически не прокатит. Этот источник телеметрии зашит глубоко в само мясо ядра Windows. События генерирует не сам процесс, а операционная система, когда этот процесс выполняет опасные действия. Соответственно, из пользовательского пространства дотянуться до этого логгера крайне трудно.Кстати. Про ETW я вкратце проходился в своей статье на Хабре, кому интересно - можете почитать. Начнем!
Для начала поговорим про стандартный ETW.
ETW представляет собой встроенную в Windows инфраструктуру трассировки событий. Различные компоненты операционной системы и приложения могут публиковать информацию о происходящих событиях, а другие компоненты, в том числе средства мониторинга и защиты, могут организовать сеанс сбора этих данных и получать интересующую их телеметрию, собственно антивирусу не обязательно самостоятельно внедряться в каждый процесс или устанавливать отдельный перехватчик для каждой интересующей его операции - в некоторых случаях необходимая информация уже может предоставляться самой операционной системой через соответствующих поставщиков событий.- Поставщик событий - компонент который создает события ETW. Им может быть, как сама операционная система, так и отдельное приложение или драйвер. Например, компонент системы может сообщить о создании процесса, загрузке образа или другом интересующем событии, задача протокола это сформировать событие и передать его инфраструктуре ETW;
- Сеанс трассировки - механизм, через который происходит непосредственный сбор событий. Он связывает поставщиков с системой, которая эти события получает. При запуске сеанса определяется, какие поставщики будут активны и какие события от них необходимо собирать. Полученные данные могут временно находиться в буферах, а затем передаваться потребителю или записываться в журнал;
- Потребитель - компонент, который получает события из сеанса трассировки и обрабатывает их. На данном этапе собранная информация начинает использоваться по назначению, например, антивирусный процесс может получить событие о создани нового процесса, извлечь из него идентификатор процесса, путь к исполняемому файлу и другие данные, после чего передать информацию своему механизму анализа;
- Контроллер - компонент отвечающий за управление сеансом трассировки. Через него можно запустить или остановить сеанс, добавить или отключить поставщиков, а также изменить параметры сбора событий.
ETW-Ti.
ETW-Ti(ETW Threat Intelligence) - это технология которая разработана Microsoft для качественных EDR-решений. Она является источником телеметрии, сама же технология работает глубоко внутри ядра Windows и создана для того , чтобы отслеживать выполнение подозрительных действий в системе - вроде аллокация виртуальной памяти, изменение прав защиты памяти, маппинг файла в память и т.д.Если вы взгляните на старые антивирусы или антивирусы, которые разрабатывают не очень опытные в данной сфере программисты , то заметите, что им довольно нравится использовать DLL-библиотеки для реализации IAT/EAT-хуков. Впрочем, я не говорю, что этот способ мертв. Например, IAT-хуки можно реализовать непосредственно внутри браузера, перехватывая такие функции, как GetMessage или PeekMessage, и при необходимости изменять обрабатываемые сообщения. Например, это можно использовать, например, для вмешательства в обработку нажатий клавиш и подмены данных, которые получает приложение(а-ля защита от кейлоггера). Но если речь идет об антивирусе, который в 2026 году в большей степени полагается на поведенческий анализ и корреляцию событий, то строить мониторинг исключительно на таких хуках, по мнению автора, довольно сомнительная идея. Ведь есть столь прекрасная технология, как ETW-Ti. Начнем углубляться.
Так , мы знаем, что данный источник телеметрии позволяет отслеживать определенные события. Но какие именно события нас интересуют в первую очередь? В целом, ETW-Ti предоставляет довольно интересный набор данных, связанных с операциями над виртуальной памятью, потоками и другими действиями внутри системы , самое интересное здесь то, что подобные операции могут встречаться как в обычной работе программ, так и при реализации различных техник внедрения кода в чужой процесс. Соответственно, для защитного ПО сама по себе отдельная операция не всегда является чем-то подозрительным, однако в совокупности с другими событиями она уже может представлять определенный интерес. Разберем самые интересные из них(события) -
- 0x01 - KERNEL_THREATINT_TASK_ALLOCATE_VIRTUAL_MEMORY | NtAllocateVirtualMemory - выделение виртуальной памяти локально ИЛИ удаленно.
- 0x02 - KERNEL_THREATINT_TASK_PROTECT_VIRTUAL_MEMORY | NtProtectVirtualMemory - изменение прав защиты памяти.
- 0x03 - KERNEL_THREATINT_TASK_MAPVIEW | NtMapViewOfSection - отображение секции(файла) в память процесса.
- 0x04 - KERNEL_THREATINT_TASK_QUEUEUSERAPC | NtQueueUserAPC - постановка асинхронного вызова процедуры APC в поток другого процесса.
- 0x05 - KERNEL_THREATINT_TASK_SETCONTEXTTHREAD | NtSetContextThread - жесткое изменение контекста потока. Ядро генерирует это событие, когда кто-то пытается переписать регистры процессора(типа RIP/EIP или отладочные DR0-DR7) в чужом потоке.
- 0x06 - KERNEL_THREATINT_TASK_GETCONTEXTTHREAD | NtGetContextThread - чтение контекста потока.
- 0x07 - KERNEL_THREATINT_TASK_READVM | NtReadVirtualMemory - чтение памяти другого процесса.
- 0x08 - KERNEL_THREATINT_TASK_WRITEVM | NtWriteVirtualMemory - прямая запись в память чужого процесса.
- 0x09 - KERNEL_THREATINT_TASK_SUSPENDRESUMETHREAD | NtSuspendThread / NtResumeThread - заморозка или отморозка конкретного потока.
- 0x0A - KERNEL_THREATINT_TASK_SUSPENDRESUMEPROCESS | NtSuspendProcess / NtResumeProcess - приостановка работы всего процесса сразу.
- Если провайдер активен и к нему подключен EDR(сессия трассировки запущена), то все собранные данные успешно улетают в системные буферы ETW, откуда их потом забирает антивирус.
- Если сессии нет - вызов просто завершается ведь телеметрию просто некому передавать.
C++:
if ( KeGetCurrentThread()->PreviousMode == 1 )
{
if ( a4 == 16 )
JUMPOUT(0x14093B816LL);
if ( EtwProviderEnabled(RegHandle: RegHandle, Level: 0, Keyword: 0xC0000u) != 0 )
{
if ( a2 == a3 )
{
v10 = 0;
v11 = (const EVENT_DESCRIPTOR *)&RtlSystemOverrideInformation;
}
else
{
v10 = EtwProviderEnabled(RegHandle: RegHandle, Level: 0, Keyword: 0x200000000uLL);
v11 = &PfSnEvt_GetReadLists_Stop;
}
v12 = v11;
Регистрация ETW-Ti.
Вышел я подмечал, что данная технология используется в частности антивирусным защитным ПО, которому важно обеспечивать сбор данных поведенческим способом. Microsoft не выдают документацию данной технологии налево и направо, вследствие, чтобы получить документацию - компания должна пройти жесткий аудит, доказать, что разрабатывает именно защитное ПО(EDR/антивирус), и заключить с Microsoft специальное соглашение, также пользовательский сервис должен обладать статусом защиты AM-PPL. Впрочем, мутная и сложная тема.Сэр, а может, теперь про обход?
Теперь про сам обход. Сразу скажу, что из пользовательского пространства обойти данную технологию не выйдет(т.е без драйвера), разработчик в любом случае под рукой должен иметь либо свой с нуля разработанный драйвер , который маппится в пространство ядра через индивидуальный маппер(аналог kdmapper-а), либо, реализовать этот обход через коммуникацию с BYOVD-драйвером через простые IOCTL-запросы.Если выбирать вариант с маппером своего драйвера, то все получается в разы проще. От уязвимого драйвера-донора нам нужен самый минимум - условно, просто примитив для выделения и маппинга памяти, чтобы один раз подсунуть и запустить наш собственный код в ядре. А вот во втором случае(пытаться сделать все чисто через IOCTL чужого драйвера, без маппинга своего) начнется геморрой. Там должно совпасть слишком много вещей - нужно найти живой драйвер со специфическими примитивами произвольного чтения-записи произвольной памяти.
Теперь про сам обход. Для начала нужно понять, как ядро администрирует текущие сессии трассировки, в результате чего мы натыкаемся на недокументированную структуру WMI_LOGGER_CONTEXT. Каждая активная сессия описывается данной структурой внутри ядра, манипулируя ее полями, атакующий драйвер может перенастроить правила игры. Внутри данной структуры есть интересные поля, например -
- LoggerMode - данное поле описывает флаги конфигурации сессии. Например, если сбросить биты отвечающие за доставку логов в реальном времени, защитное ПО просто перестанет оперативно получать события.
- AcceptNewEvents - Булево поле. Тоже можно к чертям выставить на 0, в результате чего, получаем то, что получаем - новые сессии больше не принимаются.
C++:
typedef struct _TRACE_ENABLE_INFO {
ULONG IsEnabled;
UCHAR Level;
UCHAR Reserved1;
USHORT LoggerId;
ULONG EnableProperty;
ULONG Reserved2;
ULONGLONG MatchAnyKeyword;
ULONGLONG MatchAllKeyword;
} TRACE_ENABLE_INFO, *PTRACE_ENABLE_INFO;