Module 8: Full Chain, Detection & Comparison
Comparing Ekko, FOLIAGE, and ShellcodeFluctuation — detection vectors, Moneta/pe-sieve bypass results, limitations, and the state of the art.
Module Objective
Synthesize everything from the course into a complete end-to-end understanding. Compare ShellcodeFluctuation against Ekko and FOLIAGE, analyze real-world detection results from Moneta and pe-sieve, identify remaining detection vectors, understand fundamental limitations, and assess the current state of sleep evasion research.
1. The Complete Execution Chain
Here is the full end-to-end execution flow of ShellcodeFluctuation with ThreadStackSpoofer integration, from initial loading through multiple beacon cycles:
// ============================================
// PHASE 0: LOADER INITIALIZATION
// ============================================
// 1. Read shellcode (beacon.bin) from disk/resource
// 2. VirtualAlloc(NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)
// 3. memcpy(allocation, shellcode, size)
// 4. VirtualProtect(allocation, size, PAGE_EXECUTE_READ, &old)
// 5. Generate random XOR32 key
// 6. Resolve kernel32!Sleep via GetProcAddress
// 7. Install inline hook: Sleep -> MySleep
// 8. Save original bytes + hook bytes
// 9. (Optional) Register VEH for Mode 2
// 10. CreateThread(NULL, 0, allocation, NULL, 0, NULL)
// -> Beacon shellcode begins executing
// ============================================
// PHASE 1: BEACON ACTIVE (repeats each cycle)
// ============================================
// Beacon performs its check-in:
// - Connects to C2 server
// - Downloads tasks
// - Executes commands
// - Uploads results
// Duration: ~100ms
// ============================================
// PHASE 2: BEACON CALLS Sleep(interval)
// ============================================
// Beacon's sleep call is redirected to MySleep via inline hook
// ============================================
// PHASE 3: MySleep HANDLER
// ============================================
// 3a. Spoof stack: *_AddressOfReturnAddress() = 0
// 3b. VirtualProtect(shellcode, RW)
// 3c. xor32(shellcode, key) [encrypt]
// 3d. Unhook: restore original bytes to kernel32!Sleep
// 3e. Sleep(interval) [actual sleep - maximally hidden]
// 3f. Rehook: restore hook bytes to kernel32!Sleep
// 3g. xor32(shellcode, key) [decrypt]
// 3h. VirtualProtect(shellcode, RX)
// 3i. Restore stack: *_AddressOfReturnAddress() = origAddr
// ============================================
// PHASE 4: RETURN TO BEACON
// ============================================
// MySleep returns, Beacon resumes at next instruction
// -> Back to Phase 1
Full Lifecycle
Inject + Hook
C2 check-in
Encrypt+Spoof
Hidden state
Decrypt+Restore
2. Technique Comparison: Ekko vs FOLIAGE vs Fluctuation
Three prominent sleep evasion techniques take fundamentally different architectural approaches to the same problem:
| Property | Ekko (C5pider) | FOLIAGE (Austin Hudson) | ShellcodeFluctuation (mgeeky) |
|---|---|---|---|
| Sleep mechanism | Timer queue callbacks via CreateTimerQueueTimer | APC queuing with NtContinue context manipulation | Inline hook on kernel32!Sleep |
| Encryption | RC4 via SystemFunction032 | XOR or RC4 via ROP/APC chain | XOR32 (custom, no imports) |
| Protection change | Via timer callback to VirtualProtect | Via APC-queued NtProtectVirtualMemory | Direct VirtualProtect call in hook handler |
| Call stack | Clean — callbacks from ntdll!TppWorkerThread | Clean — NtContinue creates clean context | Requires ThreadStackSpoofer for clean stack |
| Code complexity | Moderate — chained timer callbacks | High — APC manipulation + context crafting | Low — straightforward hook handler |
| Hook IOC | No function hooks needed | No function hooks needed | Inline hook on Sleep (mitigated by unhooking) |
| CET compatible | No — uses ROP-like callback chains | Partially — NtContinue may be restricted | Yes — standard call/ret flow |
| Suspicious imports | SystemFunction032, CreateTimerQueueTimer | NtContinue, NtQueueApcThread | None beyond standard APIs |
3. Moneta Detection Results
Moneta is the gold standard for memory anomaly detection. Here are the actual detection results for each configuration:
Moneta Scan: Unprotected Beacon
// Moneta output for unprotected Cobalt Strike Beacon:
[!] SUSPICIOUS: Private executable memory
Process: beacon.exe (PID: 4832)
Region: 0x000001A00000 - 0x000001A4C000
Size: 0x4C000 (311,296 bytes)
Protect: PAGE_EXECUTE_READ
Type: MEM_PRIVATE
IOC: Abnormal private executable memory
Moneta Scan: Fluctuating Beacon (during sleep)
// Moneta output for ShellcodeFluctuation Mode 1 during sleep:
// Region 0x000001A00000 - 0x000001A4C000:
// Protect: PAGE_READWRITE
// Type: MEM_PRIVATE
// Content: Encrypted (no recognizable patterns)
// IOC: None - RW private memory is normal
// However, kernel32.dll shows:
[*] MODIFIED: kernel32.dll
Region: 0x00007FFB1A240000
IOC: Modified code (private working set page)
Note: Page modified but content matches disk
(hook was removed before sleep)
The fluctuating Beacon eliminates the "Abnormal private executable memory" IOC. The remaining IOC is the kernel32 private page artifact from the copy-on-write caused by the hook installation. Crucially, the content matches the on-disk file (because the hook bytes are restored), so the IOC is a weaker "private working set" anomaly rather than a clear "modified code" detection.
4. pe-sieve Detection Results
| Configuration | pe-sieve Result | Details |
|---|---|---|
| Unprotected Beacon | Detected | Shellcode found in private executable memory via implant scanning |
| Fluctuation Mode 1 (during sleep) | Not detected (shellcode) | Encrypted RW memory does not match any shellcode signatures |
| Fluctuation Mode 1 (during sleep) | Possible IOC (kernel32) | pe-sieve can detect that kernel32 has modified working set pages |
| Fluctuation Mode 2 (NOACCESS) | Not detected | NOACCESS memory cannot even be read by the scanner |
| Fluctuation + Stack Spoof | Not detected | Neither memory nor stack analysis reveals the implant |
5. BeaconEye Detection Results
BeaconEye specifically targets Cobalt Strike Beacon configuration structures in memory:
| Configuration | BeaconEye Result | Why |
|---|---|---|
| Unprotected Beacon | Detected | Single-byte XOR config found via brute force (256 keys) |
| Fluctuation Mode 1 (during sleep) | Not detected | XOR32 encryption with ~4.3 billion possible keys; brute force infeasible |
| Fluctuation (during active execution) | Detected | Config is decrypted while Beacon is active; original single-byte XOR remains |
Active Window Vulnerability
During the brief active window (~100ms per cycle), the Beacon's memory is fully decrypted and scannable. BeaconEye or any other scanner that happens to scan during this window will find the implant. ShellcodeFluctuation only protects during the sleep window. This is the fundamental limitation of all sleep-time-only evasion techniques.
6. Remaining Detection Vectors
Even with both ShellcodeFluctuation and ThreadStackSpoofer active, several detection paths remain available to defenders:
| Detection Vector | Description | Difficulty to Detect |
|---|---|---|
| Thread start address | The thread was created with CreateThread pointing to private memory. The start address is recorded in the ETHREAD structure and cannot be changed post-creation | Easy — visible via NtQueryInformationThread |
| Private working set pages in kernel32 | Copy-on-write from hook installation creates private pages that persist even after unhooking | Moderate — requires working set analysis |
| ETW telemetry | VirtualProtect calls generate ETW events. Periodic RW/RX toggling on the same region is an anomalous pattern | Moderate — requires ETW consumer + pattern analysis |
| Timing correlation | Periodic VirtualProtect calls correlated with network beaconing can reveal the sleep cycle | Hard — requires cross-signal correlation |
| Active window scanning | Scanning during the ~100ms active window catches the decrypted shellcode | Hard — requires fast, frequent scanning or triggered scanning |
| Kernel callbacks | PsSetCreateThreadNotifyRoutine logs thread creation with private memory start addresses | Easy from kernel mode |
| Memory allocation patterns | Large VirtualAlloc + PAGE_EXECUTE_READ for private memory is itself suspicious | Moderate — many legitimate uses exist |
7. Fundamental Limitations
What Sleep Evasion Cannot Solve
- Active-time exposure — during command execution, the entire shellcode must be decrypted and executable. No sleep-time technique helps here. Only per-function encryption (FunctionPeekaboo) addresses this
- Network IOCs — C2 communication patterns (DNS beaconing, HTTPS to suspicious domains) are orthogonal to memory evasion
- Behavioral detection — process injection, credential dumping, lateral movement all generate detectable events regardless of memory state
- Kernel telemetry — ETW providers, minifilter drivers, and kernel callbacks operate below the level that user-mode techniques can control
- Sleep 0 scenarios — if the beacon interval is 0 (continuous), Sleep is never called and the fluctuation mechanism never triggers. The shellcode sits permanently decrypted in executable memory
- Hardware security — Intel CET (Control-flow Enforcement Technology) shadow stacks will eventually break techniques that manipulate return addresses, though ThreadStackSpoofer's approach is more CET-compatible than ROP-based alternatives
8. State of the Art and Evolution
ShellcodeFluctuation represents one point in the evolution of sleep evasion research. Understanding where it fits helps assess its current relevance:
Evolution of Sleep Evasion
| Era | Technique | Innovation |
|---|---|---|
| 2021 | ShellcodeFluctuation (mgeeky) | Inline-hook approach with unhook/rehook cycle and XOR32 encryption |
| 2021 | ThreadStackSpoofer (mgeeky) | Return address overwriting for call stack evasion |
| 2022 | Ekko (C5pider) | First public timer-callback-based sleep encryption with clean call stacks |
| 2022 | FOLIAGE (Austin Hudson) | APC + NtContinue for clean execution context |
| 2022 | Cobalt Strike Sleep Mask Kit v2 | Official CS support for custom sleep masks with heap encryption |
| 2022-23 | SilentMoonwalk, Unwinder | Full call stack fabrication with synthetic unwind metadata |
| 2023+ | Nighthawk, BruteRatel | Commercial C2 frameworks with built-in sleep evasion suites |
| 2025 | FunctionPeekaboo (MDSec) | Per-function encryption at the LLVM compiler level — active-time protection |
Where ShellcodeFluctuation Excels
- Simplicity — the hook-based architecture is easy to understand, implement, and debug. No ROP chains, no APC manipulation
- CET compatibility — standard call/ret flow works with Intel CET shadow stacks, unlike Ekko's timer-callback chains
- Zero suspicious imports — no
SystemFunction032, noNtContinue, no timer queue APIs. Uses onlyVirtualProtect,Sleep, andGetProcAddress - Integration-friendly — the
MySleephook handler can easily incorporate additional techniques (stack spoofing, heap encryption, etc.) - Educational value — the clear, sequential nature of the algorithm makes it an excellent teaching tool for understanding memory evasion concepts
9. Defense Recommendations
For blue team operators and detection engineers, the following approaches can detect ShellcodeFluctuation and similar techniques:
Detection Strategies
- Thread start address auditing — flag threads whose start address is in private (non-image) memory. This is a fundamental IOC that no user-mode sleep evasion technique can eliminate
- ETW VirtualProtect monitoring — look for periodic
NtProtectVirtualMemorycalls toggling the same region between RW and RX. Correlate with sleep timing - Working set analysis — detect private pages in normally-shared DLL sections (kernel32.dll .text). This survives the unhook/rehook cycle
- Triggered scanning — instead of periodic scans, trigger memory scans on behavioral events (network connections, process creation) that occur during the active window
- Kernel callbacks — use kernel-mode notification routines that fire before user-mode code can react
- Hardware-assisted detection — Intel PT (Processor Trace) can record control flow history, revealing the hook and encryption operations
10. Course Summary
| Module | Key Concept |
|---|---|
| 1. Memory Scanning Threat Model | Scanners target the 99.8% sleep window where shellcode sits idle in executable memory |
| 2. XOR Encryption | XOR32 is self-inverse, in-place, zero-import, and fast enough to toggle on every sleep cycle |
| 3. VirtualProtect & Pages | Toggle between RW (writable, not executable) and RX (executable, not writable) — never RWX |
| 4. Sleep Function Hooking | Inline hook on kernel32!Sleep intercepts every beacon cycle with an unhook/rehook IOC reduction |
| 5. The Fluctuation Algorithm | 7-phase cycle: RW → encrypt → unhook → sleep → rehook → decrypt → RX |
| 6. Shellcode Region Tracking | VirtualQuery + AllocationBase identify the region; page alignment is guaranteed by the OS |
| 7. Thread Stack Spoofing | Overwrite return address to 0 during sleep; combined with fluctuation for dual-layer evasion |
| 8. Full Chain & Detection | Bypasses Moneta/pe-sieve/BeaconEye during sleep; remaining IOCs are thread start address and working set anomalies |
Knowledge Check
Q1: Which detection vector persists even with ShellcodeFluctuation + ThreadStackSpoofer active during sleep?
Q2: What architectural advantage does ShellcodeFluctuation have over Ekko regarding Intel CET?
Q3: What fundamental limitation do ALL sleep-time-only evasion techniques share?