
BOF для запуска PE в Cobalt Strike Beacon без создания консоли
BOF RunPE — это Beacon Object File для Cobalt Strike, который выполняет PE-файлы полностью в памяти внутри процесса beacon. В отличие от традиционного fork&run, не создается дочерний процесс, не создается консоль и не используется канал (pipe) — весь вывод захватывается через перехват 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

| Метод | Описание |
|---|---|
None | Прямые вызовы API |
Draugr | Вызовы API со спуфингом стека |
Regwait | Обратный вызов RegisterWaitForSingleObject |
Timer | Обратный вызов Timer Queue |
| Метод | Описание |
|---|---|
Heap | Приватная куча через RtlCreateHeap с Draugr |
VirtualAlloc | NtAllocateVirtualMemory с Draugr |
Module stomping | Перезапись секции .text легитимной DLL |
| Опция | Описание |
|---|---|
AllocRWX | Выделять как RWX (вместо перехода RW→RX) |
UnhookNtdll | Заменить .text ntdll.dll свежей копией с диска |
Timeout | Таймаут выполнения в миллисекундах (0 = бесконечно) |
StompModule | Путь к DLL для module stomping (например, chakra.dll) |
| Опция | Описание |
|---|---|
ModuleName | Легитимный модуль для стартового адреса (например, Kernel32.dll) |
ProcedureName | Имя функции внутри модуля (например, BaseThreadInitThunk) |
Offset | Смещение от начала функции |
Весь вывод PE перенаправляется в консоль beacon через перехваты IAT. Не создается ни окно консоли, ни именованный канал.
| Перехваченная функция | Цель |
|---|---|
GetCommandLineA/W | Возвращает подставные аргументы |
__getmainargs / __wgetmainargs | Инициализация аргументов CRT |
printf / wprintf | Перенаправление в BeaconPrintf |
WriteConsoleA/W | Перенаправление в BeaconPrintf |
__stdio_common_vfprintf | Функции печати UCRT |
ExitProcess / exit | Преобразуется в ExitThread |
| Техника | Обход чего |
|---|---|
| Косвенные системные вызовы | Перехваты API на уровне пользователя (EDR/AV) |
| Спуфинг стека Draugr | Анализ стека вызовов |
| Спуфинг стартового адреса потока | Анализ стартового адреса потока |
| Module Stomping | Обнаружение незакрепленной памяти |
| Выделение приватной кучи | Мониторинг VirtualAlloc |
| Снятие перехвата ntdll | Перезапись ntdll в памяти копией с диска |
| Перехват IAT (без каналов) | Мониторинг именованных каналов |
NtGetContextThread / NtSetContextThread:
Операции с памятью:
DONT_RESOLVE_DLL_REFERENCES (если распределитель памяти — module stomping)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
| Ограничение | Описание |
|---|---|
| CET | Технология Control-flow Enforcement может блокировать синтетические кадры стека |
| Только x64 | Нет поддержки x86/WoW64 |
| Видимость на уровне ядра | Создание потока видимо для callback-функций ядра |
| .NET | Управляемые исполняемые файлы не поддерживаются |
Windows Native API Programming — Pavel YosifovichWindows Internals, Part 1 — Pavel YosifovichWindows Internals, Part 2 — Andrea Allievi