The Hidden ART Of Rolling Shellcode Decryption - Tijme Gommers

Tijme Gommers (Offensive Cyber Security Engineer · ABN AMRO Bank)

Nullcon Goa 2025 · Main Stage

Overview

This talk, "The Hidden ART Of Rolling Shellcode Decryption," presented by Tijme Gommers, delves into advanced techniques for loading shellcode into memory while actively evading detection by modern security solutions. Primarily aimed at offensive security engineers or red teamers who routinely deploy shellcode, the research explores novel methods to keep malicious payloads hidden. However, it also provides crucial insights for defensive security engineers and SOC analysts seeking to understand and detect sophisticated shellcode loading techniques that may emerge in future threats.

Watch on YouTube

Visual summary for The Hidden ART Of Rolling Shellcode Decryption - Tijme Gommers by Tijme Gommers
Visual summary for The Hidden ART Of Rolling Shellcode Decryption - Tijme Gommers by Tijme Gommers

Key moments

  1. 0:00 Introduction: Kong Loader & Rolling Shellcode Decryption
  2. 2:10 Inspiration: Michael's Rolling Decryption Proof of Concept
  3. 3:30 Understanding Position Dependent vs. Independent Shellcode
  4. 5:45 Reflective Loading and Donut for Position Independent Code
  5. 6:50 Challenges: EDR/AV Detection of Traditional Shellcode Loading

The Hidden ART Of Rolling Shellcode Decryption - Tijme Gommers

Speakers: Tijme Gommers, Offensive Cyber Security Engineer, ABN Amro Bank

Conference: Nullcon

YouTube: https://www.youtube.com/watch?v=K3OY-ZNmMxo

Overview

This talk, "The Hidden ART Of Rolling Shellcode Decryption," presented by Tijme Gommers, delves into advanced techniques for loading shellcode into memory while actively evading detection by modern security solutions. Primarily aimed at offensive security engineers or red teamers who routinely deploy shellcode, the research explores novel methods to keep malicious payloads hidden. However, it also provides crucial insights for defensive security engineers and SOC analysts seeking to understand and detect sophisticated shellcode loading techniques that may emerge in future threats.

Gommers highlights the limitations of existing evasion methods, such as traditional sleep masks, and introduces a more dynamic and stealthy approach: rolling shellcode decryption. This technique ensures that only a minimal portion of the shellcode is ever decrypted in memory at any given time, significantly reducing the window of opportunity for detection. While acknowledging that the research is still ongoing, the promising results presented offer valuable strategies for both offensive operations and the development of more robust defensive countermeasures.

The core of the presentation revolves around Kungloader, a proof-of-concept tool developed by Gommers that implements this rolling decryption. The talk not only details the technical intricacies of Kungloader but also contrasts it with similar prior work, showcasing its performance advantages and enhanced evasion capabilities. This deep dive into the art of dynamic shellcode obfuscation provides a forward-looking perspective on the evolving cat-and-mouse game between attackers and defenders.

Background

▶ Watch: Introduction: Kong Loader & Rolling Shellcode Decryption (0:00)

To appreciate the significance of rolling shellcode decryption, it's essential to understand the fundamentals of shellcode and the challenges of loading it undetected. Shellcode can broadly be categorized into two types: position dependent code and position independent code (PIC). Position dependent code, typical of standard compiled programs, relies on fixed memory addresses for its data and functions. When extracted and injected into an arbitrary memory location in another process, it often crashes because its internal references point to invalid or non-existent memory segments.

To circumvent this, position independent code (PIC) is used. PIC is designed to execute correctly regardless of its base address in memory. While writing complex PIC directly is arduous, tools like TheWack0lian's Donut (often referred to simply as Donut) offer a solution. Donut wraps existing position dependent executables or .NET assemblies with a PIC stub, allowing them to be loaded as shellcode. However, this convenience comes at a cost: the resulting shellcode becomes significantly larger, making it less ideal for red teamers who prioritize small, nimble payloads.

Regardless of how shellcode is generated, the traditional loading process involves several steps: defining the shellcode as a byte array, allocating a read-write-execute (RWX) memory segment, copying the shellcode into this segment, and then executing it. This method, while simple, is highly susceptible to detection. Endpoint Detection and Response (EDR) and antivirus solutions employ various mechanisms:

  • Initial memory scan: On execution, EDRs scan newly allocated RWX memory for known malicious signatures.
  • Behavioral analysis: If the shellcode performs malicious actions (e.g., a C2 beacon connecting to a server), EDRs trigger alerts based on observed behavior.
  • Continuous scans: Many EDRs periodically scan memory segments, potentially catching shellcode that has been decrypted for an extended period.

