目录
使用APC进行dll注入

异步过程调用是一种能在特定线程环境中异步执行的系统机制。往线程APC队列添加APC,系统会产生一个软中断。在线程下一次被调度的时候,就会执行APC函数,APC有两种形式,由系统产生的APC称为内核模式APC,由应用程序产生的APC被称为用户模式APC。每个线程都拥有自己的APC队列。应用程序可以使用函数把APC添加到指定线程的APC队列,函数定义如下:

1
DWORD WINAPI QueueUserAPC(
2
    _In_ PAPCFUNC pfnAPC, //APC函数地址
3
    _In_ HANDLE hThread, //目标线程
4
    _In_ ULONG_PTR dwData //APC函数的参数
5
    );

当用户模式APC被添加后,线程并不会直接调用APC函数,只有当线程处于“可变等待状态”时才会调用。如果希望线程执行APC函数,就要让线程进入可变等待状态。当线程调用SleepEx、SignalObjectAndWait、MsgWaitForMultipleObjectEx、WaitForMultipleObjectsEx或WaitForSingleObjectEx时就会进入可变等待状态。 ReadFileEx、WriteFileEx、和SetWaitableTimer等都是使用APC作为完成例程的回调机制。

原理:使用QueueUserAPC向目标进程的线程添加APC函数,而这个APC函数能够实现模块的加载功能。要使用这种方法的前提是目标进程能够进入可变等待状态,否则即便添加了APC也没有执行的机会
步骤:

1.向目标进程写入待注入的模块名称
2.枚举目标进程所有线程。(由于并不是每个线程都有机会进入可变等待状态,为了增加APC的机会,向目标进程的每个线程都添加APC是个比较保险的做法)
3.增加APC,把LoadLibrary作为APCProc,把第一步中DLL路径名称所在地址作为其参数

1
int InjectDllWithApc(WCHAR* DllFullPath, ULONG ProcessId)
2
{
3
	HANDLE hTatgetProcessHandle;
4
	hTatgetProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
5
	if (hTatgetProcessHandle == NULL)
6
	{
7
		printf("Failed To Open Process!!\n");
8
		return 0;
9
	}
10
	ULONG32 ulDllLength = (ULONG32)_tcslen(DllFullPath) + 1;
11
	//申请内存  
12
	WCHAR* pRemoteAddress = (WCHAR*)VirtualAllocEx(hTatgetProcessHandle, NULL, ulDllLength * sizeof(WCHAR),
13
		MEM_COMMIT, PAGE_READWRITE);
14
	if (pRemoteAddress == NULL)
15
	{
16
		printf("Alloc Virtual Address Failed!\n");
17
		CloseHandle(hTatgetProcessHandle);
18
		return 0;
19
	}
20
	//DLL写入 
21
	if (WriteProcessMemory(hTatgetProcessHandle, pRemoteAddress, (LPVOID)DllFullPath, ulDllLength * sizeof(WCHAR), NULL) == FALSE)
22
	{
23
		VirtualFreeEx(hTatgetProcessHandle, pRemoteAddress, ulDllLength, MEM_DECOMMIT);
24
		CloseHandle(hTatgetProcessHandle);
25
		return 0;
26
	}
27
	THREADENTRY32 ThreadEntry32 = { 0 };
28
	HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
29
	ThreadEntry32.dwSize = sizeof(THREADENTRY32);
30
	HANDLE hThreadHandle;
31
	BOOL bStatus;
32
	DWORD dwReturn;
33
	//创建快照
34
	hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
35
	if (hThreadSnap == INVALID_HANDLE_VALUE)
36
	{
37
		return 0;
38
	}
39
	if (!Thread32First(hThreadSnap, &ThreadEntry32))
40
	{
41
		CloseHandle(hThreadSnap);
42
		return 1;
43
	}
44
	do
45
	{
46
		//遍历线程  
47
		if (ThreadEntry32.th32OwnerProcessID == ProcessId)
48
		{
49
			printf("TID:%d\n", ThreadEntry32.th32ThreadID);
50
			hThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadEntry32.th32ThreadID);
51
			if (hThreadHandle)
52
			{
53
				//向线程插入APC  
54
				dwReturn = QueueUserAPC(
55
					(PAPCFUNC)LoadLibrary,
56
					hThreadHandle,
57
					(ULONG_PTR)pRemoteAddress);
58
				if (dwReturn > 0)
59
				{
60
					bStatus = TRUE;
61
				}
62
				//关闭句柄  
63
				CloseHandle(hThreadHandle);
64
			}
65
		}
66
	} while (Thread32Next(hThreadSnap, &ThreadEntry32));
67
	VirtualFreeEx(hTatgetProcessHandle, pRemoteAddress, ulDllLength, MEM_DECOMMIT);
68
	CloseHandle(hThreadSnap);
69
	CloseHandle(hTatgetProcessHandle);
70
	return 0;
71
}
文章作者: yaoyue
文章链接: https://yaoyue123.github.io/2021/01/25/Windows-APC-dllinject/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 yaoyue的博客

评论