游戏安全实验室 首页 技术入门 查看内容

 阅读目录

插APC注入

发布于:2016-6-21 19:12   |    169024次阅读 作者: 管理员    |   原作者: TP   |   来自: 原创

一、概述

APC是异步过程调用,系统创建线程的时候为线程创建一个APC队列,线程调用SleepExWaitSingleObjectEx函数时,把线程状态被设置为可提醒状态时,线程并不会睡眠而是检查APC队列是否为空如果不为空,转去执行APC队列中的每一项因此给目标进程中的线程插入APC,就可以实现进程注入。

二、用到的Windows API函数

函数QueueUserAPC可以插入APC到目标进程的线程,其原型如下:

DWORD WINAPI QueueUserAPC(

   _In_ PAPCFUNC  pfnAPC,//APC回调函数的指针

   _In_ HANDLE    hThread,//目标线程的句柄

   _In_ ULONG_PTR dwData//传递给回调函数的参数

)

根据前一小结可知,可以调用API读写目标进程,本次APC注入需要线程句柄,进程句柄可以通过OpenProcess来获得,那么同理,线程句柄可以通过函数OpenThread获得,函数原型如下:

HANDLE WINAPI OpenThread(

  _In_ DWORD dwDesiredAccess,//打开权限

   _In_ BOOL  bInheritHandle,//子进程是否继承该句柄

   _In_ DWORD dwThreadId//线程ID

)

其中线程ID的获取,可以通过枚举线程来完成。用的API如下:

HANDLE WINAPI CreateToolhelp32Snapshot(

   _In_ DWORD dwFlags,//snapshot包涵的内容

   _In_ DWORD th32ProcessID//进程ID

)用来创建一个枚举线程的快照然后调用函数Thread32First和Thread32Next循环枚举线程。原型如下:

BOOL WINAPI Thread32First(

   _In_    HANDLE          hSnapshot,//快照句柄

   _Inout_ LPTHREADENTRY32 lpte//保存相关信息结构

)

BOOL WINAPI Thread32Next(

   _In_  HANDLE          hSnapshot,

   _Out_ LPTHREADENTRY32 lpte

)

三、代码实现

第一步,打开目标进程获得句柄,第二步枚举目标进程里面的线程得到线程ID,第三步打开线程得到线程句柄,第四,调用QueueUserAPC函数向枚举到的每一个线程插入APC。工程代码见附件代码所示。关键代码如下所示。

void InjectByAPC(DWORD dwPid, char* pDllName)

{

    THREADENTRY32 te = { 0 };

    te.dwSize = sizeof(THREADENTRY32);

    HANDLE hSnap = INVALID_HANDLE_VALUE;

    HANDLE hProc = NULL;

    BYTE* pbyDllNameBuf = NULL;

 

    do

    {

        hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);//第一步打开进程获得句柄

        if (NULL == hProc)

        {

            printf("[InjectByAPC]OpenProcess Fails\n");

            break;

        }

 

        DWORD dwDllNameStrLen = strlen(pDllName) + 2;

        pbyDllNameBuf = (BYTE*)VirtualAllocEx(hProc, NULL, dwDllNameStrLen, MEM_COMMIT, PAGE_READWRITE);

        if (!pbyDllNameBuf)

        {

            printf("[InjectByAPC]VirtualAllocEx Fails\n");

            CloseHandle(hProc);

            break;

        }

 

        if (!WriteProcessMemory(hProc, pbyDllNameBuf, pDllName, dwDllNameStrLen, NULL))

        {

            printf("[InjectByAPC]WriteProcessMemory Fails\n");

            VirtualFreeEx(hProc, (PVOID)pbyDllNameBuf, 0, MEM_RELEASE);

            break;

        }

/*第二步枚举进程里面的线程,得到线程ID*/

        hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

        if (INVALID_HANDLE_VALUE == hSnap)

        {

            printf("[InjectByAPC]CreateToolHelp32Snapshot fails\n");

            break;

        }

 

        if (Thread32First(hSnap, &te))

        {

            do

            {

                if (dwPid == te.th32OwnerProcessID)

                {

                    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);//第三步获得线程句柄

                    if (hThread)

                    {

                        DWORD dwRet = QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)pbyDllNameBuf);//第四步,插入APC

                        printf("dwRet:%d\n", dwRet);

                        if (0 == dwRet)

                        {

                            printf("[InjectByAPC]QueneUserAPC Fails\n");

                        }

                        if (dwRet)

                        {

                            CloseHandle(hThread);

                        }

                    }

                }

            } while (Thread32Next(hSnap, &te));

        }

    } while (0);

 

    CloseHandle(hProc);

}

 

 

Demo程序的执行结果如图下图所示。

 

四、习题

    参试修改Demo代码,不需要手动输入进程ID,直接输入进程名就可以对其进行注入(提示:枚举系统进程)

*转载请注明来自游戏安全实验室(GSLAB.QQ.COM)

分享到:
踩0 赞1

收藏

上一篇:基于文件修改的注入方式

下一篇:挂起进程注入

最新评论
B Color Image Link Quote Code Smilies

发表评论