To combat these detections, sleep masks emerged as a common evasion technique. A sleep mask works by decrypting the entire shellcode into memory, executing a command, and then re-encrypting the shellcode before "sleeping" for a predefined duration (e.g., 30 seconds) to reduce network traffic and memory footprint. While effective at minimizing the time the shellcode is in plaintext, a critical vulnerability remains: during active execution, especially for long-running commands like SharpHound or extensive data exfiltration, the entire shellcode is fully decrypted and vulnerable to detection. This persistent window of exposure is the fundamental problem that Kungloader and the concept of rolling shellcode decryption aim to resolve.

Key Findings

▶ Watch: Inspiration: Michael's Rolling Decryption Proof of Concept (2:10)

The central finding of this research is the viability and enhanced stealth offered by rolling shellcode decryption, a technique that ensures only a single instruction of the shellcode is decrypted at any given moment. This drastically shrinks the detection window compared to traditional sleep masks. The initial spark for this concept came from a colleague, Michael, who quickly built a proof-of-concept demonstrating that even a two-instruction shellcode could be executed while never being entirely in plaintext in memory. This confirmed the core premise: it's possible to execute encrypted code by decrypting it just-in-time.

Tijme Gommers then extended this idea with Kungloader, aiming to support full C2 framework beacons. The key technical contribution of Kungloader lies in its sophisticated implementation using hardware breakpoints and Vector Exception Handling (VEH). This approach allows the system to trigger an exception before each instruction, enabling the loader to decrypt the current instruction, execute it, and then re-encrypt it, all while moving to the next.

A significant finding during Kungloader's development was the performance bottleneck encountered by similar projects, such as VoidGate. VoidGate utilized a trap flag approach, which breaks on every CPU instruction, leading to millions of breakpoints even for simple tasks and making execution extremely slow. Kungloader overcomes this by intelligently placing breakpoints only where necessary, primarily at the start of each shellcode instruction or at the return addresses of external function calls. This optimization drastically improves execution speed, reducing breakpoints for a "Hello World" shellcode from 13 million in VoidGate to just 2,000 in Kungloader.

Furthermore, Kungloader addresses complex scenarios like "fake encryption states" (where shellcode contains embedded data that needs decryption) and "fake execution states" (multi-threaded shellcode). By leveraging a tiny disassembler called Sydis within the exception handler, Kungloader can dynamically interpret instructions and adapt its decryption strategy, ensuring both data and execution integrity across various shellcode types. The research demonstrates that Kungloader, in its current state, provides a highly effective obfuscation layer, allowing common msfvenom payloads and custom C2 beacons to run undetected by Microsoft Defender for Endpoint.

Technical Deep Dive

▶ Watch: Understanding Position Dependent vs. Independent Shellcode (3:30)

The technical core of Kungloader's rolling shellcode decryption lies in the precise orchestration of Vector Exception Handling (VEH) and hardware breakpoints. The process begins by registering a custom exception handler function using AddVectoredExceptionHandler. This function will be invoked whenever a CPU exception occurs within the process. Crucially, a hardware breakpoint is then set on the very first instruction of the encrypted shellcode.

Hardware breakpoints differ from software breakpoints (like int3) in that they are managed by the CPU's debug registers and do not modify the code itself. Kungloader uses the GetThreadContext Windows API function to access the current thread's context, specifically the debug registers. The address of the first instruction is placed in dr0, and dr7 is configured to enable this breakpoint. When execution reaches this address, a breakpoint exception is triggered, and Kungloader's registered VEH function takes control.

Inside the exception handler, the logic unfolds as follows:

  1. Re-encryption of Previous Instruction: If a previous instruction was decrypted and executed, it is immediately re-encrypted to maintain stealth.
  2. Decryption of Current Instruction: The instruction at the current program counter (where the breakpoint occurred) is decrypted. Given that x86/x64 instructions vary in length, Kungloader decrypts a maximum of 16 bytes, which is the longest possible x86-64 instruction. While this brief plaintext window exists, it's too small and dynamic for effective signature-based detection.
  3. Calculation of Next Breakpoint: This is where Kungloader significantly diverges from less efficient methods like VoidGate's trap flag. Instead of breaking on every single instruction, Kungloader intelligently determines the address of the next instruction to breakpoint. For simple sequential code, this is straightforward. However, for CALL or JMP instructions, especially those targeting external Windows API functions, a more sophisticated approach is required.

To handle these control flow changes efficiently, Kungloader embeds Sydis, a tiny disassembler. When a CALL or JMP instruction is encountered:

  • If the target address is within the shellcode, a breakpoint is set directly on that target.
  • If the target address is outside the shellcode (e.g., a Windows API call), Kungloader calculates the expected return address of that external function. A breakpoint is then set at this return address. This prevents Kungloader from needlessly breaking on every instruction within the Windows API call, which would cause significant performance degradation (as seen in VoidGate, where a "Hello World" required 13 million breakpoints, while Kungloader achieved it in 2,000).

