3.2 DLL注入:远程APC异步注入

dll,注入,远程,apc,异步 · 浏览次数 : 30

小编点评

## APC 异步过程调用 APC 是一种 Windows 操作系统的核心机制,允许在进程上下文中执行用户定义的函数,而无需创建线程或等待 OS 执行完成。 **主要功能:** * 当某些事件发生时,例如文件 I/O、网络 I/O 或定时器触发,这些事件将被操作系统添加到一个 APC 队列中。 *在下一次发生 ALERTABLE 的事件时,OS 将弹出 APC 函数并在执行线程上下文中调用该函数,并在执行完毕后恢复线程执行。 **与 DLL 注入的关系:** APC 是一种可以使用 APC 机制将代码注入另一个进程的方式实现 DLL 注入。 ** APC 的使用场景:** * 处理异步操作 * 降低线程创建和切换的成本 * 改善性能 **示例代码:** ```c++ // 函数原型:DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData) ``` ** APC 注入流程:** 1. 进程 A 向进程 B 发送 APC 请求。 2. 进程 B 在 APC 队列中插入一个 APC 入口。 3. 进程 B 在 APC 队列中插入一个线程。 4. 进程 B 通知 APC 队列中插入的线程,线程开始执行 APC 指令。 5. 进程 B 返回,等待 APC 指令执行完毕。 **注意:** * APC 需要在目标进程中运行。 * APC 注入的安全性取决于应用程序的构建。

正文

APC(Asynchronous Procedure Call)异步过程调用是一种Windows操作系统的核心机制,它允许在进程上下文中执行用户定义的函数,而无需创建线程或等待OS执行完成。该机制适用于一些频繁的、短暂的或非常细微的操作,例如改变线程优先级或通知线程处理任务。在APC机制中,当某些事件发生时(例如文件IO,网络IO或定时器触发),这些事件将被操作系统添加到一个APC队列中,该队列绑定到执行线程。在下一次发生ALERTABLE的事件时(例如调用SleepEx或SignalObjectAndWait时),OS将弹出APC函数并在执行线程上下文中调用该函数,并在执行完毕后恢复线程执行。

APC机制与DLL注入的关系在于,可以使用APC机制将某些代码注入到另一个进程中,并由该进程执行。读者可以使用NtQueueApcThreadQueueUserAPC等函数将用户定义的函数添加到目标进程中的APC队列中,目标线程将在调用SleepExSignalObjectAndWait等函数时执行注入函数。但读者需要注意,注入函数必须是一个简短的、没有长时间阻塞的代码块,通常会加载DLL或者在目标线程中打开其他进程。

QueueUserAPC 函数允许将一个用户定义的函数添加到指定线程对应的APC队列中。该函数中的APC指异步过程调用,是指通过消息的方式将一段代码投递给线程去执行的一种机制,常用于处理异步操作,该函数的函数原型如下:

DWORD WINAPI QueueUserAPC(
  PAPCFUNC  pfnAPC,
  HANDLE    hThread,
  ULONG_PTR dwData
);

参数说明如下:

  • pfnAPC: 一个指向线程函数的函数指针,在本函数被执行时调用。
  • hThread: 目标线程的句柄。
  • dwData: 传递给线程函数的参数。

当调用QueueUserAPC函数时,该函数将在目标线程的APC队列中添加一个APC入口,APC的入口点为pfnAPC。当目标线程处于alertable状态时,即调用了如SleepEx等同于处理APCs的等待函数时,系统会将APC从队列中弹出,并调用pfnAPC。在DLL注入中,可以使用QueueUserAPC函数向目标进程内的线程的APC队列中插入一个我们定义的函数的指针,使该函数在目标线程执行时运行,从而实现DLL注入的目的。

