
コンソールを作成せずに Cobalt Strike Beacon 上で PE を実行する BOF
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 │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
printf/WriteConsole フックを介して取得されますBOF の動作は、Additionals postex -> RunPe Config で編集できます。

| Method | Description |
|---|---|
None | 直接 API 呼び出し |
Draugr | スタックスプーフィングされた API 呼び出し |
Regwait | RegisterWaitForSingleObject コールバック |
Timer | Timer Queue コールバック |
| Method | Description |
|---|---|
Heap | Draugr を使用した RtlCreateHeap によるプライベートヒープ |
VirtualAlloc | Draugr を使用した NtAllocateVirtualMemory |
Module stomping | 正規 DLL の .text セクションを上書き |
| Option | Description |
|---|---|
AllocRWX | RWX として割り当て(RW→RX 遷移の代わりに) |
UnhookNtdll | ntdll.dll の .text をディスクからの新しいコピーに置き換え |
Timeout | 実行タイムアウト(ミリ秒単位、0 = 無制限) |
StompModule | モジュールストンピング用 DLL パス(例: chakra.dll) |
| Option | Description |
|---|---|
ModuleName | 開始アドレス用の正規モジュール(例: Kernel32.dll) |
ProcedureName | モジュール内の関数名(例: BaseThreadInitThunk) |
Offset | 関数先頭からのオフセット |
すべての PE 出力は IAT フックを介して beacon コンソールにリダイレクトされます。コンソールウィンドウや名前付きパイプは作成されません。
| Hooked Function | Target |
|---|---|
GetCommandLineA/W | スプーフィングされた引数を返す |
__getmainargs / __wgetmainargs | CRT 引数の初期化 |
printf / wprintf | BeaconPrintf へのリダイレクト |
WriteConsoleA/W | BeaconPrintf へのリダイレクト |
__stdio_common_vfprintf | UCRT の print 関数 |
ExitProcess / exit | ExitThread に変換 |
| Technique | Bypasses |
|---|---|
| 間接システムコール | ユーザーランド API フック(EDR/AV) |
| Draugr スタックスプーフィング | コールスタック検査 |
| スレッド開始アドレスのスプーフィング | スレッド開始アドレスの分析 |
| モジュールストンピング | バックされていないメモリの検出 |
| プライベートヒープ割り当て | VirtualAlloc の監視 |
| Ntdll アンフッキング | ディスク上の ntdll でメモリ内 ntdll を上書き |
| IAT フッキング(パイプなし) | 名前付きパイプの監視 |
NtGetContextThread / NtSetContextThread:
メモリ操作:
DONT_RESOLVE_DLL_REFERENCES で読み込まれる(メモリ割り当てがモジュールストンピングの場合)Cobalt Strike → Script Manager → Load → BOF_RunPe.cna
beacon> runpe /path/to/binary.exe --arg1 value1

beacon> help runpe

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 はサポートされていません |
| カーネル可視性 | スレッド作成がカーネルコールバックに可視 |
| .NET | マネージド実行ファイルはサポートされていません |
Windows Native API Programming(著: Pavel Yosifovich)Windows Internals, Part 1(著: Pavel Yosifovich)Windows Internals, Part 2(著: Andrea Allievi)