
シェルコードローダージェネレーターで、複数のインジェクション手法をサポートし、レッドチームの活動向けに構築されています。
hollow は、シェルコードローダー生成ツールです。生のシェルコードバイナリとプロファイルを指定すると、シェルコードが暗号化されたコンパイル済みWindows PEローダーを出力します。
バイナリはリリースページから入手するか、ソースからビルドできます。
go build -o hollow .
クロスコンパイルには x86_64-w64-mingw32-gcc が必要です。
Arch Linux: pacman -S mingw-w64-gcc
Debian/Ubuntu: apt install gcc-mingw-w64-x86-64
./hollow -shellcode payload.bin -profile profiles/new_process_injection_sc.json
| フラグ | 説明 |
|---|---|
-shellcode | 生シェルコード (.bin) へのパス |
-profile | プロファイルJSONファイルへのパス |
-templates | テンプレートディレクトリ (デフォルト: ./templates) |
hollow は 暗号化 → 置換 → コンパイル の3段階パイプラインで動作します。
シェルコードは、実行ごとにランダムに生成された鍵とIVを用いてAES-256-CBCで暗号化されます。両方とも出力バイナリに埋め込まれます。次に、選択されたCテンプレート内のプレースホルダーが暗号化されたシェルコード、鍵、IVに置き換えられ、MinGWによってストリップ・静的リンクされたPEにコンパイルされます。
実行時、ローダーはWindows BCryptを使用してシェルコードを復号し、テンプレートが実装する注入手法で実行します。
テンプレートは、実際の注入ロジックを実装するCソースファイルです。各テンプレートは templates/ にあり、hollow がコンパイル前に埋め込むプレースホルダートークン(${SHELLCODE}、${KEY}、${IV}、${TARGET_PROCESS})を含んでいます。プロファイルを通じてテンプレートを選択します。
hollow には6つのテンプレートが同梱されています。
独自のテンプレートを作成して templates/ に配置できます。プロファイルがそのテンプレートを指定していれば、hollow が自動的に認識します。
プロファイルはJSONファイルで、hollow に使用するテンプレート、ターゲットプロセス、出力のコンパイル方法を指示します。profiles/ に格納されており、導入ごとにカスタマイズすることを想定しています。
{
"name": "New Process Injection via Direct Syscalls",
"author": "",
"template": "new_process_injection_sc",
"target_process": "C:\\Windows\\System32\\cmd.exe",
"arch": "x64",
"compile": {
"automatic": true,
"gcc": "x86_64-w64-mingw32-gcc",
"strip": true,
"output_type": "exe"
},
"output_dir": "./output"
}
output_type は exe または dll です。automatic: false を設定すると、コンパイルせずに置換後のCソースをディスクに出力します。コードを修正してからビルドしたい場合に便利です。
出力ファイルは output_dir に {テンプレート名}_loader.{exe|dll} という名前で書き込まれます。
テンプレート: new_process_injection
手法: 新しく生成したプロセスへのリモートスレッドインジェクション。
ターゲットプロセスを CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW フラグで起動し、2秒待って初期化を待った後、そのアドレス空間にメモリを確保し、復号したシェルコードを書き込み、実行可能に設定し、そこを指すリモートスレッドを作成します。BREAKAWAY フラグは、ローダーがWinRMから起動された場合に必要です(WinRMはすべてのプロセスをジョブオブジェクトでラップするため)。ターゲットは実行可能ファイルのフルパスです。
Win32呼び出し: CreateProcessA、VirtualAllocEx、WriteProcessMemory、VirtualProtectEx、CreateRemoteThread。
テンプレート: new_process_injection_sc
手法: 新しく生成したプロセスへのリモートスレッドインジェクション(直接システムコール、Hell's Gate使用)。
new_process_injection と同じ動作ですが、すべてのメモリ割り当てとスレッド呼び出しがWin32レイヤーをバイパスします。SSNは実行時にntdllから解決され、生の syscall 命令で実行されます。ベンチマークセクションを参照してください。
テンプレート: remote_thread_injection
手法: 既存プロセスへの従来のリモートスレッドインジェクション。
CreateToolhelp32Snapshot を使って実行中のプロセスを名前で検索し、ハンドルを開き、メモリを確保し、シェルコードを書き込み、リモートスレッドを作成します。新しいプロセスは生成しません。explorer.exe のような長時間稼働するプロセスに最適です。ターゲットはプロセスイメージ名であり、フルパスではありません。
Win32呼び出し: OpenProcess、VirtualAllocEx、WriteProcessMemory、VirtualProtectEx、CreateRemoteThread。
テンプレート: remote_thread_injection_sc
手法: 既存プロセスへの従来のリモートスレッドインジェクション(直接システムコール、Hell's Gate使用)。
remote_thread_injection と同じ動作で、Win32レイヤーをバイパスします。ベンチマークセクションを参照してください。
テンプレート: earlybird_apc
手法: Early Bird APC インジェクション (CyberArk, 2018)。
ターゲットプロセスをサスペンド状態で起動し(CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW)、復号したシェルコードをそのアドレス空間に書き込み、QueueUserAPC でメインスレッドにシェルコードを指す非同期プロシージャコール(APC)をキューに入れ、ResumeThread で再開します。APCはプロセスのエントリポイント実行前に発生するため、プロセス内の防御ツールが初期化される前にシェルコードが実行されます。VirtualAllocEx + WriteProcessMemory + CreateRemoteThread の三連符を完全に回避します。
テンプレート: dll_sideload
手法: DLLサイドローディング / インプロセスシェルコード実行。
EXEではなくDLLを生成します。DLL_PROCESS_ATTACH 時に、シェルコードを復号してインプロセスで実行するスレッドが生成されます:VirtualAlloc、memcpy、VirtualProtect、そしてシェルコードへの直接関数呼び出し。ペイロードが初期化される間(Sliverビーコンの場合約10秒)、ホストプロセスは生存している必要があります。正規のバイナリが不足しているDLL検索パスのエントリ経由で読み込む場所にDLLを配置して展開します。
テスト環境: Windows 10 Build 19041、Windows Defender リアルタイム保護有効、定義 1.453.354.0、ペイロードとして17MBのDonutでラップしたSliverビーコンを使用。
Trojan:Win64/AsyncRat.RPY!MTB は、リモートプロセスハンドルに対してWin32 APIレイヤーを通じて VirtualAllocEx + WriteProcessMemory + CreateRemoteThread の古典的なリモートインジェクションシーケンスが呼び出された場合にトリガーされる機械学習による動作ルールです。Defender は、これらの3つの呼び出しが連続して出現したときに発火するカーネルコールバックを登録しています。
_sc テンプレートは、これらのWin32関数を決して呼び出さないことでこれを回避します。代わりに、対応するカーネルシステムコールサービス番号(SSN)を実行時にntdllからHell's Gateを使って直接解決します。フックされていない各ntdllスタブは4バイトのプロローグ 4C 8B D1 B8 で始まり、SSNはオフセット4にあります。実際のシステムコールは、movq %rcx, %r10 / movl ssn(%rip), %eax / syscall / ret のみを含むGCCのネイキッド関数であり、これはntdllスタブ自体が実行する正確なシーケンスです。監視対象のWin32ラッパーが決して呼び出されないため、Defenderのコールバックは発火しません。
ntdllスタブが完全なEDRによってパッチされている(プロローグがジャンプに置き換えられている)システムでは、クリーンスタブのチェックに失敗し、ローダーは早期に終了します。Halo's Gate(隣接するスタブをスキャンしてSSNを推測する方法)は実装されていません。
ローダーコードは約19KBのオーバーヘッドを追加します。出力サイズは基本的に入力シェルコードのサイズと同じです。17MBのSliverビーコンは18MBのローダーを生成します。典型的なMetasploitシェルコード(約200KB)では、約220KBのローダーが生成されます。
コントリビューションは歓迎します。自作のテンプレートを追加したい場合や、既存のテンプレートを改善したい場合は、お気軽にPRを開いてください。バグを見つけた場合や提案がある場合は、Issueを開いてください。
このツールの目的は、ローダー開発プロセスを容易にすることであり、完成品であることではありません。新しいテンプレート、より良いプロファイル、コアの改善など、すべてを対象としています。hollow はまた、シェルコードローダーとインジェクション手法の背後にある概念を人々が理解する手助けをすることを意図して構築されています。そのため、明確で読みやすいテンプレートコードは機能性と同じくらい価値があります。
各手法の背後にある概念とhollowの完全な使用方法については、まもなく私のブログで詳しく説明する予定です。お楽しみに。
| テンプレート | 手法 |
|---|
new_process_injection | 新しく生成したプロセスへのリモートスレッドインジェクション |
new_process_injection_sc | 同上、直接システムコール (Hell's Gate) を使用 |
remote_thread_injection | 既存プロセスへの従来のリモートスレッドインジェクション |
remote_thread_injection_sc | 同上、直接システムコール (Hell's Gate) を使用 |
earlybird_apc | Early Bird APC インジェクション |
dll_sideload | DLLサイドローディング、EXEではなくDLLを生成 |
| テンプレート | Defender 動作検知アラート | セッション確立 |
|---|
| new_process_injection | Trojan:Win64/AsyncRat.RPY!MTB | yes |
| remote_thread_injection | Trojan:Win64/AsyncRat.RPY!MTB | yes |
| earlybird_apc | none | yes |
| dll_sideload | none | yes |
| new_process_injection_sc | none | yes |
| remote_thread_injection_sc | none | yes |