APC一部注入原理可以总结为如下几个步骤,每个线程在可被唤醒时在其APC链中的函数将有机会执行被执行,每一个线程都具有一个APC链,那么只要在APC链中添加一个APC,就可以完成我们所需要的DLL注入的功能;

  • 1.WriteProcessMemory 将需要加载的DLL的完整路径写入目标进程空间
  • 2.获得LoadLibraryA函数的地址,当然也可以是LoadLibraryW函数的地址
  • 3.枚举目标进程中的所有线程,为每个线程添加一个APC函数,这样增加了注入成功的机会.

利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,通过APC注入的流程步骤大致如下;

  • 1.当进程里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断
  • 2.当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数
  • 3.利用QueueUserAPC()可以在软中断时向线程的APC队列插入一个函数指针,此处插入Loadlibrary()
  • 4.当插入函数被执行时则会加载Loadlibrary并将其指向的DLL模块插入到进程内

但读者需要注意一点,不论如何目标程序必须有执行SleepEx()或者WaitForSingleObjectEx()否则DLL不会加载,读者可自行做实验测试是否可以注入成功;

#include <windows.h>
#include <iostream>
#include <TlHelp32.h>
#include <tchar.h>

// 传入进程名称返回该进程PID
DWORD FindProcessID(LPCTSTR szProcessName)
{
    DWORD dwPID = 0xFFFFFFFF;
    HANDLE hSnapShot = INVALID_HANDLE_VALUE;
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
    Process32First(hSnapShot, &pe);
    do
    {
        if (!_tcsicmp(szProcessName, (LPCTSTR)pe.szExeFile))
        {
            dwPID = pe.th32ProcessID;
            break;
        }
    } while (Process32Next(hSnapShot, &pe));
    CloseHandle(hSnapShot);
    return dwPID;
}

// APC注入
BOOL ApcInjectDll(DWORD dwPid, char* szDllName)
{
    // 得到文件完整路径长度
    int nDllLen = lstrlen(szDllName) + sizeof(char);

    // 打开目标进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
    if (hProcess == NULL)
    {
        return FALSE;
    }

    // 在对端开辟内存空间
    PVOID pDllAddr = VirtualAllocEx(hProcess, NULL, nDllLen, MEM_COMMIT, PAGE_READWRITE);
    if (pDllAddr == NULL)
    {
        CloseHandle(hProcess);
        return FALSE;
    }

    // 根据不同位数写出DLL文件路径
#ifdef _WIN64
    size_t dwWriteNum = 0;
    WriteProcessMemory(hProcess, pDllAddr, szDllName, nDllLen, &dwWriteNum);
#else
    DWORD dwWriteNum = 0;
    WriteProcessMemory(hProcess, pDllAddr, szDllName, nDllLen, &dwWriteNum);
#endif
    CloseHandle(hProcess);

    THREADENTRY32 te = { 0 };
    te.dwSize = sizeof(THREADENTRY32);

    // 得到线程快照
    HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (INVALID_HANDLE_VALUE == handleSnap)
    {
        CloseHandle(hProcess);
        return FALSE;
    }

    // 得到LoadLibraryA函数的地址
    FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    DWORD dwRet = 0;

    // 得到第一个线程
    if (Thread32First(handleSnap, &te))
    {
        do
        {
            // 进程ID对比是否为传入的进程
            if (te.th32OwnerProcessID == dwPid)
            {
                // 打开线程,得到线程句柄
                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                if (hThread)
                {
                    // 向线程插入APC队列
                    dwRet = QueueUserAPC((PAPCFUNC)pFunAddr, hThread, (ULONG_PTR)pDllAddr);

                    // 关闭句柄
                    CloseHandle(hThread);
                }
            }
            // 循环下一个线程
        } while (Thread32Next(handleSnap, &te));
    }

    // 关闭句柄
    CloseHandle(handleSnap);
    return TRUE;
}

