Skip to content
This repository was archived by the owner on Apr 8, 2025. It is now read-only.
/ bof-loader Public archive

Loader library for Cobalt Strike Beacon Object Files (BOFs), without dependencies to the CRT or standard library. Suitable for use in shellcode projects.

License

Notifications You must be signed in to change notification settings

cirosec/bof-loader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Beacon Object File (BOF) Runtime/Loader

This project implements a Beacon Object File (BOF) Runtime/Loader intended to be ran on Windows. It is heavily inspired by https://github.com/trustedsec/COFFLoader (almost all of the relocation code is from there).

The special feature of this loader compared to other loaders is that this implementation is suitable for use as position independent (shell)code ("PIC")! This is achieved by following these restrictions:

  • No non-const globals are used. This means that there is no writable .data section that needs to be merged into the shellcode.
  • The functions of the C Standard Library are not used - the required functions are implemented by the loader itself. Other dependencies (e.g. VirtualAlloc) can (and must) be loaded outside the loader and passed to it. This makes it more flexible, since the function loading process can be done by different means.
  • Heap usage is avoided as far as possible. Most variables reside on the stack. This makes memory scans more difficult for EDR software.

Another difference to other loaders is the fact that the beacon API functions must be implemented by the user, not the loader itself. This makes it way easier (but also more time consuming) to integrate the loader in your own projects, e.g. your own C2 agent, and use the agent code within the API implementations.

The loader also allows the definition of an own function to resolve external functions from the Windows API. It does not do any LoadLibrary or GetProcAddress by itself.

The following Beacon APIs are currently supported (more can be added easily):

  • Data Parser API
  • Format API
  • Output API
  • Token API
  • Utility functions

This project was part of the master's thesis written by Leon Schmidt:

@thesis{Schmidt2025,
  author      = {Schmidt, Leon},
  title       = {Enhancing Command & Control Capabilities: Integrating Cobalt Strike's Plugin System into a Mythic-based Beacon Developed at cirosec},
  institution = {University of Applied Sciences Offenburg, Faculty EMI},
  year        = {2025},
  language    = {en}
}

Building

The Loader resides within the "BOFLoader" Visual Studio Project and is built with clang-cl as a static Windows library (.lib). This means that linking takes place in your own application, not within the loader project!

The project "TestMain" is a small test program that uses the BOF loader project. It thus implements the compatibility layer functions and passes all external dependencies. It then loads a BOF from disk, and invokes the loader. The "TestMain" project can be used as a reference.

Using this project as a library

  1. Implement the beacon API functions
  2. Implement the resolver function (ResolveFunc_t)
  3. Store function pointers to required Windows functions in external_functions_ptr_t
  4. Store function pointers to beacon API implementations in cs_compat_functions_ptr_t
  5. Prepare BOF argument string with UnhexlifyArgs
  6. Execute the BOF with RunBOF, passing it the results from UnhexlifyArgs

You can consult the "TestMain" project in this repo, where all these steps were also done.

#include "BOFLoader.h"
#include "ExternalFuncs.h"
#include "my_beacon_apis.h" // implement the beacon APIs here

// simple resolve function example for DFR
static void *ResolveFunc(const char *lib, const char *func) {
    return GetProcAddress(LoadLibraryA(lib), func);
}

int execute_bof(const unsigned char *coff_file, int coff_size, const unsigned char *args) {
    // External functions (e.g. use the one from Windows.h or resolve them manually)
    external_functions_t external_functions = {
        (VirtualAlloc_t)VirtualAlloc,
        (VirtualFree_t)VirtualFree,
        (HeapAlloc_t)HeapAlloc,         // you can also use RtlAllocateHeap here
        (HeapFree_t)HeapFree,
        (GetProcessHeap_t)GetProcessHeap,
        (LoadLibraryA_t)LoadLibraryA,
        (GetModuleHandleA_t)GetModuleHandleA,
        (GetProcAddress_t)GetProcAddress,
        (FreeLibrary_t)FreeLibrary,
        (ResolveFunc_t)ResolveFunc      // this is the DFR resolv function
    };

    // CS Compat functions (a.k.a. beacon APIs)
    cs_compat_functions_t compat_functions = {
        (BeaconDataParse_t)BeaconDataParse,
        (BeaconDataInt_t)BeaconDataInt,
        (BeaconDataShort_t)BeaconDataShort, 
        (BeaconDataLength_t)BeaconDataLength,
        // all other functions ...
        (toWideChar_t)toWideChar 
    };

    // Prepare arguments
    int arg_size = 0;
    unsigned char *prepared_args = UnhexlifyArgs(
        &external_functions, 
        (unsigned char*)args,
        &arg_size
    );
      
    // Invoke BOF runtime
    int retcode = RunBOF(
        &external_functions, 
        &compat_functions,
        (char*)"go",
        (unsigned char*)coff_file,
        coff_size,
        prepared_args,
        arg_size
    );

    return retcode;
}

License and Credits

This project is licensed under the GNU Affero General Public License v3.0.

Parts of the code are based on COFFLoader by TrustedSec and used under a BSD-style license. All original rights and attributions remain with the respective authors. See third_party_licenses/ for details.

About

Loader library for Cobalt Strike Beacon Object Files (BOFs), without dependencies to the CRT or standard library. Suitable for use in shellcode projects.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published