Difficulty: Advanced

Module 8: Detection, CET & Nighthawk

Real-world deployment, hardware security compatibility, detection strategies, and the Nighthawk “Evanesco” production implementation.

Module Objective

Understand how FunctionPeekaboo relates to Intel CET (Control-flow Enforcement Technology) and Shadow Stacks, why it is compatible while Ekko/Zilean are not, how MDSec’s Nighthawk C2 implements this technique in production as “Evanesco,” and what detection strategies defenders can employ against per-function self-masking.

1. Intel CET and Shadow Stacks

Intel Control-flow Enforcement Technology (CET) is a hardware-based security feature in recent Intel processors (11th gen+ Alder Lake and later) that prevents Return-Oriented Programming (ROP) and Jump-Oriented Programming (JOP) attacks. It has two components:

CET ComponentWhat It DoesMechanism
Shadow StackMaintains a hardware-protected copy of return addressesOn CALL, return address is pushed to both the normal stack and the shadow stack. On RET, both are compared. If they differ → #CP (Control Protection) exception
Indirect Branch Tracking (IBT)Ensures indirect branches (JMP/CALL through registers or memory) land on valid targetsIndirect branches must land on an ENDBR64 instruction. If not → #CP exception

CET is increasingly enabled by default in Windows 11 and recent builds of Windows Server. Any evasion technique that manipulates return addresses or uses ROP-like chains will fail on CET-enabled systems.

2. Why Ekko/Zilean/FOLIAGE Break Under CET

Traditional sleep obfuscation techniques fundamentally conflict with CET’s Shadow Stack:

The ROP Problem

Ekko, Zilean, and FOLIAGE use callback-based execution chains (timer callbacks, APC queuing, NtContinue context manipulation) that effectively construct ROP chains — sequences of return addresses that redirect execution through system functions. The Shadow Stack detects that these return addresses were never pushed by a legitimate CALL instruction and raises a #CP exception, killing the process.

TechniqueHow It Chains ExecutionCET Compatible?
EkkoTimer callbacks with crafted context records; uses NtContinue to set RSP to a gadget chainNo — Shadow Stack mismatch on RET from manipulated stack
ZileanAPC queue with context manipulationNo — same issue with return address validation
FOLIAGEAPC + NtContinue with RSP pivotingNo — RSP pivot causes Shadow Stack desync
FunctionPeekabooNormal CALL/RET flow through prologue/epilogue stubsYes — all calls and returns are legitimate

3. FunctionPeekaboo’s CET Compatibility

FunctionPeekaboo is fully compatible with CET because it uses legitimate control flow:

Why It Works Under CET

4. Nighthawk C2 and “Evanesco”

MDSec’s Nighthawk is a commercial C2 framework designed for red team operations. Version 0.3.3 introduced “Evanesco” — a production implementation of FunctionPeekaboo’s per-function self-masking concept.

Nighthawk Evanesco Features

FeaturePoC (FunctionPeekaboo)Production (Nighthawk Evanesco)
Masking scopeFunctions with peekaboo attributeAll implant functions automatically
Thread safetyBasic (single-byte IsEncrypted flag)Reference counting, mutex protection for shared functions
Exception handlingNot addressed in PoCCustom unwind handlers ensure re-encryption on exceptions
VirtualProtect avoidanceUses kernel32 importDirect syscalls (NtProtectVirtualMemory) to bypass hooks
Section names.funcmeta, .stub (descriptive)Randomized or merged into existing sections
Key strengthSingle-byte XORPotentially stronger masking (multi-byte or rolling XOR)
PerformanceProof of conceptOptimized XOR engine, minimal syscall overhead
Sleep integrationSeparate (manual combination)Integrated with Nighthawk’s sleep obfuscation

The “Evanesco” Name

Named after the vanishing spell in the Harry Potter series, Evanesco makes implant code “vanish” from memory scanners. Each function only appears when actively called — the rest of the time, it’s XOR’d garbage that matches no known signatures.

5. Detection Strategies for Defenders

Understanding FunctionPeekaboo from a defensive perspective is essential for blue team operations. Several detection approaches can identify per-function self-masking:

5.1 VirtualProtect Monitoring

Behavioral Pattern

FunctionPeekaboo generates a characteristic pattern of VirtualProtect calls: rapid RX → RW → RX transitions on small memory regions within the .text section. This pattern is unusual for legitimate software — most programs never change the permissions of their own code sections after loading.

Detection Rule (Pseudocode)rule FunctionPeekaboo_VProtect:
  trigger: NtProtectVirtualMemory
  conditions:
    - target address is within a PE .text section
    - protection changed from PAGE_EXECUTE_READ to PAGE_READWRITE
    - followed within 1ms by PAGE_READWRITE to PAGE_EXECUTE_READ
    - same small region (< 0x2000 bytes)
    - occurs repeatedly during process lifetime
  action: alert "Potential per-function self-masking detected"

5.2 Custom PE Section Detection

IndicatorDetection Method
.funcmeta section namePE section name scan (static analysis, YARA)
.stub section namePE section name scan
Entry point not in .textValidate AddressOfEntryPoint falls within the .text section
RW data section with structured entriesEntropy and structure analysis of non-standard sections

5.3 TEB UserReserved Monitoring

TEB Field Writes

