APC注入
APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:
1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断(或者是Messagebox弹窗的时候不点OK的时候也能注入)。
2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。
3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的。
核心函数:
局限:
这种注入方式局限性很明显,一是必须要等待时机,而是当注入成功后,SleepEx或者其他等待函数直接就会跳过当前等待继续往下走,这样可能造成被注入程序的不稳定行,经常导致被注入程序崩溃。
代码:
// LoadExeWin32.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <string>
#include <windows.h>
#include <shlwapi.h>
#include <tlhelp32.h>
#include <winternl.h>
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib,"ntdll.lib")
using namespace std;
//根据进程名字获取pid
DWORD GetPidFromName(wstring wsProcessName) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE){
return FALSE;
}
PROCESSENTRY32W pe = {sizeof(pe)};
BOOL bOk;
for (bOk = Process32FirstW(hSnapshot, &pe); bOk; bOk = Process32NextW(hSnapshot, &pe)){
wstring wsNowProcName = pe.szExeFile;
if(StrStrI(wsNowProcName.c_str() ,wsProcessName.c_str())!= NULL){
CloseHandle(hSnapshot);
return pe.th32ProcessID;
}
}
CloseHandle(hSnapshot);
return 0;
}
//把wcCacheInDllPath DLL文件注入进程wsProcessName
BOOL Injection_APC(const wstring &wsProcessName ,const WCHAR wcCacheInDllPath[]){
//初始化
DWORD dwProcessId = GetPidFromName(wsProcessName);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);
if (!hProcess){
return FALSE;
}
PVOID lpData = VirtualAllocEx(hProcess,
NULL,
1024,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
DWORD dwRet;
if (lpData) {
//在远程进程申请空间中写入待注入DLL的路径
WriteProcessMemory(hProcess,
lpData,
(LPVOID)wcCacheInDllPath,
MAX_PATH,&dwRet);
}
CloseHandle(hProcess);
//开始注入
THREADENTRY32 te = {sizeof(THREADENTRY32)};
//得到线程快照
HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD ,0);
if (INVALID_HANDLE_VALUE == handleSnap) {
return FALSE;
}
BOOL bStat = FALSE;
//得到第一个线程
if (Thread32First(handleSnap,&te)){
do { //进行进程ID对比
if (te.th32OwnerProcessID == dwProcessId) {
//得到线程句柄
HANDLE handleThread = OpenThread(THREAD_ALL_ACCESS ,FALSE ,te.th32ThreadID);
if (handleThread) { //向线程插入APC
DWORD dwRet = QueueUserAPC(
(PAPCFUNC)LoadLibraryW,
handleThread,
(ULONG_PTR)lpData);
if (dwRet > 0) {
bStat = TRUE;
}
//关闭句柄
CloseHandle(handleThread);
}
}
//循环下一个线程
} while (Thread32Next(handleSnap,&te));
}
CloseHandle(handleSnap);
return bStat;
}
//Adds a user-mode asynchronous procedure call (APC)
int main(int argc, char* argv[]){
//Sleep(1000*100);
Injection_APC(L"Sleep3M.exe" ,L"M.dll");
return 0;
}
然后写一个测试DLL:
然后再写一个被注入程序:
测试结果:
注入自己的程序成功:
随便尝试了下注入QQ.exe,直接崩溃退出了。