Introduction
If you read a threat report written around 2018, you might be tempted to write off APC injection as a solved problem. The technique was old, a textbook trick, once which most EDRs had learned to flag. By 2023, academic researchers were calling out its “near disappearance” from commodity malware. So why are we writing about it in 2026?
Well, this is because the problem refused to go away and simply mutated, much like a real life virus, it developed two new variants: Early Bird APC and Special User APC and even more like real life viruses, these variants are stealthier. Now both variants have begun showing up in nation-state actor toolkits and fresh new loaders made after 2024.
Process injection sits at the top of the MITRE ATT&CK heap for the second year running. Picus Labs’ Red Report 2025 found T1055 in roughly 31% of the million-plus malware samples they examined.
Recap
An Asynchronous Procedure Call (APC) is a Windows kernel mechanism that allows a function to execute asynchronously within the context of a specific thread. Every thread maintains its own APC queue, and when a thread enters an alertable wait state (by calling functions like SleepEx or WaitForSingleObjectEx with the alertable flag set), Windows drains that queue and executes whatever routines are waiting in it.
Attackers soon realized that hijacking threads was silent compared to CreateRemoteThread and had a lesser chance of getting caught in detections. Hence APC injection was formed as a technique, they'd find a process with a thread in an alertable wait and get a handle to it, call VirtualAllocEx and WriteProcessMemory to plant shellcode and then call QueueUserAPC pointed at the shellcode, the thread would eventually wake up and execute the shellcode. Defenders took time to catch onto these developments and eventually there was sufficient attention towards APC Injection.
What makes APC injection a 2026 problem?
Well, 2 developments and 1 pivot from the attackers.
Development 1: The rise of Special User APCs
The Windows kernel has long allowed a user-mode APC to fire only when a target thread sits in an alertable wait, defenders, quite rightfully, built around that assumption: if a thread wasn’t alertable, your APC wouldn’t run. Then NtQueueApcThreadEx2 arrived (the API was technically present from RS5, but undocumented for years), and with the QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC flag set, the kernel forces the APC to fire whether the target is alertable or not. It does this by piggybacking on a kernel APC; and all of a sudden the detection watching SleepEx no longer is sufficient.