BOF_RunPE
BOF RunPE は、beacon プロセス内で PE ファイルを完全にメモリ上で実行する Cobalt Strike 用の Beacon Object File です。従来の fork&run とは異なり、子プロセスは生成されず、コンソールも作成されず、パイプも使用されません。すべての出力は IAT フッキングを介して取得され、beacon コンソールにリダイレクトされます。
アーキテクチャ: x64 のみ
概要
┌──────────────────────────────────────────────────────────────┐
│ Cobalt Strike Beacon │
│ (Current Process) │
└────────────────────────┬─────────────────────────────────────┘
│
│ beacon_inline_execute()
│
▼
┌──────────────────────────────────────────────────────────────┐
│ BOF RunPE │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ VxTable + Draugr Initialization │ │
│ │ (Syscall Resolution + Stack Spoofing) │ │
│ └──────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼─────────────────────────────────┐ │
│ │ PE Mapping │ │
│ │ - Section Copy - IAT Patching (with hooks) │ │
│ │ - Relocations - Memory Protection │ │
│ └──────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼─────────────────────────────────┐ │
│ │ Thread Execution │ │
│ │ - Spoofed Start Address │ │
│ │ - RIP Hijacking to Entry Point │ │
│ │ - Output Redirection via Hooks │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
主な機能
- プロセス生成なし: PE は beacon プロセス内で実行されます
- コンソール/パイプなし: 出力は
printf/WriteConsole フックを介して取得されます
- 複数の割り当て方法: Heap、VirtualAlloc、Module Stomping
- プロキシ読み込み: Timer Queue、RegisterWait、または直接呼び出し
- Ntdll アンフッキング: ディスクからの新しいコピーをオプションで使用
- RWX: メモリを RWX で割り当てるオプション
- スレッド開始アドレスのスプーフィング: RIP ハイジャックによる正規の開始アドレス
設定オプション
BOF の動作は、Additionals postex -> RunPe Config で編集できます。

プロキシ方式
| Method | Description |
|---|
None | 直接 API 呼び出し |
Draugr | スタックスプーフィングされた API 呼び出し |
Regwait | RegisterWaitForSingleObject コールバック |
割り当て方式
| Method | Description |
|---|
Heap | Draugr を使用した RtlCreateHeap によるプライベートヒープ |
VirtualAlloc | Draugr を使用した NtAllocateVirtualMemory |
Module stomping | 正規 DLL の .text セクションを上書き |
一般オプション
| Option | Description |
|---|
AllocRWX |
スレッドスプーフィング
| Option | Description |
|---|
ModuleName | 開始アドレス用の正規モジュール(例: Kernel32.dll) |
ProcedureName | モジュール内の関数名(例: BaseThreadInitThunk) |
|
出力キャプチャ
すべての PE 出力は IAT フックを介して beacon コンソールにリダイレクトされます。コンソールウィンドウや名前付きパイプは作成されません。
回避技術
検出ベクトル
カーネルテレメトリ(ETW-TI)
NtGetContextThread / NtSetContextThread:
- 中断されたスレッドのコンテキストを操作してから再開する
メモリ操作:
- NtAllocateMemory による割り当て。RWX にすることが可能(設定に依存)
- NtProtectVirtualMemory の遷移(RW → RX)
- ヒープ領域内の実行可能メモリは疑わしい(設定に依存)
- モジュールストンピングはセクションハッシュの不一致で検出可能(設定に依存)
行動インジケーター
- 中断されたスレッドが作成され、コンテキストを取得した後に RIP の値が変更される
- ヒープメモリが実行可能としてマークされる(メモリ割り当てがヒープの場合)
- DLL が
DONT_RESOLVE_DLL_REFERENCES で読み込まれる(メモリ割り当てがモジュールストンピングの場合)
- ntdll の .text セクションが変更される(アンフッキングが有効な場合)
使用方法
スクリプトの読み込み
Cobalt Strike → Script Manager → Load → BOF_RunPe.cna
Aggressor コマンド
beacon> runpe /path/to/binary.exe --arg1 value1


コンパイル
GCC 13(mingw-w64)が必要です。付属の Dockerfile を使用してください:
sudo docker build -t ubuntu-gcc-13 .
sudo docker run --rm -it -v "$PWD":/work -w /work ubuntu-gcc-13:latest make
出力: Bin/runpe.o
制限事項
| Limitation | Description |
|---|
| CET | Control-flow Enforcement Technology が合成スタックフレームをブロックする可能性があります |
| x64 のみ | x86/WoW64 はサポートされていません |
クレジット / 開発に使用したリソース
リポジトリ/ブログ記事
書籍
Windows Native API Programming(著: Pavel Yosifovich)
Windows Internals, Part 1(著: Pavel Yosifovich)
Windows Internals, Part 2(著: Andrea Allievi)