Segment-Encryption-Decryption (SED) is a runtime code-protection system that encrypts functions in memory, decrypts them only during execution, and immediately re-encrypts them afterward.
This is a complete modern rearchitecture of C5Hackr’s original Segment-Encryption (SED).
All credit for the original concept and proof-of-concept implementation goes to C5Hackr.
If you find this project useful, please star the repository to support further development!
SED protects sensitive code by dynamically encrypting and decrypting functions in memory at runtime. This project enhances the original with:
- Modern C++ design - replaces global C-style data with typed structures, atomics, and thread-local storage and call stacks.
- Full thread safety - no data races under concurrent execution.
- Lock-free global state - immutable table publication (RCU-style).
- Fast runtime - decrypt–execute–relock cycles complete in microseconds.
- Stealth wipe - functions are cleared with randomized
UD2sleds + junk bytes instead of static illegal opcodes. - Per-cycle re-randomization - every wipe differs (no stable memory signature).
- Stash relocation - the encrypted backup moves to a new memory region after each re-lock cycle.
- Garbage Collection - old stash pages and old function tables are safely reclaimed after a grace period; zero leaks, zero UAFs.
- Hardened stash memory - isolated via
VirtualAlloc, keptPAGE_READONLYorPAGE_NOACCESSat rest.
-
Initialization
EncryptFunction()scans a function, copies its bytes to a per-function encrypted stash (privateVirtualAllocregion), and overwrites the live code with a randomizedUD2+ junk pattern.- A global Vectored Exception Handler (VEH) is installed to handle decryption on demand.
-
Execution
- Executing a wiped function triggers
EXCEPTION_ILLEGAL_INSTRUCTION. - The VEH decrypts the stash, restores the function bytes, and resumes execution.
- Only the first thread decrypts; concurrent threads reuse the live code.
- Executing a wiped function triggers
-
Post-Execution
- Each function ends with
EndSED(), which decrements its atomicActiveCallscounter. - When the last thread exits:
- The code is wiped again with a new random UD2/junk pattern.
- The encrypted stash is cloned to a new VA region, and the old region is retired under a new epoch.
- Epoch-based reclamation frees only those retired stashes and obsolete function tables that are at least one full generation older, ensuring no UAFs while eliminating leaks.
- Each function ends with
Performance: ~1-2 µs per full decrypt/re-encrypt cycle.
Thread Safety: Fully atomic design; no locks or races even under 8+ threads.
Memory Safety: No leaks, no UAFs - epoch-based GC guarantees one-grace-period safety.
Since this version re-encrypts functions in roughly 0.5 µs, viewing the decrypted code without an intentional delay is virtually impossible. To assist with debugging, two optional macros have been added at the top of SED.h that control re-encryption behavior:
#define SED_DEBUG_KEEP_DECRYPTED 0
#define SED_DEBUG_SLEEP 0| Macro | Description |
|---|---|
SED_DEBUG_KEEP_DECRYPTED |
Keeps code decrypted after EndSED() for inspection. |
SED_DEBUG_SLEEP |
Adds a short pause before re-encryption to attach a debugger. |
This version significantly enhances the original SED project with the following upgrades:
- Each protected function owns its own encrypted stash in a
VirtualAllocregion. - Stashes are
PAGE_READONLYat rest and decrypted only during VEH handling. - Live code pages are wiped after execution using randomized UD2 sleds + junk patterns, ensuring no static opcode signature remains.
- Every wipe uses a per-function RNG seed, so patterns differ on every cycle.
- After each full execution cycle, both the encrypted stash and its metadata table are cloned to new memory regions.
- The old versions are retired under a grace epoch model, guaranteeing zero use-after-free conditions.
- Epoch-based garbage collection safely frees both retired stash pages and old tables once they’re at least one generation old, ensuring fully leak-free operation.
- Thread safety is ensured through atomic
ActiveCallscounters and a per-thread call stack (g_tls_stack). - Global tables are published immutably (RCU-style), allowing readers to proceed without locks.
- All reclamation (stash and table rotation) runs atomically and safely even under heavy multithreaded load.
- The Vectored Exception Handler verifies:
- Function size validity (
0 < size ≤ 64KB) - Instruction pointer alignment with the registered function start
- Function size validity (
- Prevents controlled-fault exploits or mid-body decrypts.
- Decryptions and re-encryptions are strictly bounded to valid function regions.
- Re-encryption occurs only when the final thread exits a protected function.
- Minimizes redundant
VirtualProtectandFlushInstructionCachecalls for speed (~1 µs per full decrypt–execute–relock). - Debug macros (
SED_DEBUG_KEEP_DECRYPTED,SED_DEBUG_SLEEP) allow inspection pauses or persistent decryption for analysis. - Extensive inline comments and section banners clarify lifecycle behavior and implementation intent.
run_concurrent_same()andrun_concurrent_mixed()for thread-safety stress tests.run_stash_relocation_tests()verifying generation increments and epoch-based reclamation.run_break_reencrypt_churn()simulating heavy churn to confirm stable re-encrypt/decrypt cycles.- All tests must pass without crashes, leaks, or unmapped access under 8+ concurrent threads.
| Feature | Original | This Version |
|---|---|---|
| Thread Safety | No | Yes (Atomic + TLS) |
| VEH Hardening | No | Yes (Sanity checks) |
| Stash Relocation | No | Yes (Safe per-cycle relocation) |
| Garbage Collection | No | Yes (Leak-free memory reclamation) |
| Memory Wipe | Static 0x1F | Randomized UD2 + junk |
| Debugging | None | Macros + inspection delay |
| Performance | ~Slow | ~1-2µs per call |
| Memory Safety | Partial | Full |
| Locking | Global locks | Lock-free atomic RCU table |
- Include
SED.hin your project. - Encrypt target functions from
main():
EncryptFunction(reinterpret_cast<uintptr_t>(myFunction));- Each protected function must end with:
return EndSED(returnValue);- Build with C++17+ and
std::atomicsupport. - Run the examples in
SED.cppto test.
This project is for educational and research purposes only, based on the original design by C5Hackr.
Use responsibly and in compliance with all applicable laws.
The author assumes no liability for misuse.
Licensed under GNU GPL v3.0
See LICENSE for details.


