Sleep Obfuscation
Overview
An implant spends almost all of its life asleep. That idle window is exactly when a memory scanner runs, and a beacon sitting in plaintext RX memory is the easiest thing in the world to signature. Sleep obfuscation closes the window: before parking, the implant encrypts its own image, drops the pages to RW or NA, sleeps, then reverses the process.
The published families — Ekko, Foliage, Cronos and their descendants — differ mainly in how they get code to run while the main thread is parked. Timer queues, APCs and fibers all end up executing a short ROP chain that performs the mask, the wait and the unmask.
The mask is only as good as its timing. Scanners that sample on a randomised interval, rather than a fixed one, catch the unmasked window that every implementation still has to open to do work.
The call chain
- 1CreateTimerQueueTimerQueue a chain of timers that will run while the beacon thread is parked.
- 2RtlCaptureContextSnapshot the thread context so it can be restored after the mask/unmask cycle.
- 3VirtualProtect(RW) + SystemFunction032Flip the beacon's own pages to RW and RC4-encrypt them in place.
- 4WaitForSingleObjectThe actual sleep, during which the payload exists only as ciphertext.
- 5decrypt + VirtualProtect(RX)Reverse the cycle and NtContinue back into the beacon loop.
Detection
The protection-cycle signal is the durable one. Encryption defeats content matching by design, but a private region that oscillates between RW and RX on a regular cadence is behaviourally distinctive and survives every re-implementation of the mask itself.