Skip to content
λmaldev wiki/
pagesAPC Injection
T1055.004Windowsx64 / x86C / C++

APC Injection

updated 2026-05-195 min readthehackersbrain
Authorized use only. This material is published for detection engineering, malware analysis and authorized red-team engagements. Running these techniques against systems you do not own or have written permission to test is illegal.

Overview

Asynchronous Procedure Calls are a legitimate Windows mechanism for running a function in the context of a specific thread. A user-mode APC only fires when its target thread enters an alertable wait, so this technique trades reliability for quiet: no thread is created, no context is rewritten, and the payload runs on a thread that was always going to run.

The “early bird” variant sidesteps the reliability problem entirely by queueing the APC onto the primary thread of a process created with CREATE_SUSPENDED — that thread is guaranteed to drain its APC queue during ResumeThread, before any EDR DLL has finished initialising.

The call chain

  1. 1
    VirtualAllocEx + WriteProcessMemory
    Stage the payload in the target address space.
  2. 2
    NtQuerySystemInformation
    Enumerate threads to find one sitting in an alertable wait.
  3. 3
    QueueUserAPC
    Attach the payload address to that thread's APC queue.
  4. 4
    (thread enters alertable wait)
    The APC fires the next time the thread calls SleepEx, WaitForSingleObjectEx or similar.

Reference implementation

apc.cC
PVOID mem = VirtualAllocEx(hProc, NULL, size, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProc, mem, shellcode, size, NULL);

DWORD old;
VirtualProtectEx(hProc, mem, size, PAGE_EXECUTE_READ, &old);

// early bird: hThread is the primary thread of a CREATE_SUSPENDED process
QueueUserAPC((PAPCFUNC)mem, hThread, 0);
ResumeThread(hThread);   // the queue drains before the process fully initialises

Detection

SYSMON EID 10
ProcessAccess with THREAD_SET_CONTEXT rights immediately before a queue operation.
ETW-TI
KERNEL_THREATINT_TASK_QUEUEUSERAPC events targeting a thread in another process.
MEMORY SCAN
Private RX memory in a process whose threads all belong to signed modules.
BEHAVIOURAL
Early-bird variants queue the APC into a process created suspended — pair the two events.

ETW-TI is the only continuous source that sees the queue operation itself. Without it, you are left correlating the handle request with the memory artifact the payload leaves behind.

Was this page useful?edit this page ↗