Детект в памяти Windows: почему in-memory активность оставляет признаки и как их анализируют защитники

Вредоносный код, который никогда не касается диска, всё равно вынужден взаимодействовать с механизмами операционной системы. Windows управляет памятью через строго определённые структуры данных, и любое выделение, изменение прав или создание потока фиксируется ядром. Именно эти следы и становятся основой для детекта.

Почему полностью невидимое выполнение невозможно​


Процессор x86-64 выполняет инструкции только из страниц памяти, помеченных как executable. Чтобы код начал работать, кто-то должен:

  1. Выделить регион виртуальной памяти (или перенаправить существующий).
  2. Записать в него машинные инструкции.
  3. Установить флаг исполнения (PAGE_EXECUTE или производные).
  4. Передать управление на этот адрес.

Каждый из этих шагов проходит через системные вызовы ядра Windows: NtAllocateVirtualMemory, NtWriteVirtualMemory, NtProtectVirtualMemory, NtCreateThreadEx и их аналоги. Ядро ведёт учёт всех операций в структурах EPROCESS и VAD (Virtual Address Descriptor). Даже если вредоносный код использует прямой системный вызов через syscall/sysenter, минуя user-mode API, ядро всё равно обновляет внутренние таблицы.

Полиморфные кодировщики — например, shikata_ga_nai из Metasploit — меняют байтовое представление шеллкода при каждой генерации, используют динамический ключ и не привязаны к конкретным регистрам. Это усложняет сигнатурный поиск по содержимому памяти, но не отменяет структурных артефактов: регион всё равно выделен, права всё равно изменены, поток всё равно создан.

Ключевые артефакты в памяти процесса​


VAD-дерево и аномалии прав доступа​


Каждый процесс Windows содержит дерево VAD-узлов, описывающих все выделенные регионы виртуальной памяти. Каждый узел хранит базовый адрес, размер, тип выделения (private, mapped, image) и флаги защиты.

Для защитника интересны регионы с комбинацией PAGE_EXECUTE_READWRITE (RWX). Легитимное ПО крайне редко создаёт такие страницы: компиляторы генерируют код в секциях .text с правами PAGE_EXECUTE_READ, а данные размещают в .data/.bss без права исполнения. RWX-регион в private-памяти процесса — сильный индикатор того, что код был записан и подготовлен к исполнению непосредственно в памяти.

Отсутствие backing image​


Когда регион памяти не привязан к файлу на диске (нет mapping к PE-образу), это означает, что содержимое было записано программно. В VAD-дереве такой регион помечен как PrivateMemory = 1. Если при этом регион имеет права исполнения и содержит валидные машинные инструкции — это классический признак shellcode или reflective loading.

Аномалии в цепочке потоков​


Каждый поток в Windows описывается структурой ETHREAD, связанной с EPROCESS. Защитные решения проверяют:

  • Стартовый адрес потока: указывает ли он на регион без backing image или на адрес внутри другого модуля (признак thread hijacking).
  • Стек потока: если стек потока не соответствует ожидаемому диапазону для данного модуля, это может указывать на stack pivot или выполнение из нестандартного места.
  • Parent process: поток создан процессом, который не является ожидаемым родителем (например, svchost.exe порождает cmd.exe с аргументами загрузки PowerShell).

Handle table и межпроцессное взаимодействие​


Таблица дескрипторов процесса содержит все открытые объекты: файлы, ключи реестра, другие процессы, мьютексы, события. Аномальные записи — например, дескриптор на процесс lsass.exe с правами PROCESS_VM_READ у нестандартного процесса — указывают на попытку чтения чужой памяти (credential dumping).

Подходы к анализу​


Статический дамп памяти​


Снятие полного дампа памяти процесса или всей системы позволяет провести офлайн-анализ. Инструменты вроде Volatility Framework парсят структуры ядра Windows и извлекают:

  • Список процессов с их VAD-деревьями.
  • Сетевые соединения на момент снятия дампа.
  • Загруженные DLL и их хеши.
  • Содержимое командных строк процессов.
  • Дескрипторы и мьютексы.

Преимущество: анализ не зависит от того, активен ли вредоносный код в момент исследования. Недостаток: дамп фиксирует состояние на одно конкретное мгновение и не показывает динамику.

Поведенческий мониторинг в реальном времени​