After decrypting the current instruction and setting the next breakpoint, the exception handler returns EXCEPTION_CONTINUE_EXECUTION, allowing the CPU to execute the now-decrypted instruction and seamlessly continue the program flow.

Beyond basic instruction execution, Kungloader also tackles two critical challenges:

  • Fake Encryption States (Data in Shellcode): Many msfvenom payloads embed strings or other data (e.g., cmd.exe arguments) directly within the shellcode's instruction stream. If a MOV instruction attempts to access this data while it's encrypted, the program will crash or produce garbage. Kungloader addresses this by using Sydis to identify MOV instructions. If the MOV instruction's source operand points to an address within the shellcode, Kungloader decrypts the necessary data bytes. For strings, it decrypts byte-by-byte until a null terminator is found. For other data types, it can leverage function signatures (or Windows debug symbols) to determine the size of the argument being passed to a Windows API function, then decrypt that specific number of bytes.
  • Fake Execution States (Multi-threading): Shellcode that spawns new threads using CreateThread poses a problem, as Kungloader's breakpoint mechanism is thread-specific. If one thread decrypts an instruction while another thread, unaware of Kungloader's state, re-encrypts it, the first thread will attempt to execute encrypted code and crash. The solution implemented in Kungloader is to duplicate the entire shellcode instance (including its current encryption state) in memory when CreateThread is called. The newly created thread is then directed to execute from this duplicated, independent copy of the shellcode. This allows both threads to decrypt and encrypt their respective instruction streams without interfering with each other.

While Kungloader's current implementation, with its reliance on Sydis and instruction interpretation, introduces some overhead, the speaker notes that future work aims to mitigate this. The long-term vision is to move much of this dynamic interpretation from runtime to compile time. This would involve "transpiling" the shellcode into an enriched format, pre-calculating instruction sizes and next breakpoint addresses, effectively turning Kungloader into a highly optimized, custom virtual machine (VM) for the shellcode, akin to techniques seen in VMProtect used by advanced threat actors. This would eliminate the runtime disassembler, making Kungloader significantly faster and even more difficult to detect.

Demo / Proof of Concept

▶ Watch: Reflective Loading and Donut for Position Independent Code (5:45)

Tijme Gommers showcased the effectiveness of Kungloader through three distinct demonstrations, highlighting its ability to execute various types of shellcode undetected by Microsoft Defender for Endpoint.

The first demonstration involved a simple msfvenom payload: win_x64/exec with the command line calc.exe. Upon execution of Kungloader, a calculator instance immediately popped up. The debug output from Kungloader clearly showed that the win_x64/exec payload was called, and the size of the cmd.exe argument was correctly guessed based on the presence of a null terminator, demonstrating Kungloader's ability to handle embedded string data within shellcode.

The second demo escalated to a more complex msfvenom payload: a win_x64/reverse_tcp shell. This payload typically takes around 30 seconds to launch a beacon, a delay that was sped up in the video for brevity. The demonstration successfully established a fully working shell, providing an incoming connection to the attacker's listener. Crucially, this was performed on a machine running Microsoft Defender for Endpoint, a prominent EDR solution. The msfvenom payloads, which are often heavily signatured through static analysis, emulators, dynamic analysis, and cloud sandboxes, ran completely undetected, underscoring Kungloader's robust evasion capabilities.

The final demonstration featured a custom Nant C2 payload. Nant C2 is a command-and-control framework developed by a colleague of Gommers. For this specific project, Gommers developed a truly position independent code version of the Nant C2 beacon, significantly smaller than reflective loading approaches. This demo also included an artificial delay, a common red teaming tactic to avoid immediate execution and reduce detection chances. After the delay, a beacon successfully checked in, and the attacker was able to interact with it, executing commands like whoami, which confirmed administrator privileges. Again, Microsoft Defender for Endpoint failed to detect the Nant C2 beacon, reinforcing Kungloader's stealth. The QR code for the Nant C2 beacon was also provided, indicating its availability on GitHub.

These demonstrations collectively proved that Kungloader, even in its current experimental state, is a viable tool for obfuscating and executing sophisticated shellcode, effectively bypassing prevalent EDR solutions.

Defensive Implications

▶ Watch: Challenges: EDR/AV Detection of Traditional Shellcode Loading (6:50)

