BOF-PE: New PE Concept Revolutionizes C2 Capabilities with Full C++ Support

Beacon Object File (BOF) support has been at the cornerstone of capability for any modern C2 platform since its inception by Cobalt Strike 4.1 back in 2020. It was a major step forward towards integrating a modular and extensible design whilst still being able to interact with the C2 platform itself via the Beacon API.

After five years of development using this approach, cracks in the design have begun to show. Complex BOFs become difficult to maintain and the lack of higher level language support (such as the C++ STL library and exceptions) can make source code bloated. So why can we not use uber new C++20 features but also execute from memory in a native fashion whilst maintaining integration with the Beacon API?

C2 Platforms

Well, this proposal will hopefully allow just that. In this article, I propose a reference design for a new BOF portable executable (PE) concept that will hopefully solve some of the current constraints and issues faced by BOF developers. Features include:

  • The ability to run the same linked EXE standalone or within a C2 environment
  • Full support for C++ and exceptions are possible
  • Symbol resolution issues disappear
  • Code will be easier to maintain vs the traditional BOF design

How would it work?

BOF PE source will include the beacon.h header as normal, but there will now be an additional import library, beacon.lib that developers will be required to link during compilation. This will create a dependency on beacon.dll for the linked BOF PE. For standalone execution, this DLL acts as the beacon compatibility layer. Both beacon.dll and the BOF PE executable will be required in the same folder to execute. Typically, the compatibility layer will write program output to stdout instead of writing the data over the C2 channel.

When executing under a C2 agent, this beacon compatibility layer is no longer required. During processing of the BOF PE DLL imports, whenever functions imported from beacon.dll are found, they are plugged into that specific C2 provider’s API calls directly as would typically happen under traditional BOF execution. The beacon.dll file is not resolved or loaded from disk at all. All other DLLs are processed as normal imports and are resolved accordingly.

Download & Use