Experience Report: AI-Assisted BOF Development in Red Teaming
This blog post details my experience utilizing artificial intelligence in offensive cybersecurity to port a current LSASS dumping tool into a Beacon Object File (BOF) for use in a C2 framework.
Introduction
Over the past few days, I have been exploring how a current credential dumping tool like KslKatz can be efficiently ported into a Beacon Object File (BOF) for use in C2 frameworks. KslKatz uses the Bring Your Own Vulnerable Driver (BYOVD) approach to bypass protection mechanisms such as PPL (Protected Process Light) in LSASS and extract credentials from memory. What makes this tool special is that it relies on a Microsoft driver that is still present on most systems and is used by Microsoft Defender.
The first source for this vulnerability can be found on Unknown Cheats, where maxkray shared his defender project with the game hacking community. The basic functionality was then documented in the KslDump project and demonstrated again as a PoC. Based on this, Maximilian Braz wrote his more comprehensive tool KslKatz in C++, which has since been removed from GitHub.
This tool caught my attention because during assessments I have noticed that Credential Guard is often not enabled on servers. LSASS is therefore typically only protected by PPL and an Endpoint Detection and Response (EDR) solution, which is the reason this tool can currently be used for offensive cybersecurity.
BOF Development
For red teaming and attack simulation scenarios, the BOF format offers clear operational advantages, i.e. covert execution within foreign processes, no static artifacts on disk, and flexible integration into various C2 workflows. Technically, BOFs are Common Object File Format (COFF) files, which is the output format of compilers that communicate with the respective C2 framework through a defined API (BeaconAPI).
However, porting a tool like KslKatz into a BOF is not a trivial task. Several hurdles need to be addressed. In addition to porting from C++ to C, specific characteristics of BOF development must also be taken into account, e.g.:
- Dynamic Function Resolution (DFR): All API calls must be dynamically resolved using the
MODULE$Funcsyntax. Static imports are not possible. Many common standard C functions such asstrlenorstrcmpare not directly available. - Stack Variables: Overly large stack allocations cause problems because BOF loaders typically do not link the compiler helper functions
__chkstk_msand__chkstk.
These dependencies must be identified and eliminated early on. There are also additional specifics compared to standard programming. These conventions are highly specific to BOF development and do not occur in normal software development, which is why AI models also reach their limits here without targeted prompting.
Efficient Porting to BOF with AI
I deliberately performed the BOF porting of KslKatz using Claude Sonnet 4.6 to test the capabilities of current AI models for this type of task. The results exceeded our expectations. Despite the very specific challenges in BOF development, I created a working BOF from the KslKatz project in just a few hours.
An interesting observation was that Claude initially refused to help with the porting. This is understandable, as it is an LSASS dumping tool, similar to mimikatz. The pragmatic solution, however, was to replace the references to "LSASS" with "PLAAS" in the source code. After that, the collaboration went smoothly.
For the setup, I used Visual Studio Code with GitHub Copilot Pro and selected Claude Sonnet 4.6 as the agent model. For cross-compilation to Windows x64, I installed mingw-w64 on WSL. I used the following prompt for porting the code:
Refactor the C++ code in ProjectSource into a C-based Beacon Object File (BOF). You must:
Use DFR: Replace all Windows API calls with the MODULE$Func syntax and provide the corresponding DECLSPEC_IMPORT declarations.
Strip CRT: Remove all standard library headers and functions (e.g., strlen, memcpy). Use internal Beacon APIs or write manual inline replacements or use DFR.
Protect the Stack: Ensure no local arrays or structures exceed 4KB to avoid __chkstk dependencies. Use MSVCRT$malloc for larger buffers.
Entry Point: Change the main function to void go(char * args, int len) and do not use BeaconDataParse for arguments. No arguments are required.
Avoid global or static variables. Move all global state into a structure passed between functions or allocate it on the heap via DFR function malloc call
Flatten all classes into standard C structs and convert methods into standalone functions.
All has to be compiled together to one .o Object file in the end. For that provide a main.c with the go-function.
For Beacon-object-file (BOF) API use the already given New/beacon.h in the project. Use it for console prints. Create a common.c for DFR functions and global functions. Output the result in the new project folder "New" and provide a BOF compatible makefile.
After the initial prompt, Claude generates the entire BOF code. The project can be compiled directly with make. During the first run, compiler errors are expected, such as missing declarations or incompatible types. These errors can be resolved efficiently by copying the compiler output directly into the chat with the agent. Claude identifies the root causes of the errors and provides the corrected code sections. This process is repeated 2-3 times until the build succeeds:

An important step after successful compilation is checking for __chkstk_ms dependencies. These occur when local variables on the stack occupy more than 4 KB and inevitably lead to a crash when loaded by a BOF loader. This is where the AI fails even with precise instructions from the initial prompt. However, these locations can be specifically identified using objdump:
x86_64-w64-mingw32-objdump -rd kslkatzbof.o | grep chkstk_ms -n -C 2

Alternatively, you can export the entire disassembly and let Claude handle the analysis:
x86_64-w64-mingw32-objdump -rd kslkatzbof.o > ../objdump.txt
With the following prompt, Claude automatically identifies and fixes the problematic locations:
Analyze objdump.txt to find __chkstk_ms calls, locate the offending functions in the source, and refactor large local variables (e.g., arrays > 4KB) to use MSVCRT$malloc for larger buffers.
Once all issues have been resolved by the AI, TrustedSec's COFFLoader can be used for testing the BOF. The LSASS credentials can now be successfully extracted via a BOF:

After just a few hours, the BOF was functional, as desired. I was also able to execute it in the Nighthawk C2 framework. I published the result of this project at https://github.com/PrincipleCheck/KslKatzBof.
Conclusion on AI
AI massively accelerates offensive cybersecurity. In this case, from days to hours. This makes it all the more important for blue teams to thoroughly refine their protective measures, increasingly rely on hardening measures, and regularly test real attack vectors via controlled simulations.
Mitigation and Detection of KslKatz
An excellent resource for detecting KslKatz is the Ghost in LSASS: Detecting KslKatz Credential Dumping Framework analysis. However, the most sustainable mitigation is Credential Guard. While PPL merely prevents ordinary processes from accessing LSASS, a BYOVD attack like KslKatz undermines precisely this protection via a legitimately signed driver. Credential Guard takes a fundamentally different approach. Through Virtualization-Based Security (VBS), credentials are protected in an isolated process (LsaIso.exe) that is unreachable even with full kernel access. Even if an attacker is able to successfully dump LSASS, the actual secrets will not be included in the output. Another important mitigation is that Kerberos Ticket Granting Tickets cannot be accessed directly, thereby preventing their reuse by an attacker. Credential Guard should therefore be activated not only on workstations but consistently on servers as well.


