1. 免杀对抗的本质与演进脉络
当EDR(终端检测与响应)系统成为企业安全标配,攻击者与防御者的博弈焦点逐渐转向了"特征"这个微观战场。我亲历过多次红蓝对抗,发现真正的技术较量往往发生在字节级别的特征修改上。比如某次实战中,通过调整PE头部的SectionAlignment值从0x1000改为0x200,就成功绕过了当时主流EDR对内存加载行为的检测。
免杀技术发展经历了三个阶段:
- 静态特征对抗阶段(2010-2015):修改哈希值、加壳加密
- 行为特征对抗阶段(2016-2020):API调用链混淆、内存操作伪装
- 上下文感知阶段(2021至今):环境感知、时序扰乱、进程树伪造
最新EDR产品普遍采用多层检测引擎:
- 静态扫描层:YARA规则+机器学习模型
- 行为监控层:内核回调+ETW事件采集
- 内存分析层:周期性内存快照比对
- 上下文关联层:进程树/网络连接/登录会话关联分析
关键认知:现代免杀不再是简单的特征修改,而是对检测体系决策逻辑的逆向工程。需要同时考虑静态特征、运行时行为、环境上下文三个维度的对抗。
2. 静态特征逃逸的实战技巧
2.1 文件特征变形技术
在最近一次攻防演练中,我们对Cobalt Strike的beacon.dll进行改造,通过以下步骤实现静态免杀:
- 节区重组:将.text节重命名为非标准名称(如.axx)
- 导入表混淆:使用LoadLibrary/GetProcAddress动态加载API
- 字符串加密:所有硬编码字符串采用RC4动态解密
- 签名伪造:添加无效但格式正确的证书数据
实测效果对比:
| 修改项 | 某EDR检出率 |
|---|---|
| 原始文件 | 100% |
| 仅加壳 | 92% |
| 节区重组 | 65% |
| 组合方案 | 8% |
2.2 无文件攻击的载体隐藏
内存加载已成为主流攻击方式,但EDR对以下关键点监控严格:
- 可执行内存区域(PAGE_EXECUTE_READWRITE)
- 非镜像内存执行(Non-Image Memory Execution)
- 反射式DLL注入(Reflective DLL Loading)
有效对抗方案:
c复制// 内存分配时添加伪装标志
VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 稍后通过VirtualProtect改为可执行
VirtualProtect(pMem, size, PAGE_EXECUTE_READ, &oldProtect);
// 使用早期Windows版本就存在的合法API
hMod = LoadLibraryA("amsi.dll");
pAmsiScanBuffer = GetProcAddress(hMod, "AmsiScanBuffer");
3. 行为层面的对抗艺术
3.1 API调用链混淆技术
现代EDR会监控敏感API的调用序列。我们通过以下方法干扰分析:
- 添加无意义API调用作为干扰项
- 拆分关键操作到不同线程
- 引入随机延迟(10-300ms)
- 通过合法进程间接调用(如explorer.exe加载COM组件)
典型对抗案例:
原始调用链:
VirtualAlloc -> WriteProcessMemory -> CreateRemoteThread
改造后:
code复制CreateFileMapping -> MapViewOfFile (干扰项)
Sleep(rand()%200)
NtAllocateVirtualMemory (替代VirtualAlloc)
RtlCopyMemory (替代WriteProcessMemory)
Sleep(rand()%100)
NtCreateThreadEx (替代CreateRemoteThread)
3.2 进程注入的新型变种
传统进程注入方式(如CreateRemoteThread)已被EDR重点监控。当前有效的替代方案:
-
进程镂空(Process Hollowing)改进版:
- 挂起合法进程(如notepad.exe)
- 替换内存内容时保留原PE头部结构
- 恢复执行前修复内存校验和
-
线程劫持(Thread Hijacking):
- 枚举目标进程已有线程
- 挂起线程并修改上下文(EIP/RIP)
- 设置单次执行陷阱(TF标志位)
-
APC注入优化:
- 选择GUI线程而非工作线程
- 结合Alertable状态检测
- 使用Ex变种(NtQueueApcThreadEx)
4. EDR对抗的进阶策略
4.1 用户态Hook检测与绕过
主流EDR通过以下方式植入用户态Hook:
- IAT Hook(导入地址表劫持)
- Inline Hook(指令跳转劫持)
- VEH Hook(向量化异常处理)
检测与绕过方案:
asm复制; 检测IAT Hook示例
mov eax, [__imp__MessageBoxA] ; 获取IAT地址
cmp byte [eax], 0xE9 ; 检查首字节是否为JMP指令
je HookDetected
; 绕过Inline Hook方案
mov eax, NtCreateFile ; 获取API地址
add eax, 5 ; 跳过可能存在的Hook(JMP+地址=5字节)
call eax ; 直接调用原始函数
4.2 内核回调的对抗思路
EDR依赖的内核回调主要类型:
- PsSetCreateProcessNotifyRoutine
- PsSetLoadImageNotifyRoutine
- CmRegisterCallback(注册表监控)
- ObRegisterCallbacks(对象操作监控)
实测有效的干扰方法:
- 通过驱动修改回调链表(需Ring0权限)
- 触发大量合法事件淹没监控(如批量创建临时进程)
- 利用回调机制缺陷(如未校验NotifyContext)
5. 环境感知与反沙箱技术
5.1 硬件特征识别
智能环境检测代码示例:
c复制BOOL IsRealMachine() {
// 检测CPU核心数
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
if (sysInfo.dwNumberOfProcessors < 2) return FALSE;
// 检测内存大小
MEMORYSTATUSEX memStat;
memStat.dwLength = sizeof(memStat);
GlobalMemoryStatusEx(&memStat);
if (memStat.ullTotalPhys < 4*1024*1024*1024ULL) return FALSE;
// 检测磁盘空间
ULARGE_INTEGER freeBytes;
GetDiskFreeSpaceEx("C:\\", NULL, NULL, &freeBytes);
return freeBytes.QuadPart > 100*1024*1024*1024ULL;
}
5.2 时序混淆技术
对抗沙箱的加速执行检测:
c复制DWORD startTick = GetTickCount();
PerformMaliciousAction();
DWORD elapsed = GetTickCount() - startTick;
// 人类操作通常有200ms以上间隔
if (elapsed < 150) {
// 可能是沙箱加速执行
ExitProcess(0);
}
// 添加随机延迟
Sleep(rand() % 400 + 100);
6. 现代EDR的防御突破点
通过对多个商业EDR产品的测试,发现以下共性弱点:
-
对.NET程序集的监控盲区:
- 动态编译(CodeDom)
- 反射加载(Assembly.Load)
- 动态方法(DynamicMethod)
-
脚本引擎的检测滞后:
- PowerShell的AMSIBypass技术
- VBA的宏混淆(控制流扁平化)
- JScript的ActiveX混淆
-
容器环境逃逸:
- 共享命名管道利用
- 挂载宿主机目录
- 内核模块漏洞利用
在最近的攻防演练中,我们通过组合以下技术实现突破:
- 使用合法的.NET编译任务(MSBuild)加载恶意程序集
- 通过WMI事件订阅实现持久化
- 利用DNS隧道进行C2通信
- 最终触达率仍保持78%以上
7. 攻防演进趋势与防护建议
从近三年攻防实战看,以下技术方向值得关注:
攻击方技术演进:
- 硬件虚拟化利用(VT-x/AMD-V)
- 可信执行环境滥用(SGX/TPM)
- 固件层持久化(UEFI/ACPI)
防御方改进建议:
- 增强行为基线分析(建立进程行为指纹库)
- 实施多引擎并行检测(至少3种不同原理的检测引擎)
- 引入硬件级可信验证(Intel CET/微软HVCI)
- 加强威胁狩猎能力(至少保留180天终端日志)
企业防护的黄金法则:
- 假定所有终端都可能失陷
- 关注横向移动的异常模式
- 对高价值资产实施零信任隔离
- 定期进行红蓝对抗实战检验
