原理:
往线程APC队列添加APC,系统会产生一个软中断。在线程下一次被调度的时候,就会执行APC函数,APC有两种形式,由系统产生的APC称为内核模式APC,由应用程序产生的APC被称为用户模式APC。
每个线程都拥有自己的APC队列。应用程序可以使用函数把APC添加到指定线程的APC队列,函数定义如下:
DWORD WINAPI QueueUserAPC( __in PAPCFUNC pfnAPC,//APC函数地址 __in HANDLE hThread, __in ULONG_PTR dwData//APC函数的参数 );
VOID CALLBACK APCProc( [in] ULONG_PTR dwParam );当用户模式APC被添加后,线程并不会直接调用APC函数,只有当线程处于“唤醒”时才会调用,线程调用SleepEx、SignalObjectAndWait、MsgWaitForMultipleObjectsEx、WaitForMultipleObjectsEx、WaitForSingleObjectEx这些函数的时候会进入可唤醒状态,为了增加机会,应向所有线程加入APC
BOOL InjectModuleToProcessById(DWORD dwProcessId, PCHAR pszDllPath, DWORD dwSize) { DWORD dwRet = 0 ; BOOL bStatus = FALSE ; LPVOID lpData = NULL ; UINT uLen = strlen(pszDllPath) + 1; // 打开目标进程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId) ; if (hProcess) { // 分配空间 lpData = VirtualAllocEx(hProcess, NULL, uLen, MEM_COMMIT, PAGE_READWRITE); DWORD dwErr = GetLastError(); if (lpData) { // 写入需要注入的模块路径全名 bStatus = WriteProcessMemory(hProcess, lpData, pszDllPath, uLen, &dwRet) ; } CloseHandle(hProcess) ; } if (bStatus == FALSE) return FALSE ; // 创建线程快照 THREADENTRY32 te32 = {sizeof(THREADENTRY32)} ; HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0) ; if (hThreadSnap == INVALID_HANDLE_VALUE) return FALSE ; bStatus = FALSE ; // 枚举所有线程 if (Thread32First(hThreadSnap, &te32)) { do{ // 判断是否目标进程中的线程 if (te32.th32OwnerProcessID == dwProcessId) { // 打开线程 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID) ; if (hThread) { // 向指定线程添加APC DWORD dwRet = QueueUserAPC ((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpData) ; if (dwRet > 0) bStatus = TRUE ; CloseHandle (hThread) ; } } }while (Thread32Next ( hThreadSnap, &te32 )) ; } CloseHandle (hThreadSnap) ; return bStatus; }