InsomniacUnwinding
Surgical UNWIND_INFO preservation for sleep masking without call stack spoofing.
Blog Post: Unwind Data Can't Sleep - Introducing InsomniacUnwinding
Overview
Traditional sleep masking encrypts the entire payload image, breaking stack unwinding. This implementation is based on Ekko created by (@C5pider) and surgically preserve only the UNWIND_INFO structures needed for stack walking (~250 bytes vs ~6KB full .rdata), the PE Headers and the .pdata section.
How It Works
The timer chain is extended to patch back preserved regions after encryption:
VirtualProtect→ RWSystemFunction032→ Encrypt entire imageRtlCopyMemory→ Restore PE headersRtlCopyMemory→ Restore .pdataRtlCopyMemory× N → Restore each UNWIND_INFO regionWaitForSingleObject→ SleepSystemFunction032→ DecryptRtlCopyMemory→ Restore PE headers (XOR'd to garbage)RtlCopyMemory→ Restore .pdataRtlCopyMemory× N → Restore each UNWIND_INFO regionVirtualProtect→ RXSetEvent→ Signal completion
Usage
-
Build in Visual Studio (x64 Release)
-
Run:
.\InsomniacUnwinding.exe
- Attach a debugger and inspect the main thread's call stack during sleep. It should resolve correctly through
BaseThreadInitThunkandRtlUserThreadStart.
YARA Testing
Test signatures are embedded in .rdata and .data:
.\yara64.exe DeadBeefSignature.yar <pid>
Expected results:
- Awake: 2 hits
- Sleeping: 0 hits (both encrypted, only UNWIND_INFO preserved)
Key Insight
Call stack spoofing is an architectural consequence of unbacked sleepmask memory, not a fundamental requirement. When the sleepmask executes from backed memory, spoofing becomes unnecessary.
Acknowledgments
Thanks to Alex Reid (@Octoberfest73) for catching a mistake in the initial research that led to this improved implementation.