zoukankan      html  css  js  c++  java
  • Dll注入:Ring3 层 APC注入

    APC,即Asynchronous procedure call,异步程序调用
    APC注入的原理是:
    在一个进程中,当一个执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断,当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数,利用QueueUserAPC()这个API,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,
     

    注入流程:
    1.根据进程名称得进程ID
    2.枚举该进程中的线程
    3.将自己的函数插入到每个线程的APC队列中

    #include "stdafx.h"
    #include <windows.h>
    #include <Tlhelp32.h>
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    
    using namespace std;
    
    
    
    typedef struct _THREADLIST
    {
         DWORD dwThreadId;
        _THREADLIST *pNext;
    }THREADLIST;
    
    
    int q = 0;
    
    
    DWORD GetProcessID(const char *szProcessName);
    int EnumThreadID(DWORD dwPID, THREADLIST * pdwTidList);
    THREADLIST* InsertThreadId(THREADLIST *pdwTidListHead, DWORD dwTid);
    DWORD Inject(HANDLE hProcess, THREADLIST *pThreadIdList);
    
    int main()
    {
        THREADLIST *pThreadIdHead = NULL;
        pThreadIdHead = (THREADLIST *)malloc(sizeof(THREADLIST));
        if (pThreadIdHead == NULL)
        {
            printf("申请失败");
            return 0;
        }
    
        //ZeroMemory是美国微软公司的软件开发包SDK中的一个宏。 其作用是用0来填充一块内存区域
        ZeroMemory(pThreadIdHead, sizeof(THREADLIST));
    
        DWORD dwProcessID = 0;
    
        if ((dwProcessID = GetProcessID("explorer.exe")) == 0)
        {
            printf("进程ID获取失败!
    ");
            return 0;
        }
    
        EnumThreadID(dwProcessID, pThreadIdHead);
    
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
    
        if (hProcess == NULL)
        {
            printf("打开进程失败");
            return 1;
        }
    
        Inject(hProcess, pThreadIdHead);
        cout<<q;
        getchar();
        getchar();
        return 0;
    }
    
    DWORD GetProcessID(const char *szProcessName)
    {
        //PROCESSENTRY32这个宏在<Tlhelp32.h>中
        PROCESSENTRY32 pe32 = { 0 };
        pe32.dwSize = sizeof(PROCESSENTRY32);
        //创建线程快照
        HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
        if (SnapshotHandle == INVALID_HANDLE_VALUE)
        {
            return 0;
        }
    
        if (!Process32First(SnapshotHandle, &pe32))
        {
            return 0;
        }
    
        do
        {
            if (!_strnicmp(szProcessName, pe32.szExeFile, strlen(szProcessName)))
            {
                printf("%s的PID是:%d
    ", pe32.szExeFile, pe32.th32ProcessID);
                return pe32.th32ProcessID;
            }
            //Process32Next是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后, 我们可以利用Process32Next函数来获得下一个进程的句柄
        } while (Process32Next(SnapshotHandle, &pe32));
    
        return 0;
    }
    
    int EnumThreadID(DWORD dwPID, THREADLIST * pdwTidList)
    {
        int i = 0;
    
        THREADENTRY32 te32 = { 0 };
        te32.dwSize = sizeof(THREADENTRY32);
    
        HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPID);
    
        if (SnapshotHandle != INVALID_HANDLE_VALUE)
        {
            if (Thread32First(SnapshotHandle, &te32))
            {
                do
                {
                    if (te32.th32OwnerProcessID == dwPID)
                    {
                        if (pdwTidList->dwThreadId == 0)
                        {
                            pdwTidList->dwThreadId = te32.th32ThreadID;
                        }
                        else
                        {
                            if (NULL == InsertThreadId(pdwTidList, te32.th32ThreadID))
                            {
                                printf("插入失败!
    ");
                                return 0;
                            }
                        }
    
                    }
                } while (Thread32Next(SnapshotHandle, &te32));
            }
        }
    
        return 0;
    }
    
    THREADLIST* InsertThreadId(THREADLIST *pdwTidListHead, DWORD dwTid)
    {
        THREADLIST *pCurrent = NULL;
        THREADLIST *pNewMember = NULL;
    
        if (pdwTidListHead == NULL)
        {
            return NULL;
        }
        pCurrent = pdwTidListHead;
    
        while (pCurrent != NULL)
        {
    
            if (pCurrent->pNext == NULL)
            {
                // 定位到链表最后一个元素
                pNewMember = (THREADLIST *)malloc(sizeof(THREADLIST));
    
                if (pNewMember != NULL)
                {
                    pNewMember->dwThreadId = dwTid;
                    pNewMember->pNext = NULL;
                    pCurrent->pNext = pNewMember;
                    return pNewMember;
                }
                else
                {
                    return NULL;
                }
            }
            pCurrent = pCurrent->pNext;
        }
    
        return NULL;
    }
    
    DWORD Inject(HANDLE hProcess, THREADLIST *pThreadIdList)
    {
        THREADLIST *pCurrentThreadId = pThreadIdList;
    
        const char szInjectModName[] = "需要加载的自己的动态库路径";
        DWORD dwLen = strlen(szInjectModName) + 1;
    
        PVOID param = VirtualAllocEx(hProcess, 
            NULL, dwLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    
        UINT_PTR LoadLibraryAAddress = (UINT_PTR)GetProcAddress(GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
    
        if (param != NULL)
        {
            SIZE_T dwRet;
            if (WriteProcessMemory(hProcess, param, (LPVOID)szInjectModName, dwLen, &dwRet))
            {
                while (pCurrentThreadId)
                {
                    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pCurrentThreadId->dwThreadId);
    
                    if (hThread != NULL)
                    {
                         //注入DLL到指定进程
                        QueueUserAPC((PAPCFUNC)LoadLibraryAAddress, hThread, (ULONG_PTR)param);
                        printf("OK
    ");
                        
                        q++;
                        
                    }
    
                    printf("ThreadID:%d
    ", pCurrentThreadId->dwThreadId);
                    pCurrentThreadId = pCurrentThreadId->pNext;
                }
            }
        }
        return 0;
    }

    如果OpenProce或者OpenThread失败,可以尝试提权,或者给UAC,以管理员身份启动。

    不过我个人觉得,这个方法不是每次都能成功,只有线程多的进程,才比较容易成功。win7 测试成功,Win10不是每次成功。

    另外没有提供删除APC队列中函数的方法,所以不能反复注入。

  • 相关阅读:
    【181】IDL 代码从 Windows 转移到 Linux
    异步加载图片到GridView上,防止OOM
    10881
    AngularJS的开发工具---yeoman 简易安装
    AIX操作oracle
    hdu2817 A sequence of numbers
    FZU 2104 (13.11.28)
    HDU 1231 (13.12.2)
    Java 23种设计模式详尽分析与实例解析之一--创建型模式
    JSP视频
  • 原文地址:https://www.cnblogs.com/HsinTsao/p/6416495.html
Copyright © 2011-2022 走看看