Most legitimate applications never write to the TEB UserReserved fields (offsets 0x1478-0x1488). Monitoring writes to these fields can indicate FunctionPeekaboo or similar techniques. This requires kernel-level or hardware-assisted monitoring (e.g., data breakpoints, page guard pages on TEB).

5.4 Timing-Based Detection

The handler adds ~4-20μs overhead to every function call. While individually undetectable, statistical analysis of function call timing across many calls might reveal the overhead pattern. This is a research-level detection approach, not currently deployed by any known EDR.

5.5 Memory Scan Timing

Aggressive Scanning Strategy

The strongest countermeasure is high-frequency memory scanning during process activity periods (not just sleep). If the scanner catches the ~2% window when a function is decrypted, it can extract signatures. This requires scanning every few hundred microseconds, which has significant performance cost but is feasible for targeted investigation.

6. YARA Rules for Detection

YARArule FunctionPeekaboo_Sections {
    meta:
        description = "Detects PE with FunctionPeekaboo custom sections"
        author = "Blue Team"

    condition:
        uint16(0) == 0x5A4D and
        for any i in (0..pe.number_of_sections - 1): (
            pe.sections[i].name == ".funcmeta" or
            pe.sections[i].name == ".stub"
        )
}

rule FunctionPeekaboo_EP_Anomaly {
    meta:
        description = "Entry point outside .text section"

    condition:
        uint16(0) == 0x5A4D and
        not for any i in (0..pe.number_of_sections - 1): (
            pe.sections[i].name == ".text" and
            pe.entry_point >= pe.sections[i].virtual_address and
            pe.entry_point < pe.sections[i].virtual_address +
                pe.sections[i].virtual_size
        )
}

rule FunctionPeekaboo_Stub_Pattern {
    meta:
        description = "Detects the CALL/POP PIC pattern followed by register saves"

    strings:
        // CALL +5 (E8 00000000) followed by POP RBX (5B)
        // then multiple PUSH instructions
        $pic_trick = { E8 00 00 00 00 5B 50 51 52 41 50 41 51 }

    condition:
        uint16(0) == 0x5A4D and $pic_trick
}

7. Comparison with Other Evasion Techniques

TechniqueScopeWhen ActiveCET SafeImplementation
FunctionPeekabooPer-functionAlways (active + sleep)YesCompiler (LLVM)
EkkoEntire imageSleep onlyNoRuntime (code)
ZileanEntire imageSleep onlyNoRuntime (code)
FOLIAGEEntire imageSleep onlyNoRuntime (code)
GargoyleEntire imageSleep onlyNoRuntime (timer ROP)
Module StompingEntire DLLPersistentYesLoader technique
PE Header WipingHeaders onlyPersistentYesPost-load cleanup

8. Limitations and Future Work

Current Limitations

LimitationImpactPotential Solution
On-disk cleartextStatic analysis sees unmasked functions before first runCombine with packing or on-disk encryption
VirtualProtect footprintEDR can monitor permission changesDirect syscalls, avoiding kernel32 imports
Thread safety gapsRace conditions with same function across threadsPer-function reference counting
Exception path leaksExceptions may leave functions decryptedCustom SEH/VEH handlers for cleanup
Custom section namesTrivially signaturableMerge into existing sections or randomize names
XOR weaknessSingle-byte XOR is easily reversedMulti-byte keys, rolling XOR, or lightweight ciphers
Build complexityRequires custom LLVM buildDistribute pre-built toolchain

9. Operational Deployment Considerations

Red Team Deployment Checklist

10. Course Summary

What You’ve Learned

ModuleKey Takeaway
1Memory scanners exploit the sleep window; traditional sleep obfuscation protects during sleep but not during active execution
2LLVM’s modular backend allows custom passes at the PreEmit stage, after all optimizations
3Custom PE sections (.funcmeta, .stub) store metadata and initialization code
4X86RetModPass identifies attributed functions and injects stubs at every entry and exit point
5Prologue (0x46 bytes) decrypts on call; epilogue re-encrypts on return; CALL/POP enables PIC
6The handler (~380 bytes) performs PE parsing, .funcmeta lookup, VirtualProtect transitions, and byte-level XOR
7Initialization encrypts all functions before main(); steady-state maintains ~98% encryption coverage
8CET-compatible (unlike Ekko/Zilean/FOLIAGE); Nighthawk Evanesco is the production implementation

Knowledge Check

Q1: Why is FunctionPeekaboo compatible with Intel CET while Ekko is not?

A) FunctionPeekaboo uses legitimate CALL/RET flow; Ekko uses ROP-like callback chains that desync the Shadow Stack
B) FunctionPeekaboo runs in kernel mode, bypassing CET
C) CET only applies to 32-bit code
D) Ekko was designed before CET existed and can be easily updated

Q2: What is the most effective detection approach for FunctionPeekaboo?

A) Scanning for the XOR key in memory
B) Checking for LLVM compiler artifacts
C) Monitoring CPU instruction counts
D) Monitoring rapid VirtualProtect RX→RW→RX transitions on .text section regions

Q3: What is Nighthawk’s “Evanesco” feature?

A) A kernel-mode rootkit for hiding processes
B) A production implementation of per-function self-masking based on FunctionPeekaboo's concepts
C) An anti-debugging technique using hardware breakpoints
D) A network protocol obfuscation layer