APC Injection (T1055.004 по MITRE ATT&CK) — техника внедрения кода, при которой произвольная функция ставится в очередь асинхронных вызовов (Asynchronous Procedure Call) чужого потока. Когда поток входит в alertable-состояние, Windows выполняет все накопленные APC-функции в порядке очереди. Ключевая особенность для защитника: вредоносный код выполняется в контексте легитимного процесса без создания нового потока, поэтому классический детект на
Техника популярна у операторов вредоносного ПО именно из-за этой скрытности: она не порождает заметных артефактов на уровне потоков и позволяет выполнять код до инициализации процесса, обходя hooks средств защиты.
Каждый поток в Windows имеет собственную очередь APC — FIFO-структуру, которую ядро обрабатывает при переходе потока в alertable-состояние. Механизм предназначен для легитимных задач: асинхронный ввод-вывод, уведомления о завершении операций, callback-функции драйверов.
Постановка функции в очередь выполняется через
Функция не выполняется немедленно. Она ожидает, пока целевой поток не войдёт в alertable-состояние. Если поток уже находится в таком состоянии, APC выполняется сразу. Если поток приостановлен — выполнение откладывается до возобновления.
Не каждая функция ожидания переводит поток в alertable-состояние. Это определяет, какие потоки могут стать мишенью:
Потоки GUI-приложений часто вызывают
Помимо документированного
Для защитника: если в ETW-трейсе или телеметрии EDR виден вызов
Классическая цепочка APC Injection включает четыре этапа:
Типичный паттерн подготовки памяти: выделение региона с
Атакующий создаёт процесс с флагом
Код выполняется до инициализации процесса, что позволяет обойти hooks, которые EDR или антивирус устанавливает при загрузке образа. Для защитника это означает, что стандартные callback-уведомления о создании процесса могут не зафиксировать вредоносную активность, потому что она происходит до полной инициализации.
Типичные цели:
Вместо
Вариация, использующая глобальную таблицу атомов Windows как канал передачи данных. Вместо
APC Injection не создаёт новый поток, поэтому правила на
API-уровень (ETW, EDR-телеметрия):
Процессы:
Память:
Потоки:
Не каждый cross-process APC — атака. Системные компоненты и некоторые легитимные приложения используют APC для асинхронного ввода-вывода. При настройке правил стоит учитывать:
APC Injection задокументирована в десятках кампаний. По данным MITRE ATT&CK:
Обращает внимание: большинство образцов используют нативные вызовы (
CreateRemoteThread здесь не срабатывает.Техника популярна у операторов вредоносного ПО именно из-за этой скрытности: она не порождает заметных артефактов на уровне потоков и позволяет выполнять код до инициализации процесса, обходя hooks средств защиты.
Как устроена очередь APC
Каждый поток в Windows имеет собственную очередь APC — FIFO-структуру, которую ядро обрабатывает при переходе потока в alertable-состояние. Механизм предназначен для легитимных задач: асинхронный ввод-вывод, уведомления о завершении операций, callback-функции драйверов.
Постановка функции в очередь выполняется через
QueueUserAPC:
C:
DWORD QueueUserAPC(
PAPCFUNC pfnAPC, // указатель на функцию для выполнения
HANDLE hThread, // дескриптор целевого потока
ULONG_PTR dwData // параметр, передаваемый в функцию
);
Функция не выполняется немедленно. Она ожидает, пока целевой поток не войдёт в alertable-состояние. Если поток уже находится в таком состоянии, APC выполняется сразу. Если поток приостановлен — выполнение откладывается до возобновления.
Alertable-состояние: обязательное условие выполнения
Не каждая функция ожидания переводит поток в alertable-состояние. Это определяет, какие потоки могут стать мишенью:
| Функция | Alertable | Условие |
|---|---|---|
SleepEx | Да | bAlertable = TRUE |
WaitForSingleObjectEx | Да | bAlertable = TRUE |
WaitForMultipleObjectsEx | Да | bAlertable = TRUE |
MsgWaitForMultipleObjectsEx | Да | Флаг MWMO_ALERTABLE |
SignalObjectAndWait | Да | bAlertable = TRUE |
Sleep | Нет | Не поддерживает alertable |
WaitForSingleObject | Нет | Нет параметра alertable |
WaitForMultipleObjects | Нет | Нет параметра alertable |
MsgWaitForMultipleObjects | Нет | Нет флага alertable |
Потоки GUI-приложений часто вызывают
MsgWaitForMultipleObjectsEx в цикле обработки сообщений, что делает их удобной мишенью. Потоки системных сервисов, использующие WaitForSingleObjectEx или WaitForMultipleObjectsEx с флагом alertable, также подходят для атаки.Три уровня API для постановки APC
Помимо документированного
QueueUserAPC, существуют нативные системные вызовы, которые делают то же самое, но обходят часть проверок user-mode:QueueUserAPC— WinAPI изkernel32.dll. Внутри вызываетNtQueueApcThread.
NtQueueApcThread— нативный вызов изntdll.dll. Прямой вызов минуяkernel32усложняет детектирование через user-mode hooks.
ZwQueueApcThread— тот же системный вызов через stub вntdll.dllс переходом в режим ядра. С точки зрения ядраNt- иZw-варианты идентичны.
Для защитника: если в ETW-трейсе или телеметрии EDR виден вызов
NtQueueApcThread или ZwQueueApcThread из процесса, не являющегося системным компонентом, это подозрительный сигнал. Большинство реальных образцов вредоносного ПО используют именно нативные вызовы, а не документированный QueueUserAPC.Последовательность атаки
Классическая цепочка APC Injection включает четыре этапа:
- Получение дескриптора целевого потока — через
OpenThreadдля существующего процесса или создание нового.
- Выделение памяти и запись полезной нагрузки —
VirtualAllocEx+WriteProcessMemory(или нативные аналоги) в адресном пространстве цели.
- Постановка APC —
QueueUserAPCили нативный аналог с указанием адреса полезной нагрузки как функции.
- Обеспечение выполнения — если поток приостановлен, вызов
ResumeThread; если поток уже в alertable-состоянии, APC выполнится автоматически.
Типичный паттерн подготовки памяти: выделение региона с
PAGE_READWRITE, копирование payload, затем смена прав на PAGE_EXECUTE_READWRITE через VirtualProtect. Этот переход прав — один из наиболее надёжных индикаторов подготовки shellcode.Early Bird Injection
Атакующий создаёт процесс с флагом
CREATE_SUSPENDED, записывает полезную нагрузку до выполнения точки входа, ставит APC в очередь главного потока и возобновляет его через ResumeThread.Код выполняется до инициализации процесса, что позволяет обойти hooks, которые EDR или антивирус устанавливает при загрузке образа. Для защитника это означает, что стандартные callback-уведомления о создании процесса могут не зафиксировать вредоносную активность, потому что она происходит до полной инициализации.
Типичные цели:
svchost.exe, rundll32.exe, explorer.exe — системные процессы, создание которых не вызывает подозрений у пользователя.Вариант через отладчик
Вместо
CREATE_SUSPENDED процесс создаётся с флагом DEBUG_PROCESS. После записи полезной нагрузки и постановки APC вызывается DebugActiveProcessStop, который прекращает отладку и возобновляет потоки — APC выполняется.DEBUG_PROCESS — легитимный флаг, используемый отладчиками. Однако сочетание создания процесса с этим флагом, последующего DebugActiveProcessStop в коротком временном окне и отсутствия реального отладочного взаимодействия (чтения регистров, установки breakpoints, обработки исключений) — аномалия, которую можно детектировать.AtomBombing
Вариация, использующая глобальную таблицу атомов Windows как канал передачи данных. Вместо
WriteProcessMemory атакующий сохраняет данные в атомную таблицу, а затем ставит APC, который читает и выполняет их. Это обходит детект на WriteProcessMemory — один из наиболее отслеживаемых API-вызовов при расследовании process injection Process Injection в Windows: механизм на уровне концепции и артефакты для детектирования.Признаки для детектирования
APC Injection не создаёт новый поток, поэтому правила на
CreateRemoteThread эту технику не покрывают. Защитнику нужно ориентироваться на комбинацию косвенных признаков.API-уровень (ETW, EDR-телеметрия):
QueueUserAPC,NtQueueApcThreadилиZwQueueApcThreadвызывается из несистемного процесса.
- Вызов направлен на поток в другом процессе (cross-process APC).
- Перед APC наблюдается
VirtualAllocEx+WriteProcessMemory(илиZwWriteVirtualMemory) в том же целевом процессе.
Процессы:
- Процесс создан с
CREATE_SUSPENDEDилиDEBUG_PROCESSи быстро возобновлён.
DebugActiveProcessStopвызывается вскоре послеCreateProcessсDEBUG_PROCESSбез реального отладочного взаимодействия.
- Системный процесс (
svchost.exe,rundll32.exe) создан не системным родителем.
Память:
- Регион с правами
PAGE_EXECUTE_READWRITEв процессе, не ожидающем исполняемый код.
- Переход
PAGE_READWRITE→PAGE_EXECUTE_READWRITEчерезVirtualProtectДетект в памяти Windows: почему in-memory активность оставляет признаки и как их анализируют защитники.
Потоки:
ResumeThreadвызывается сразу после постановки APC.
- Изменение контекста потока в сочетании с APC-вызовом.
Ложные срабатывания и настройка
Не каждый cross-process APC — атака. Системные компоненты и некоторые легитимные приложения используют APC для асинхронного ввода-вывода. При настройке правил стоит учитывать:
svchost.exeиcsrss.exeрегулярно ставят APC собственным потокам — это нормальное поведение.
- Cross-process APC из
csrss.exeв другие процессы — часть штатной работы подсистемы.
- Подозрение вызывает APC из пользовательского процесса в системный, особенно в сочетании с выделением памяти и сменой прав.
Реальные примеры из threat intelligence
APC Injection задокументирована в десятках кампаний. По данным MITRE ATT&CK:
| Вредонос | API | Цель |
|---|---|---|
| Attor | NtQueueApcThread | APC-очередь целевого процесса |
| BADHATCH (FIN8) | APC-очередь | svchost.exe -k netsvcs |
| Bumblebee | APC injection | Выполнение команд C2 |
| Carberp | ZwQueueApcThread | explorer.exe |
| IcedID | ZwQueueApcThread | Удалённые процессы |
| Pillowmint | NtQueueApcThread | svchost.exe |
| Saint Bot | NtQueueApcThread + ZwAlertResumeThread | EhStorAuthn.exe |
| Sardonic | QueueUserAPC | Shellcode |
| TURNEDUP | Early Bird | rundll32.exe |
| XLoader | NtQueueApcThread | APC-очередь |
Обращает внимание: большинство образцов используют нативные вызовы (
NtQueueApcThread, ZwQueueApcThread), а не документированный QueueUserAPC. Saint Bot дополнительно применяет ZwAlertResumeThread — вызов, который одновременно переводит поток в alertable-состояние и возобновляет его, гарантируя выполнение APC без отдельного ResumeThread.Чек-лист защитника
- [ ] Настроить ETW-подписку или EDR-правило на
NtQueueApcThread/ZwQueueApcThread/QueueUserAPCс cross-process контекстом.
- [ ] Отслеживать последовательность
VirtualAllocEx→WriteProcessMemory→QueueUserAPCв рамках одного целевого процесса.
- [ ] Мониторить создание процессов с флагами
CREATE_SUSPENDEDиDEBUG_PROCESS, особенно если цель — системный процесс.
- [ ] Обращать внимание на
DebugActiveProcessStopбез предшествующего отладочного взаимодействия.
- [ ] Контролировать переходы прав памяти
PAGE_READWRITE→PAGE_EXECUTE_READWRITEв процессах, не ожидающих исполняемый код.
- [ ] Проверять родительские процессы:
svchost.exe, созданный неservices.exe, — аномалия.
- [ ] Учитывать, что APC Injection не создаёт новый поток — правила на
CreateRemoteThreadне покрывают эту технику.
- [ ] Исключить из алертов штатные cross-process APC от
csrss.exeи внутренних APC системных сервисов.
Источники
- Цикл статей "Изучение вредоносных программ" | Изучаем технику APC Injection | Osint42.Org - Безопасность и код
- Process Injection: Asynchronous Procedure Call, Sub-technique T1055.004 - Enterprise | MITRE ATT&CK®
- The Linux Kernel documentation — The Linux Kernel documentation
- Welcome to QEMU’s documentation! — QEMU documentation