The Kungloader technique presents significant challenges for defensive security engineers and SOC analysts, as its design actively thwarts common detection methodologies.

  • Sandbox Evasion: Traditional isolated sandboxes struggle with Kungloader. The constant stream of exceptions generated by the hardware breakpoints and Vector Exception Handling (VEH) significantly slows down execution within these environments. This makes it difficult for sandboxes to complete execution within typical analysis timeouts or to perform meaningful behavioral analysis, as the sheer volume of exceptions can overwhelm their processing capabilities.
  • Debugger Resistance: Debugging Kungloader with tools like WinDbg is also problematic. Each instruction execution triggers a breakpoint, leading to millions of breakpoint events. Manually clicking "continue" a million times is impractical. While automation or ignoring exceptions is possible, ignoring the exceptions prevents Kungloader's decryption/encryption logic from functioning, causing the shellcode to crash. Even using specific WinDbg commands like sxi s (which allows the VEH to handle exceptions while WinDbg continues) leads to an exponential slowdown, making analysis exceedingly difficult.
  • EDR Blind Spots: Perhaps the most critical implication is Kungloader's current ability to bypass leading EDR solutions. As demonstrated, Microsoft Defender for Endpoint did not detect Kungloader executing msfvenom payloads or custom C2 beacons. This indicates a significant gap in current EDR capabilities regarding dynamic, rolling shellcode decryption. While defenders could attempt to detect Kungloader's native code (e.g., the loader itself), this doesn't confirm the maliciousness of the embedded shellcode. A legitimate Kungloader could theoretically exist, leading to false positives if only the loader is detected.

To counter Kungloader, defenders might consider:

  • YARA Rule Development: A potential detection strategy involves creating YARA rules to identify specific characteristics of Kungloader's native code. For example, a rule could look for the combination of AddVectoredExceptionHandler calls, the inclusion of the Sydis disassembler, and the creation of read-write-execute (RWX) memory pages.
  • Adversary Countermeasures: However, attackers can quickly adapt. The use of a polymorphic engine during Kungloader's compilation phase could randomize assembly instructions and code structure, making static YARA signatures unreliable and easily bypassed.
  • Future Detection Research: The talk points to future work for Kungloader involving compile-time transpilation, which would transform it into a highly efficient, custom virtual machine (VM) for shellcode execution. This evolution would further complicate detection, pushing the boundaries of what EDRs can discern. Defenders will need to research and develop new techniques to identify the unique execution patterns of such virtualized malware, rather than relying on traditional signature or behavior-based detections.

Ultimately, Kungloader highlights a growing need for EDRs to move beyond static and simple dynamic analysis, towards more sophisticated runtime introspection and potentially even hardware-assisted monitoring to identify these deeply obfuscated execution flows.

Key Takeaways

  • Rolling shellcode decryption offers a significant leap in stealth for shellcode execution by ensuring only one instruction is decrypted in memory at a time, drastically reducing detection windows compared to traditional sleep masks.
  • The technique relies on sophisticated use of hardware breakpoints and Vector Exception Handling (VEH), which allow for just-in-time decryption and re-encryption of individual instructions.
  • Intelligent breakpoint placement, aided by a tiny disassembler like Sydis, is crucial for performance, avoiding the slowness of trap flag approaches and efficiently handling external Windows API calls.
  • Kungloader addresses complex scenarios such as fake encryption states (embedded data within shellcode) and fake execution states (multi-threaded shellcode) through dynamic instruction interpretation and shellcode duplication.
  • Current EDR solutions, including Microsoft Defender for Endpoint, are shown to be ineffective against Kungloader in its present form, posing a significant challenge for defenders and highlighting a gap in existing detection capabilities.
  • Future advancements, such as compile-time transpilation into a custom virtual machine, aim to further enhance Kungloader's performance and evasiveness, pushing the boundaries of malware obfuscation.

About the Speaker(s)

Tijme Gommers is an experienced Offensive Cyber Security Engineer at ABN Amro Bank, where he conducts much of his cutting-edge research. In addition to his role at the bank, he is also involved in digital forensics for "Hunted," a Dutch national television show. With a background spanning six to seven years in red teaming operations, Tijme brings extensive hands-on experience in building exploits and malware, many of which he has published on his GitHub profile. His work on Kungloader stems directly from his practical need to load shellcode undetected during red team engagements.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

Gommers presents original, working research on instruction-granular shellcode decryption via hardware breakpoints and VEH — a meaningful evolution past sleep masks with a functional PoC that bypasses MDE on demo day. The engineering decisions are explained at the right level of abstraction, and the performance comparison against VoidGate's trap-flag approach (13M vs 2K breakpoints) gives the novelty claim real teeth.

Heather Calloway (CISO) — WEAK

Technically credible offensive research with a genuine EDR gap finding, but it never crosses the line into defender utility. The talk identifies a real detection problem and stops there — no detection engineering guidance, no institutional response framing, no answer to the question a security leader actually needs to ask: what do I do about this?

→ Top-rated talks at Nullcon Goa 2025

All talks from Nullcon Goa 2025