新建MFC工程,添加按钮控件,双击写代码如下所示:
void CMfcTextApcInjectDlg::OnBnClickedSleepex() { // TODO: 在此添加控件通知处理程序代码 SleepEx(5000,TRUE); }这里我们需要注意一下SleepEx中第二个参数为TRUE,查下msdn,上面写到:
大概意思是说当第二个参数为FALSE,APC是不被执行的,从此可以认为APC注入的使用条件还是有很大约束的。
.编写APC注入程序
由于我们需要时使用LoadLibrary()函数完成注入,因此需要为其先准备好必要的参数,需要我们可以通过在远程进程中申请空间的方式写入LoadLibrary()函数所需要的参数(也就是DLL的路径)。关键代码如下所示:
//打开远程进程 handle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId); if (handle) { //在远程进程申请空间 lpData = VirtualAllocEx(handle, NULL, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (lpData) { //在远程进程申请空间中写入待注入DLL的路径 bRet = WriteProcessMemory(handle, lpData, (LPVOID)sDllName, 1024,&dwRet); } //关闭句柄 CloseHandle(handle); }
CreateToolhelp32Snapshot | 创建线程快照 |
Thread32First | 得到第一个线程快照 |
Thread32Next | 循环下一个线程快照 |
THREADENTRY32 te = {0}; te.dwSize = 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 dwRet = QueueUserAPC( (PAPCFUNC)LoadLibrary, handleThread, (ULONG_PTR)lpData); if (dwRet > 0) { bStat = TRUE; } //关闭句柄 CloseHandle(handleThread); } } //循环下一个线程 } while (Thread32Next(handleSnap,&te)); } CloseHandle(handleSnap);
int CApcInjectDll::EnablePrivilege(bool isStart) { //1. 得到令牌句柄 HANDLE hToken = NULL; //令牌句柄 if (!::OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken)) { return FALSE; } //2. 得到特权值 LUID luid = {0}; //特权值 if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { return FALSE; } //3. 提升令牌句柄权限 TOKEN_PRIVILEGES tp = {0}; //令牌新权限 tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = isStart ? SE_PRIVILEGE_ENABLED : 0; if (!::AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) { return FALSE; } //4. 关闭令牌句柄 ::CloseHandle(hToken); return 0; }
APC注入因为受目标进程使用API的条件而受限,并且处于等待的线程被注入后会立即返回,也有可能造成线程的运行错误,所以应用起来不是很通用。