|
去年在某次红队演练中,我用默认配置生成的Cobalt Strike Beacon打出去,上线不到三秒钟就被Windows Defender杀了。不是拦截,是直接杀——连内存都没进去。 换了XOR加密再打,活了大概两分钟。够我执行whoami和ipconfig,然后再次被杀。第三次,我用了Module Overloading加间接系统调用加Sleep Masking的组合拳。这台机器在目标内网里待了整整两周,每天回传一次心跳,横向移动了两台服务器,直到演练结束防守方都没发现这个Beacon。
事后复盘时,蓝队队长看了我的工具链配置,说了一句话:你们的木马在EDR眼里,看起来就像Windows自己启动了一个后台线程。
这就是2026年的免杀现实——你不再是在和杀毒软件的特征库打,而是在和整个终端防护体系打。特征匹配、内存扫描、行为分析、内核回调、ETW遥测、AI异常聚类——每一层都在盯着你的木马,看它有没有在"不该干的事"。而你要做的,是让它在每一层看来,都"只是在干正常的事"。
本文将我在多个授权红队项目中验证过的免杀技术,从编译层、加载层、执行层、行为层四个维度完整拆开。每条技术都附具体配置和脱敏案例。
一、静态逃逸:把木马的"指纹"从文件里擦干净
杀软的第一道防线是静态扫描——在文件落地的瞬间,甚至还没执行,就通过对PE结构、导入表、字符串特征的分析判定它是恶意程序。
C2工具生成的Shellcode带有明显的"刀具形状"——固定的WinAPI调用序列、硬编码的User-Agent、特定的内存分配模式,这些特征在杀软眼里就像指纹一样清晰。这就是为什么我们需要Loader——给这些"刀具"穿上不同的"外衣",让它们在X光机下看起来像普通物品。实测数据验证了这一点:用默认配置生成的Cobalt Strike Shellcode,几乎100%会被主流杀软检测到;但经过XOR加密处理后,检测率立即下降到30%以下。
XOR加密只是入门。2026年有效的静态逃逸手段包括:
字节级特征混淆:对Shellcode进行多轮不同密钥的XOR加密,每轮使用不同的密钥,加密后在内存中分片解密、逐片执行。杀软的特征库覆盖不了所有加密变体。字节顺序随机打乱、插入无效指令(NOP sled)、分块传输加载都是验证有效的技术。
Go语言静态编译:Go编译出的二进制文件天然规避了.NET或Java等环境的特征检测,默认静态链接,运行时和标准库全打包进二进制,不含外部DLL依赖。关键编译参数:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H=windowsgui" -o beacon.exe main.go-s -w剥离符号表和DWARF调试信息,显著减小体积并增加逆向分析难度;-H=windowsgui抑制控制台窗口,伪装为GUI程序。额外加UPX压缩可进一步降低文件熵值,但需注意部分EDR会直接拦截UPX加壳行为,需在目标环境做沙箱测试确认。 Nim语言的优势:Nim编译为C后再编译为二进制,生成的PE结构比Go更接近手写C,导入表更简洁、没有明显的语言runtime指纹。Go的二进制文件虽然静态编译,但标准库符号丰富、PE/ELF结构规整,反而已被新一代EDR通过行为建模与静态熵值分析精准识别。Nim在这个维度上目前处于相对低位——主流EDR对Nim编译产物的特征覆盖还不够完善。
C2框架定制化修改:Sliver的默认Shellcode生成依赖Donut的AMSI bypass,这段代码已被杀软严重签名。通过修改Sliver源码禁用默认的AMSI绕过,配合自定义Shellcode Loader将Payload动态映射到内存中,可实现在运行时的免杀。shad0w C2框架采用类似思路,通过频繁更新Payload来规避常见AV产品。
Donut本身也内置了反检测能力——可修补Windows AMSI以防止安全工具在执行前检查脚本内容。但Donut的默认配置签名已被广泛采集,使用时必须修改源码去除特征。
二、Loader技术:给Shellcode穿上"隐身衣"
Shellcode本身没有任何文件结构。它不依赖加载器、不注册PEB、不创建新进程。但正因为它"什么都不像",反而容易被EDR识别——正常的Windows程序不会直接分配一块内存然后跳过去执行。
Loader的任务,就是让Shellcode的执行方式看起来像正常行为。
2.1 传统注入为什么不行了
VirtualAllocEx + WriteProcessMemory + CreateRemoteThread这套组合拳,在2026年几乎等同于自杀。EDR对所有跨进程内存写入和远程线程创建做了全量监控——不是抽样,是每一个调用都记录。CrowdStrike 2026全球威胁报告显示,2025年82%的检测已经是无恶意软件的,攻击者不再依赖传统恶意代码,而是通过合法凭证和信任路径横向移动。
2.2 Module Overloading:把恶意代码藏进合法DLL的影子
模块重载是当前绕过内核回调最有效的手段之一。
传统Payload加载依赖LoadLibrary,这个行为被EDR通过Callback-Gate和用户态Hook严密监控。Module Overloading完全绕过了加载器——它手动创建文件映射对象并映射到内存,不触发任何加载事件。
标准操作步骤:第一步,打开目标DLL(如ntdll.dll)的文件句柄;第二步,使用NtCreateSection创建SEC_IMAGE属性的节对象——告诉内核把这个文件当成一个可执行映像来处理;第三步,使用NtMapViewOfSection把节映射到当前进程的内存空间。此时,映射区域的内存属性仍然是"由磁盘文件backed"——EDR的内存扫描看到的是原始的合法ntdll.dll内容,不会触发篡改告警。
第四步最精妙:直接用自己的Shellcode覆盖映射区域的.text段。因为内存仍然属于由磁盘文件backed的映射区域,部分EDR仅做页面哈希校验时会误认为内容未改变。覆盖完成后,映射区域里运行的就是恶意代码,但从进程的已加载模块列表看,这只是ntdll.dll的一个"普通映射"。
Elastic EDR同时使用内核回调(监控模块加载事件)和用户态Hook(拦截API调用)两层防御。Module Overloading绕过了内核层的映像验证(因为不是通过LoadLibrary加载,不触发回调),但用户态Hook仍然能拦截后续的API调用。这需要搭配Stack Spoofing来对抗。
2.3 PData注册与RtlAddFunctionTable:修复调用栈
Windows的异常分发机制依赖函数表来展开调用栈。当EDR对线程做栈回溯时,如果发现某帧的返回地址指向一个"不属于任何已注册模块"的内存区域,直接判定为恶意行为。
RtlAddFunctionTable允许动态注册自定义函数表,告诉Windows的栈展开器:我的Shellcode所在内存区域是一组合法的函数,对应的展开信息在这里。注册后,EDR的栈回溯会正常走过你的函数帧,不会因为看到一个来自无名内存的返回地址而报alien callstack告警。
具体操作:分配Shellcode所在内存区域的RUNTIME_FUNCTION结构体,填充起始地址、结束地址和展开信息,然后调用RtlAddFunctionTable注册。注册后使用WinDbg的k命令可验证栈回溯是否经过你伪造的合法帧。这步操作往往是决定一个Loader能否存活超过一小时的唯一变量。
三、执行层对抗:让EDR的钩子全部失效
EDR的用户态Hook工作原理很直接:在ntdll.dll的关键API函数(如NtAllocateVirtualMemory、NtWriteVirtualMemory、NtCreateThreadEx)开头插入一条jmp指令,让所有调用先经过EDR的监控代码,再决定是否放行。
现代EDR/XDR的核心检测能力建立在三个技术支柱上:内核级行为监控——通过操作系统内核回调和ETW对进程创建、内存分配、句柄操作、网络连接做实时监控;内存与代码完整性分析——扫描进程内存区域、检测代码段异常修改、验证数字签名;智能威胁狩猎与跨层关联——集成AI和机器学习模型对时间序列遥测数据做异常聚类分析,利用LSTM等架构检测C2心跳的细微周期性模式。
而攻击者只需要做一件事:直接执行内核级系统调用,彻底绕过被监控的API桩。
3.1 间接系统调用:从ntdll.dll动态提取syscall指令
间接系统调用的核心思想:不调用kernel32.dll或ntdll.dll的导出函数(那些函数开头有EDR的jmp钩子),而是自己从ntdll.dll的原始代码中定位syscall指令的位置,自己设置寄存器,自己执行syscall。
完整流程:第一步,动态解析ntdll.dll中指定函数(如NtAllocateVirtualMemory)的syscall桩——这段代码在EDR Hook之前就已存在于ntdll.dll中。第二步,确定该函数对应的系统服务号(SSN)。第三步,用汇编桩将参数加载到正确寄存器(RCX、RDX、R8、R9),然后执行syscall或sysenter指令。整个调用链完全不经过被监控的API层,EDR的Hook形同虚设。
3.2 Hit-And-Run:VEH + 调用栈窃取,让syscall看起来合法
Hit-And-Run是2026年3月公开的一种新型系统调用技术。它的核心创新在于:不仅绕过Hook,还让syscall的调用栈看起来像是从合法的Windows API序列中自然产生的。
技术实现依赖两个关键机制:Vectored Exception Handling(VEH)和调用栈窃取。VEH是Windows提供的动态异常处理机制,允许开发者在运行时注册异常处理器。调用栈窃取则是劫持一个合法函数的调用栈,确保syscall看起来是从一个有效的Windows API序列中发起的。
具体步骤:先调用ntdll.dll中的一个合法函数(如NtAllocateVirtualMemory),这个调用设置了初始执行流。接着设置断点,触发VEH异常处理器。在异常处理器中,修改线程上下文,将RIP指向自定义的syscall指令,同时保持栈帧不变。这样当EDR对syscall做栈回溯时,看到的是一个完整的、合法的调用链——从用户代码到ntdll.dll再到内核——没有"从天而降"的异常跳转。
Hit-And-Run的PoC实现中借用了SysWhispers3来解析函数地址和SSN,以避免重复造轮子。从调用栈分析的角度看,没有任何证据表明内联Hook被绕过,因为每一帧调用链都是合法且一致的。
3.3 Go语言syscall/LazyDLL:直接从用户态对话内核
Go在红队工具开发中之所以快速崛起,一个重要原因是它对底层系统调用的支持极为直接。不需要Cgo,不需要外部依赖,标准库的syscall和unsafe包就能完成进程注入、提权利用等全套操作。
使用syscall.NewLazyDLL手动调用NTDLL函数,规避kernel32.dll等被重点监控的高危导入表。编译时用CGO_ENABLED=0强制纯Go模式,避免CGO交叉编译引入libc依赖和符号暴露。
Go原生提供net/http实现HTTP(S) C2信道,crypto/aes和crypto/rsa实现密钥协商与载荷加密,embed包将Shellcode直接编译进二进制规避磁盘落地检测。Go还具备天然的跨平台交叉编译能力,在Linux主机上可直接构建Windows反弹Shell:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H=windowsgui" -o beacon.exe main.go
据237个实战样本的对比数据报告,Go语言在编译体积、启动延迟和EDR绕过成功率三个维度上对Python/C具有显著优势。 四、行为规避:让EDR的AI模型觉得你"正常"
即使syscall绕过了Hook,EDR仍然在通过ETW和内核回调监控整个系统的行为——进程创建、内存分配模式、句柄操作序列、网络连接时序。这些数据被送入机器学习模型做异常检测,即使单次syscall调用看起来合法,行为序列的异常仍然会被标记。
4.1 Sleep Masking:在"睡觉"时把自己藏起来
Beacon心跳是C2通信的核心,也是EDR AI模型最容易捕捉到的行为模式。Sleep Masking的核心原理是:在Beacon进入休眠前,把所有敏感的内存区域(Shellcode、配置信息、已窃取的数据)用强密钥加密;休眠结束后再解密恢复执行。
实现注意事项:加密和解密操作本身会产生新的行为特征——频繁的VirtualProtect调用修改内存权限。需要在每次Sleep周期中使用不同的加密密钥和不同的内存页面顺序,防止形成固定的"加密→休眠→解密→执行"签名。
4.2 ETW与AMSI的"致盲"操作
ETW(Event Tracing for Windows)是Windows内置的诊断基础设施,EDR依赖它来获取进程创建、内存分配、网络连接等事件。AMSI(Antimalware Scan Interface)允许安全产品在脚本引擎和应用程序层面检查内容。
对于Go语言工具,-ldflags="-s -w"剥离调试符号与DWARF信息不仅减小体积和增加逆向分析难度,还切断了ETW中的堆栈符号解析——当EDR尝试解析Go二进制的调用栈时,缺乏符号信息导致回溯结果不完整或无法识别。
4.3 Cortex XDR BIOC白名单绕过案例
InfoGuard Labs在2025年对Palo Alto Cortex XDR的研究揭示了行为检测的一个致命盲区。研究团队通过逆向Cortex XDR的加密BIOC规则,发现其中包含一个全局白名单——只要进程的命令行参数中包含\Windows\ccmcache这个字符串,XDR Agent就自动将其排除在行为监控之外。这个单一字符串成功地让大约一半的Cortex XDR行为检测规则失效。
实战利用极为简单:在运行任何敏感工具时,追加\Windows\ccmcache参数即可。研究团队成功使用该方法运行了ProcDump(SysInternals工具集中的LSASS内存转储工具)而完全未被检测到。此漏洞已于2026年2月通过Cortex XDR Agent 9.1版本修复——修复方式是彻底删除这些全局白名单,而非仅仅修改加密密钥。
4.4 延迟执行策略与GC暂停控制
Windows Defender会监控一系列可疑行为:直接跳转到内存区域执行、异常的内存权限变更、可疑的进程注入操作。对抗这些实时监控的一个实用技巧是"延迟执行"——先申请普通内存,过几分钟再修改为可执行权限。这种时间差能有效规避实时监控,因为大多数EDR的实时分析窗口覆盖不了这种延时跨度。
Go语言的内存管理虽含垃圾回收(GC),但可通过runtime.GC()手动控制触发时机,并结合sync.Pool复用对象,避免高频分配引发的GC波动。红队工具常需长期驻留且规避行为监控,这种内存管理模式能减少堆分配频率,降低EDR对异常内存模式的检出概率。
五、内核级对抗:BYOVD——把EDR直接"干掉"
当用户态的所有绕过手段都失效时,攻击者还有一张王牌:Bring Your Own Vulnerable Driver——自带漏洞驱动。
BYOVD的原理是:攻击者将一个合法签名但存在漏洞的驱动程序部署到目标机器上,利用该驱动的内核级权限来终止安全产品的进程。Windows 64位版本强制执行驱动程序签名,只允许加载经过签名的驱动,因此攻击者只能寻找已签名但存在漏洞的合法驱动来利用。
2026年BYOVD攻击事件密集爆发:
PoisonX是一个被发现的零日BYOVD漏洞。该驱动拥有有效的微软签名,VirusTotal上71款杀软零检出。通过逆向分析,研究人员发现其IOCTL码0x22E010触发一个专用的进程终止流程——驱动程序接收一个ASCII格式的进程ID字符串,用atoi()转换为整数,然后调用ZwOpenProcess和ZwTerminateProcess以内核权限终止目标进程。在用户态试图终止CrowdStrike Falcon的受保护进程会直接返回拒绝访问,但内核态ZwOpenProcess完全绕过PPL限制,无声无息地杀死安全代理。
Reynolds勒索软件组织利用NSecKrnl驱动(CVE-2025-68947)在加密数据前先终止安全产品。攻击链为:提升权限→安装/加载内核驱动→利用BYOVD终止EDR进程→加密文件并留下赎金通知。
HwAudKiller活动通过Google Ads恶意广告投递ScreenConnect安装程序,最终部署利用华为音频驱动的BYOVD工具,以内核权限终止AV和EDR进程。该活动利用商业隐蔽服务和现成加密工具,显著降低了攻击门槛。
还有攻击者通过SonicWall SSLVPN凭证入侵网络后,利用EnCase取证驱动以内核权限终止所有安全工具进程。
防御BYOVD的三条基本策略:
第一,应用WDAC(Windows Defender Application Control)或易受攻击的驱动程序阻止列表,强制拦截已知漏洞驱动。第二,HVCI(Hypervisor-protected Code Integrity,即内存完整性)如果系统支持就开启,这能防止未签名代码进入内核。第三,监控SeLoadDriverPrivilege权限的使用——BYOVD需要加载驱动的特权,这一行为的告警价值极高。
六、基础设施隐匿:C2流量伪装
免杀不只发生在终端上。即使木马在目标主机上完全不被检测到,如果C2流量被网络层的全流量分析抓到,整个行动仍然会暴露。
6.1 CloudFlare Workers C2重定向
CloudFlare Workers是部署在全球CDN边缘节点的JavaScript运行时。它们不是传统VPS——没有固定的源IP,每个请求都由最近的边缘节点处理。Cloudflare-Redirector利用Workers构建C2重定向器,支持多C2、多域名、WebSocket监听。
架构设计:Workers节点面向目标主机接收心跳请求,根据预配置规则转发到后端真实C2服务器。目标主机看到的始终是Cloudflare的IP,后端C2完全隐藏在Workers层之后。结合JWT认证和Zero Trust策略进一步加强隐蔽性。
6.2 Malleable C2 Profile定制
Cobalt Strike和Havoc等C2框架的默认流量特征——TLS指纹(JA3/JA4)、HTTP请求间隔规律、URI路径模式——已被几乎所有NTA/NIDS产品识别。必须定制Malleable C2 Profile来模拟真实应用的流量特征,将心跳伪装为正常的Microsoft 365通信、Google Analytics上报或CloudFlare CDN回源流量,调整抖动(jitter)参数使请求间隔呈现人类浏览行为的随机分布。
七、实战案例:从外网打点到内网横移的全链路免杀
这是一个已经脱敏处理的实战案例。
入口:红队通过外网打点发现IIS服务器,权限极低。蓝队在后台持续监控C2通信。根据掌握的免杀技术开始针对某国产EDR和云镜做针对性免杀。
提权阶段:先用systeminfo导出补丁信息,交给AI分析推荐提权方案。AI推荐土豆系列,常规进程注入此时被EDR强力查杀。针对EDR行为特征,改用API动态调用+直接syscall+ETW致盲组合拳,让AI生成免杀版本的上传组件。实测360核晶动态防护也能绕过。但因当前用户缺少SeImpersonatePrivilege权限,所有土豆系提权全部失败。
转向SpoolFool打印机功能提权。再做一套免杀操作——但提权依然失败。排查发现目标服务器未启用打印机服务。AI继续分析环境,推荐寻找可写路径打DLL劫持提权。考虑到生产环境不能重启服务,此方案被搁置。
最终突破:AI分析目标服务器上的SQL Server服务,建议打XP_CMDSHELL。红队成员在配置文件中找到了SQL Server连接凭据,通过XP_CMDSHELL成功执行命令。这轮操作的关键是:AI把环境分析、提权方案推荐、免杀改造的迭代速度拉到了人力无法企及的高度,但AI倾向推荐高风险操作(如直接重启服务),最终由人来判断和把控风险边界。
免杀七层穿透模型:从编译到运行的全链路对抗
这不是传统OSI网络模型,而是针对现代终端防护体系(EDR/XDR/AV)设计的纵深对抗框架,覆盖文件落地、进程创建、内存分配、API调用、网络通信、行为签名到沙箱逃逸七个检测面。每层专注绕过一类检测机制,层间通过动态加载、上下文感知与条件跳转联动:
第一层编译期:Go -ldflags剥离符号+消除DLL导入表+CGO禁用生成纯原生二进制+UPX压缩控制文件熵值。
第二层加载期:Module Overloading绕LoadLibrary监控+NtCreateSection手动映射不触发内核回调。
第三层内存分配期:分段映射+逐片异或解密+XOR加密后检测率降至30%以下。
第四层API调用期:间接syscall绕用户态Hook+LazyDLL手动调用NTDLL函数规避高危导入表。
第五层网络通信期:CloudFlare Workers重定向+TLS 1.3伪装浏览器流量+模拟Chrome最新版本指纹。
第六层行为签名期:Sleep Masking内存加密+ETW致盲+GC暂停控制减少高频分配+延迟执行策略拖过实时监控窗口。
第七层运行期:合法进程子线程上下文执行Shellcode+RtlAddFunctionTable注册函数表使栈回溯正常走过伪造的合法帧。
这套七层框架的目的不是在某一点上彻底击败EDR,而是让攻击行为在每一层检测面上都低于告警阈值。CrowdStrike 2026报告显示,攻击者平均突破时间(breakout time)已压缩到29分钟,防御方的反应时间窗口正在急速收窄。
写在最后
免杀已经不再是二进制特征的对抗,而是系统工程。一个能在目标环境里活过两周的木马,靠的不是某一种技巧,而是对EDR检测链每一个环节的精确理解和针对性绕过。
这篇文章里提到的每一项技术,都有一个共同的底层逻辑:EDR不是万能的,它是在性能和安全性之间做的折衷。间接syscall之所以有效,是因为EDR厂商选择在用户态Hook API而不是在内核态拦截每一个syscall。Module Overloading之所以有效,是因为内核只校验了映像文件的签名,没有校验内存页面是否被篡改。BYOVD之所以有效,是因为Windows信任签名驱动,而签名驱动的漏洞没有被及时修复。
理解EDR的"折衷点",比掌握具体的绕过技巧更重要。
如果你想深入实践,最推荐的入门语言是Go。它的静态编译、syscall支持、跨平台能力和标准库丰富度,让它成为2026年红队武器开发的理想选择。其次是Nim,语法简洁,编译产物比Go更难被EDR指纹识别。Rust虽然安全性和性能均佳,但学习曲线较陡。
最后,所有技术在合法授权的红队演练中验证,目的是帮助防守方发现检测盲区、加固防御体系。技术无罪,边界是法律。
|