APC Injection
Last updated
Last updated
What is APC?
Asynchronous Procedure Calls are a Windows operating system mechanism that enables programs to execute tasks asynchronously while continuing to run other tasks. APCs are implemented as kernel-mode routines that are executed in the context of a specific thread. Malware can leverage APCs to queue a payload and then have it execute when scheduled.
Alertable State
Not all threads can run a queued APC function, only threads in an alertable state can do so. An alertable state thread is a thread that is in a wait state. When a thread enters an alertable state it is placed in a queue of alertable threads, allowing it to run queued APC functions.
To queue an APC function to a thread, the address of the APC function must be passed to the WinAPI. According to Microsoft's documentation:
An application queues an APC to a thread by calling the QueueUserAPC function. The calling thread specifies the address of an APC function in the call to QueueUserAPC.
The injected payload's address will be passed to QueueUserAPC
in order to have it executed. Before doing so, a thread in the local process must be placed in an alertable state.
QueueUserAPC
is shown below and it accepts 3 arguments:
pfnAPC
- The address of the APC function to be called.
hThread
- A handle to an alertable thread or suspended thread.
dwData
- If the APC function requires parameters, they can be passed here. This value will be NULL
in this module's code.
The thread that will be executing the queued function needs to be in an alertable state. This can be done by creating a thread and using one of the following WinAPIs:
These functions are used for synchronizing threads and improving performance and responsiveness in applications, however in this case, passing a handle to a dummy event is sufficient. Passing the correct parameters to these functions is not necessary since simply using one of the functions is enough to place the thread in an alertable state.
Using The Functions
Any of the following functions can be used as a sacrificial alertable thread to run the queued APC payload. See below for examples of how to use the functions to place the current thread in an alertable state.
Using SleepEx
Using WaitForSingleObjectEx
Using WaitForMultipleObjectsEx
Using MsgWaitForMultipleObjectsEx
Using SignalObjectAndWait
QueueUserAPC
can also succeed if the target thread is created in a suspended state. If this method is used to execute the payload, QueueUserAPC
should be called first and then the suspended thread should be resumed next. Again, the thread must be created in a suspended state, suspending an existing thread will not work.
The code shared in this module demonstrates APC injection via an alertable and suspended thread.
To summarize, the implementation logic will be as follows:
First, create a thread that runs one of the previously mentioned functions to place it in an alertable state.
Inject the payload into memory.
The thread handle and payload base address will be passed as input parameters to QueueUserAPC
.
RunViaApcInjection
is a function that performs APC Injection and requires 3 arguments:
hThread
- A handle to an alertable or suspended thread.
pPayload
- A pointer to the payload's base address.
sPayloadSize
- The size of the payload.
To create a dummy event, the WinAPI will be used. The newly created event object is a synchronization object that allows threads to communicate with each other by signaling and waiting for events. Since the output of CreateEvent
is irrelevant, any valid event can be passed to the previously shown WinAPIs.