Как вредоносные программы используют reflected DLL injection

Если вы разбираетесь в том, как малварь прячется в процессах, рано или поздно вы упрётесь в reflected DLL injection. Это не теория из учебников — технику реально используют в современных атаках, и её понимание критично, если вы расследуете инциденты, настраиваете защиту или просто хотите знать, что происходит под капотом. Ниже разберём именно механику, зачем злоумышленники её выбирают и на что смотреть при анализе.

Что это вообще такое

Классическая DLL-инъекция — это когда вредоносный код загружает библиотеку с диска в адресное пространство другого процесса. Всё просто: нашли DLL на диске, вызвали LoadLibrary, и код стартовал. Но у этого подхода есть слабое место — файл на диске. Его легко обнаружить, просканировать, удалить.

Reflected DLL injection решает эту проблему иначе. Вместо того чтобы загружать библиотеку через стандартный механизм Windows, код сам реализует загрузчик. DLL не лежит на диске — она прилетает в память, и инжектор вручную проходит все этапы, которые обычно делает операционная система: маппинг секций, релокации, разрешение импортов, вызов точки входа.

Ключевой момент: загрузчик не просто копирует байты. Он воссоздаёт то, что делает ntdll!LdrLoadDll на уровне структур PE-файла. Поэтому целевой процесс не знает, что в него что-то загрузили — в списке модулей ничего нового не появляется.

Почему малварь выбирает именно этот подход

Злоумышленники не используют сложные техники ради сложности. Reflected injection даёт конкретные преимущества перед другими методами:

  • Нет файла на диске. Антивирусы и EDR-решения привыкли сканировать файлы. Когда DLL существует только в памяти, сигнатурный анализ на диске бесполезен.
  • Меньше артефактов в системе. Нет записи на диске — нет следов в файловой системе, которые можно собрать при форензике.
  • Не требуется регистрация в PEB. Стандартная загрузка DLL оставляет след в списке загруженных модулей процесса. Reflected подход этого не делает, что усложняет детекцию через перечисление модулей.
  • Обход некоторых мониторов. Многие решения отслеживают вызовы LoadLibrary и аналогичных API. Когда загрузка идёт вручную, этих вызовов просто нет.

Как это работает шаг за шагом

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

  1. Выделение памяти в целевом процессе. Инжектор через VirtualAllocEx резервирует область памяти с правами RWX или сначала RW, потом переключает в RX. Размер подбирается под полный размер загружаемой DLL.
  2. Копирование raw-данных DLL. Содержимое PE-файла целиком записывается в выделенную область через WriteProcessMemory. На этом этапе данные ещё не готовы к выполнению.
  3. Обработка релокаций. DLL обычно компилируется с предполагаемым базовым адресом. Если память выделилась по другому адресу — все абсолютные ссылки нужно поправить. Инжектор проходит таблицу релокаций и корректирует адреса.
  4. Разрешение импорта. DLL почти всегда зависит от других библиотек. Инжектор читает Import Directory, находит нужные функции через экспорты системных DLL и записывает реальные адреса в IAT.
  5. Настройка прав доступа. Область памяти переводится в Execute-режим. Это критичный момент — именно здесь многие современные EDR могут задетектить подозрительную область RWX или смену прав.
  6. Вызов точки входа. Инжектор создаёт поток в целевом процессе с адресом входа DLL. На этом этапе вредоносный код начинает выполняться уже внутри легитимного процесса.

Что происходит с точки зрения целевого процесса

Целевой процесс не подозревает о подмене. Он продолжает работать как обычно, а внутри него теперь крутится чужой код. Внешне это может выглядеть как:

  • Неожиданное сетевое соединение от имени доверенного процесса
  • Изменение поведения приложения без видимых причин
  • Утечка памяти или рост потребления ресурсов
  • Вызовы API, нетипичные для данного процесса

При этом стандартные инструменты вроде диспетчера задач или даже Process Explorer не покажут подозрительную DLL в списке модулей — её там просто нет.

Как обнаружить reflected DLL injection

Обнаружение — это всегда игра в кошки-мышки. Но есть конкретные признаки, на которые стоит обращать внимание:

  • Области памяти RWX или память с EXECUTE правами, не привязанная к известному модулю. Это красный флаг. Нормальные приложения редко нуждаются в исполняемой памяти вне загруженных DLL.
  • Несоответствие между потоками и модулями. Если поток выполняется по адресу, который не принадлежит ни одной загруженной DLL — это подозрительно.
  • Аномальные вызовы API из «неправильного» контекста. Например, браузер вдруг начинает вызывать функции шифрования или обращаться к разделам реестра, которые ему не нужны.
  • Артефакты в памяти. При дампе памяти можно найти структуры, характерные для ручной загрузки PE-файла — необработанные данные рядом с исполняемым кодом.

Сравнение с другими техниками инъекции

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

