APC注入

Windows中的2种类型的APC:
    用户模式  APC执行在用户模式下的线程的上下文中,必须得到线程的允许才能得到执行
同时用户APC还需要目标进程处在Alertable等待状态才能被成功的调度执行 在内核模式中
可以执行KeWaitForSingleObject.....,在用户模式下可以调用SleepEx..... 当用户APC
投递到线程中 调用上面函数 执行条件满足时去执行APC历程 执行完APC历程 继续执行线程
    内核模式  分为普通内核APC和特殊内核APC 当APC投递到线程上 特殊的内核APC不需要
得到现车允许即可得到执行 普通内核APC需要特定环境才能得到执行 特殊内核APC甚至可以唤醒
阻塞的线程

APC执行优先级  特殊内核APC > 普通内核APC > 用户APC

每个线程都含有2个APC队列  用户模式APC队列 和 内核模式APC队列


APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:
    1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断。
    2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。
    3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的。

  //打开远程进程  
    handle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);  
    if (handle)  
    {  
        //在远程进程申请空间  
        lpData = VirtualAllocEx(handle,  
            NULL,  
            1024,  
            MEM_COMMIT,  
            PAGE_EXECUTE_READWRITE);  
  
        if (lpData)  
        {  
            //在远程进程申请空间中写入待注入DLL的路径  
            bRet = WriteProcessMemory(handle,  
                lpData,  
                (LPVOID)sDllName,  
                1024,&dwRet);  
        }  
        //关闭句柄  
        CloseHandle(handle);  
}  

当我们准备好 用于注入DLL的LoadLibrary()函数后,接下来需要使用QueueUserAPC()函数将此函数插入到软中断线程的APC队列中。但是由于 QueueUserAPC()函数的第三个参数是线程ID,因此我们需要根据现有进程ID,并通过遍历对比得到线程ID,具体API如下表所示:
CreateToolhelp32Snapshot  
创建线程快照  
Thread32First  
得到第一个线程快照  
Thread32Next  
循环下一个线程快照  



THREADENTRY32 te = {0};  
    te.dwSize = sizeof(THREADENTRY32);  
    //得到线程快照  
    HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);  
    if (INVALID_HANDLE_VALUE == handleSnap)  
    {  
        return FALSE;  
    }  
  
    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  
                    dwRet = QueueUserAPC(  
                        (PAPCFUNC)LoadLibrary,  
                        handleThread,  
                        (ULONG_PTR)lpData);  
                    if (dwRet > 0)  
                    {  
                        bStat = TRUE;  
                    }  
                    //关闭句柄  
                    CloseHandle(handleThread);  
                }  
            }  
            //循环下一个线程  
        } while (Thread32Next(handleSnap,&te));  
    }  
CloseHandle(handleSnap);  
原文地址:https://www.cnblogs.com/yifi/p/6527752.html