BOF_RunPE
BOF RunPE is a Beacon Object File for Cobalt Strike that executes PE files entirely in-memory within the beacon process. Unlike traditional fork&run, no child process is spawned, no console is created, and no pipe is used - all output is captured via IAT hooking and redirected to the beacon console.
Architecture: x64 only
Overview
┌──────────────────────────────────────────────────────────────┐
│ 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 │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Key Features
- No Process Creation: PE runs inside the beacon process
- No Console/Pipe: Output captured via
printf/WriteConsole hooks
- Multiple Allocation Methods: Heap, VirtualAlloc, Module Stomping
- Proxy Loading: Timer Queue, RegisterWait, or direct calls
- Ntdll Unhooking: Optional fresh copy from disk
- RWX : Optional allocate memory in RWX
- Thread Start Spoofing: Legitimate start address with RIP hijacking
Configuration Options
The behaviorus of BOF can be edited in Additionals postex -> RunPe Config

Proxy Methods
| Method | Description |
|---|
None | Direct API calls |
Draugr | Stack spoofed API calls |
Regwait |
Allocation Methods
| Method | Description |
|---|
Heap | Private heap via RtlCreateHeap with Draugr |
VirtualAlloc | NtAllocateVirtualMemory with Draugr |
Module stomping | Overwrites legitimate DLL .text section |
General Options
Thread Spoofing
| Option | Description |
|---|
ModuleName | Legitimate module for start address (e.g., Kernel32.dll) |
ProcedureName | Function name within module (e.g., ) |
Output Capture
All PE output is redirected to the beacon console via IAT hooks. No console window or named pipe is created.
Evasion Techniques
Detection Vectors
Kernel Telemetry (ETW-TI)
NtGetContextThread / NtSetContextThread:
- Thread context manipulation on suspended threads then resume it
Memory Operations:
- NtAllocateMemory allocation, can be in RWX (depend with config)
- NtProtectVirtualMemory transitions (RW → RX)
- Executable memory in heap regions is suspicious (depend with config)
- Module stomping detectable via section hash mismatch (depend with config)
Behavioral Indicators
- Suspended thread created, take the context then change the value of RIP
- Heap memory marked as executable (if memory allocator is heap)
- DLL loaded with
DONT_RESOLVE_DLL_REFERENCES (if memory allocator is module stomping)
- Ntdll .text section modified (if unhooking enabled)
Usage
Loading the Script
Cobalt Strike → Script Manager → Load → BOF_RunPe.cna
Aggressor Commands
beacon> runpe /path/to/binary.exe --arg1 value1


Compilation
Requires GCC 13 (mingw-w64). Use provided Dockerfile:
sudo docker build -t ubuntu-gcc-13 .
sudo docker run --rm -it -v "$PWD":/work -w /work ubuntu-gcc-13:latest make
Output: Bin/runpe.o
Limitations
| Limitation | Description |
|---|
| CET | Control-flow Enforcement Technology may block synthetic stack frames |
| x64 Only |
Credits / Ressources use for dev
Repos/blogpost
Books
Windows Native API Programming by Pavel Yosifovich
Windows Internals, Part 1 by Pavel Yosifovich
Windows Internals, Part 2 by Andrea Allievi