Техника Файл на диске Видимость в списке модулей Сложность реализации Основной риск детекта
LoadLibrary (классическая) Да Да Низкая Файл на диске, запись в PEB
Reflected DLL injection Нет Нет Высокая RWX-память, аномальные потоки
Process hollowing Частично Замена образа Средняя Несовпадение образа на диске и в памяти
Thread execution hijacking Нет Нет Средняя Подозрительный поток в чужом процессе
APC injection Нет Нет Средняя Очереди APC, нестандартные вызовы

Что делать, если вы столкнулись с подозрением на инъекцию

Здесь важно действовать методично, а не паниковать. Вот реальная последовательность действий:

  1. Не убивайте процесс сразу. Если это рабочая система, резкое завершение может привести к потере данных. Сначала соберите информацию.
  2. Сделайте дамп памяти подозрительного процесса. Для этого подойдёт Process Explorer, Task Manager (в Windows 10+) или WinDbg. Дамп нужен для последующего анализа.
  3. Проверьте области памяти. Используйте WinDbg с командой !address -f:MEM_EXECUTE или аналогичные инструменты. Ищите RWX-области без привязки к модулю.
  4. Проанализируйте потоки. Посмотрите, откуда начинается каждый поток. Если адрес старта не попадает в диапазон известных DLL — это кандидат на проверку.
  5. Проверьте сетевую активность. Даже если инъекция обнаружена постфактум, важно понять, какие данные могли утечь и куда были отправлены запросы.

Частые ошибки при анализе

Когда люди впервые сталкиваются с reflected injection, они регулярно наступают на одни и те же грабли:

  • Ожидают увидеть DLL в списке модулей. Это принципиальная особенность техники — модуля там нет. Если вы ищете только через списки модулей, вы ничего не найдёте.
  • Полагаются только на антивирус. Сигнатурные методы против reflected injection работают плохо. Нужен поведенческий анализ и мониторинг на уровне памяти.
  • Игнорируют RWX-области как норму. «У меня в процессе есть RWX — это нормально». Возможно. Но каждую такую область стоит проверить. В современных приложениях количество RWX-областей обычно предсказуемо.
  • Не проверяют потоки. Иногда инжектор создаёт новый поток, иногда перехватывает существующий. Анализ только модулей без анализа потоков — неполная картина.
  • Путают с легитимным кодом. Некоторые приложения (особенно с плагинными системами или JIT-компиляторами) сами создают исполняемую память в рантайме. Важно понимать контекст и базовое поведение конкретного приложения.

Практические рекомендации по защите

Полностью исключить reflected injection невозможно — если злоумышленник получил код на машине, он может обойти практически любую защиту. Но можно сильно усложнить жизнь атакующему:

  • Включите и настройте EDR с поведенческим анализом. Современные решения умеют детектить аномальные выделения памяти и создание потоков в чужих процессах.
  • Мониторьте выделение RWX-памяти. Это один из самых надёжных индикаторов. Настройте алерты на VirtualAllocEx с PAGE_EXECUTE_READWRITE.
  • Контролируйте межпроцессное взаимодействие. Вызовы вроде WriteProcessMemory, CreateRemoteThread, NtMapViewOfSection между несвязанными процессами — повод для проверки.
  • Используйте принцип минимальных привилегий. Многие техники инъекции требуют прав на запись в память другого процесса. Ограничение прав снижает поверхность атаки.
  • Регулярно обновляйте ПО. Reflected injection часто используется не сам по себе, а как этап после получения начального доступа через уязвимость.

Как выбрать подход в зависимости от вашей ситуации

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

Если вы специалист по реагированию на инциденты: фокусируйтесь на артефактах в памяти, а не на файловой системе. Дампы памяти, леты EDR, аномалии в сетевой активности — ваши основные источники. Не тратьте время на поиск файла DLL — его нет.

Если вы разрабатываете защиту: внедряйте мониторинг на уровне ядра (если это возможно в вашей среде) или используйте ETW/AMSI для получения видимости над ключевыми API. Поведенческие правила на основе последовательности вызовов работают лучше, чем статические проверки.

Итог

Reflected DLL injection — это техника, которая существует не для галочки, а для конкретной цели: загрузить код в чужой процесс без следов на диске и без стандартных механизмов загрузки Windows. Она сложнее в реализации, чем классическая инъекция, но и заметить её труднее.

Главное, что стоит запомнить: если вы видите исполняемый код в памяти процесса, который не привязан к загруженному модулю, — это повод для серьёзного анализа. Не списывайте это на «особенность работы программы». Проверьте — возможно, кто-то внедрил свой код именно через reflected injection.

Для практического старта: если вы ещё не работали с анализом памяти, возьмите чистый процесс, сделайте дамп, посмотрите структуру через WinDbg. Потом найдите любой открытый PoC reflected loader, запустите в изолированной среде и сравните. Разница между «чистым» и «инжектированным» процессом станет очевидной очень быстро.

Оцените статью
PEFile — Безопасность и технологии простым языком