APC Queue Injection
In this article, I will address process injection, focusing on Asynchronous Procedure Calls (APC) with evasion techniques and some important OPSEC warnings for your upcoming engagements in Red Team.
About APC
Firstly, Asynchronous Procedure Calls
(APC) are a mechanism in the Windows operating system that allows programs to perform tasks asynchronously while continuing to execute other tasks. APCs are implemented as kernel-mode routines executed in the context of a specific thread.
Process Injection - Shellcode Injection x Mapping Injection
One of the major advantages of using APCs is that we do not need to rely on highly suspicious WINAPIs like CreateRemoteThread. Two uses of it and their differences in process injection: Shellcode Injection = VirtualAllocEx + WriteProcessMemory — This way, it will allocate private memory in a remote process. A key observation regarding this process injection is that a Cleanup RWX
can be performed to clear the memory protection and avoid leaving it as RWX
. Simply allocate memory with PAGE_READWRITE
, copy the payload into the memory, change it to PAGE_EXECUTE_READ
, and create the thread. The biggest issue is here, with the CreateRemoteThread for create thread. Mapping Injection = CreateFileMapping + MapViewOfFile — It has an advantage over Shellcode Injection because it uses mapped memory with CreateFileMapping, which in itself is less targeted by malware. VirtualAllocEx uses private memory, which is already highly targeted by defense solutions. However, its memory protection poses an issue as it cannot be changed, so we are forced to use RWX
.
Disadvantage of CreateRemoteThread
Both require the use of CreateRemoteThread, and therein lies the problem. Even if you employ techniques for evading EDR hooking such as NTLL Unhooking
or Indirect Syscalls
, it will not be sufficient for you to stay undetected. The issue is that these functions can still be detected through process and thread monitoring, event logs, and a myriad of other methods.
Payload Execution - APC Injection
The APC (Asynchronous Procedure Call) injection method for payload execution utilizes QueueUserAPC, differing from previous techniques. Its evasive nature stems from not being detected by methods capable of identifying the CreateRemoteThread. This is because there is no way to query APC Queue or have any way of visualizing them. However, despite its advantages, there is a drawback to APC Injection. In order for QueueUserAPC to work and queue the payload into the thread, it requires a thread that is alertable or suspended. This can be a bit of a challenge, due to the fact that there is no way to check which threads are in an alert state and which are not, but I’ll now demonstrate some ways to put this technique into practice.
Two Ways to use APC Queue
The FIRST WAY
is by using Early Bird APC Injection, the implementation will be as follows:
- We create a process with the flags
EXTENDED_STARTUPINFO_PRESENT
andDEBUG_PROCESS
with CreateProcess. - We will use
Spoofing PPID
to start the process in a specific parent process. - Memory allocation in a remote process with VirtualAllocEx and writing to this memory with WriteProcessMemory.
- We will enqueue the payload with QueueUserAPC and stop the debugging of the remote process using DebugActiveProcessStop, resuming its threads and executing the payload.
Now let’s move on to the explanation. The EXTENDED_STARTUPINFO_PRESENT
flag is used to give us more privileges over the created process, which is useful for the Spoofing PPID
we will be performing. DEBUG_PROCESS is an alternative to CREATE_SUSPENDED
, and it will make the remote process be debugged by our process, placing a breakpoint at its entrypoint.
About Spoofing PPID
, with the EXTENDED_STARTUPINFO_PRESENT
flag set during the process creation, we will access the lpAttributeList
member within the STARTUPINFOEXA structure, updating it with UpdateProcThreadAttribute to set the attributes defining the PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
flag, thus allowing us to specify the parent process of the thread. It can also be used Process Argument Spoofing depending on how you are going to do it. This part is quite simple: we will allocate memory in the remote process created with PAGE_READWRITE
permission and write the payload with WriteProcessMemory. Then, we will change the protection again, but this time to PAGE_EXECUTE_READ
. Remember the “Cleanup RWX” I mentioned earlier; memories with RWX permissions can attract attention. Finally, we will enqueue the payload with QueueUserAPC, passing to it the thread identifier and the address of the payload previously allocated with VirtualAllocEx. Then, we stop the debug with DebugActiveProcessStop, and voilà, the payload is executed. 😁
The SECOND WAY
is to pay to see and try to use the APC in all threads of a process. Something interesting is that browsers in general will almost certainly work, the problem is, we may end up receiving several connections in our C2 because it may happen that several threads are in an alert state. One solution for this is Execution Control, basically it’s about using Mutexes
, Semaphores
, Events
and others. Another solution is configuring the infrastructure of your C2, something we will not discuss at this moment. The implementation will be as follows:
Use OpenProcess in target process, VirtualAllocEx to allocate memory in the remote process with RW permissions, write to the allocated memory with WriteProcessMemory with your payload, and change the permissions to
RX
with VirtualProtectEx.Perform a thread enumeration using CreateToolhelp32Snapshotor NtQuerySystemInformation, whichever you prefer, and then capture the identifier for the desired process and then retrieve the identifiers of the threads.
Utilize QueueUserAPC to enqueue your payload.
Conclusion
The advantages, disadvantages, and methods of executing an evasive APC injection were explained. A reader with a certain level of programming and Windows knowledge will be able to apply the techniques properly explained without much difficulty, even though it is a theoretical article. However, I leave here an example of a repository on my GitHub called Early_Bird_Injection with first implementation.
Certainly, this raw technique as it stands may still be detected by some solutions through API Hooking. There are other functionalities to add, such as anti-analysis mechanisms and bypassing API Hooking
, for example, NTDLL Unhooking
and Syscalls
. These will be two topics for future articles in this journal. Any questions or suggestions, feel free to contact me. Until the next article! 🙃