EDR-решения (Endpoint Detection and Response) подписываются на callback-механизмы ядра Windows:

  • PsSetCreateProcessNotifyRoutine — уведомление о создании/завершении процессов.
  • PsSetCreateThreadNotifyRoutine — уведомление о создании потоков.
  • PsSetLoadImageNotifyRoutine — уведомление о загрузке образов (DLL, драйверов).
  • ObRegisterCallbacks — фильтрация операций с объектами (открытие процессов, чтение памяти).

Эти callback-и позволяют фиксировать события в момент их возникновения и коррелировать их: например, последовательность «выделение RWX-региона → запись данных → создание потока с стартовым адресом в этом регионе» формирует цепочку, характерную для shellcode-инъекции.

ETW (Event Tracing for Windows)​


ETW предоставляет структурированный поток событий ядра и пользовательских провайдеров. Провайдеры вроде Microsoft-Windows-Kernel-Memory и Microsoft-Windows-Kernel-Process генерируют события выделения памяти, изменения прав и создания потоков. Аналитик может подписаться на эти события и строить детекты на основе последовательностей, не полагаясь на сигнатуры.

Что усложняет детект​


Полиморфизм и метаморфизм​


Как уже упоминалось, кодировщики вроде shikata_ga_nai генерируют уникальное байтовое представление при каждом запуске. Метаморфные движки идут дальше: перестраивают граф потока управления, вставляют мусорные инструкции, меняют порядок базовых блоков. Сигнатурный поиск по содержимому памяти против таких техник неэффективен.

Process hollowing и process doppelgänging​


Эти техники подменяют содержимое легитимного процесса после его создания. VAD-дерево при этом может выглядеть нормально (backing image присутствует), но фактическое содержимое страниц отличается от оригинального PE-файла на диске. Детект требует сравнения in-memory образа с on-disk файлом — по хешу или побайтово.

Direct system calls​


Вызов системных функций напрямую через syscall обходит user-mode хуки, которые устанавливают некоторые защитные продукты. Однако kernel-mode callback-и и ETW продолжают работать, поскольку они находятся ниже уровня системных вызовов.

Unhooking и обход EDR​


Продвинутые образцы пытаются удалить хуки EDR из ntdll.dll или kernel32.dll, перезаписывая первые байты функций оригинальными инструкциями. Это обнаруживается по сравнению текущего содержимого модулей в памяти с их образом на диске или с известными эталонными хешами.

Практические индикаторы для защитника​


При анализе дампа памяти или событий EDR стоит обращать внимание на следующие паттерны:

ИндикаторЧто проверяетсяТипичная причина
RWX-регион в private memoryVAD-дерево, флаги защитыShellcode, reflective DLL loading
Поток со стартовым адресом вне любого модуляETHREAD.StartAddress vs. список загруженных образовShellcode-инъекция
Процесс с VAD, не совпадающим с файлом на дискеСравнение хешей in-memory и on-diskProcess hollowing
Дескриптор на lsass.exe с VM_READ у нестандартного процессаHandle table, права доступаCredential dumping
Последовательность Allocate → Write → Protect → CreateThreadКорреляция событий ETW/EDRКлассическая цепочка инъекции
Командная строка процесса содержит base64 или encoded-параметрыПарсинг командной строки из EPROCESSObfuscated PowerShell, certutil abuse

Ограничения memory-based детекта​


  • Время жизни артефактов. Если вредоносный код освобождает память после выполнения (например, shellcode стирает себя после создания persistence), дамп, снятый позже, может не содержать улик.
  • Шифрование в памяти. Некоторые образцы хранят payload в зашифрованном виде и расшифровывают только на время исполнения, после чего затирают расшифрованную копию.
  • Объём данных. Полный дамп памяти 64-битной системы с 32 ГБ RAM — это файл размером в десятки гигабайт. Офлайн-анализ требует времени и ресурсов.
  • Ложные срабатывания. JIT-компиляторы (Java, .NET, JavaScript-движки браузеров) легитимно создают RWX-регионы. Детект должен учитывать контекст процесса.

Memory-based детект не является серебряной пулей, но он закрывает слепую зону, которую оставляет файловый антивирус: код, который существует только в оперативной памяти и никогда не появляется на диске в исполняемом виде. Комбинация структурного анализа VAD, поведенческой корреляции событий и сравнения in-memory образов с дисковыми файлами даёт защитнику устойчивое покрытие против большинства техник fileless-атак.

Источники​


 

Похожие темы

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