int main(int argc, char *argv[])
{
    DWORD pid = FindProcessID("lyshark.exe");
    std::cout << "进程PID: " << pid << std::endl;

    bool flag = ApcInjectDll(pid, (char *)"d://hook.dll");
    std::cout << "注入状态: " << flag << std::endl;

    return 0;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/cfe47325.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与3.2 DLL注入:远程APC异步注入相似的内容:

3.2 DLL注入:远程APC异步注入

APC(Asynchronous Procedure Call)异步过程调用是一种`Windows`操作系统的核心机制,它允许在进程上下文中执行用户定义的函数,而无需创建线程或等待OS执行完成。该机制适用于一些频繁的、短暂的或非常细微的操作,例如改变线程优先级或通知线程处理任务。在`APC机制`中,当某些事件发生时(例如文件IO,网络IO或定时器触发),这些事件将被操作系统添加到一个`APC队列`

cmake构建32位应用程序

1. 背景介绍 2. 工具介绍 3. 环境搭建 4. MinGW编译器版本 1. 背景介绍 最近需要使用第三方动态库文件G33DDCAPI.dll进行二次开发。由于这个动态库文件生成的时间比较早,且只提供了32位的版本,并没有提供源代码。如果希望利用这个动态库进行开发,有两种解决方法: 编译64位应

DHorse v1.3.2 发布,基于 k8s 的发布平台

## 版本说明 ### 新增特性 * 构建版本、部署应用时的线程池可配置化; ### 优化特性 * 构建版本跳过单元测试; ### 解决问题 * 解决Vue应用详情页面报错的问题; * 解决Linux环境下脚本运行失败的问题; * 解决下载Maven安装文件失败的问题; ### 升级说明 下载v1.

Llama2-Chinese项目:3.2-LoRA微调和模型量化

提供LoRA微调和全量参数微调代码,训练数据为data/train_sft.csv,验证数据为data/dev_sft.csv,数据格式为"Human: "+问题+"\nAssistant: "+答案。本文主要介绍Llama-2-7b模型LoRA微调以及4bit量化的实践过程。

.NET周报 【3月第2期 2023-03-12】

国内文章 ASP.NET Core中如何限制响应发送速率(不是调用频率) https://www.cnblogs.com/coredx/p/17195492.html ASP.NET Core中有很多RateLimit组件,.NET 7甚至推出了官方版本。不过这些组件的主要目标是限制客户端访问服务的

[转帖]skywalking配置nacos集群模式

版本: nameversionnacos1.1.0skywalking6.2.0elasticsearch6.3.2 es集群管理工具 cerebro-0.8.3 https://github.com/lmenezes/cerebro 前置: es、nacos至少各有一个 1 开始: 1.将 apa

SpringBoot 3.x 结合 Swagger3 (Knife4j )踩坑实录

SpringBoot 3.x + Swagger3 踩坑实录 我的是springboot 版本是:3.2.2 org.springframework.boot spring-boot-starter-parent

iceoryx源码阅读(三)——共享内存通信(一)

目录0 导引1 整体通信结构2 RelativePointer2.1 原理2.2 PointerRepository2.3 构造函数2.4 get函数3 ShmSafeUnmanagedChunk3.1 队列数据3.2 RelativePointerData3.3 构造函数3.4 releaseTo

[转帖]SpringBoot配置SSL 坑点总结【密码验证失败、连接不安全】

文章目录 前言1.证书绑定问题2.证书和密码不匹配3.yaml配置文件问题3.1 解密类型和证书类型是相关的3.2 配置文件参数混淆 后记 前言 在SpringBoot服务中配置ssl,无非就是下载证书设置一下配置文件的问题,这里主要记录我在配置的过程中遇到的坑点。 如果是新手上道的话建议结合其他的

[转帖]优化命令之sar——最牛命令

目录 一:sar命令概述 1.1sar概述 1.2sar常用选项 1.3常用参数 二:CPU资源监控 2.1整体CPU使用统计(-u) 2.2各个CPU使用统计(-P) 2.3将CPU使用情况保存到文件中 三:内存监控 3.1内存和交换空间监控 3.2内存分页监控 3.3系统交换活动信息监控 四:I