obsidian community edition - universal pe packer
advanced, open-source obfuscation
obsidian is a custom universal pe packer / executable protector written in C. it is designed to be paired with a loader stub that decrypts and executes the packed payload.
the stub included uses rolling xor obfuscation with shifts and does not contain any anti-debugging mechanisms. this packer/stub has been tested to work on putty.exe, strings.exe, and can even pack itself, and then pack other executables from the packed state.
full source for both arm64 and amd64 stubs are included in this repo. feel free to modify it to suit your needs or to evade detection.
community edition-v1.3:
- ARM64 support now added
- improved xor algorithm
- hash-based import lookups
- compiled xorshift64+ stub (stubs/stub.bin)
- high entropy ASLR support
- stub template (BYOS - bring your own stub)
- extensive debug output (-DDEBUG & --debug flags)
- randomized config marker
- zeroed out optional headers
- secure key generation
- checksum recalculation
- pe section manipulation
- progress bar and colors
obsidian pro is an upgraded version of obsidian community edition with SPECK encryption, aPlib compression, and anti-debugging syscalls. it is licensed using open-source obsidian keykeeper which sits behind a clearnet-to-tor proxy, enabling anonymous license management.
where to find:
pro edition features:
- SPECK 128/128 CTR encryption
- aPlib compression (--compress)
- resource encryption
- extensive syscall anti-debug (--ultra)
- anti-sandbox
- hmac integrity checks
- ollvm-22 obfuscated
community and pro edition:
- pyinstaller support
- remain updated to keep ahead of av detection
commercial edition(future):
- gui
- anti-dump protection
- license support/hardware binding
- online key provisioning
- DRM-like protections
.\obsidian.ce.universal.exe program.exe packed.exe
void obfuscate_data(uint8_t* data, size_t size, uint64_t key) {
uint8_t key_xor_aa = (uint8_t)(key ^ 0xAA);
uint8_t key_xor_aa_shr8 = (uint8_t)((key ^ 0xAA) >> 8);
for (size_t i = 0; i < size; i++) {
uint64_t subkey = key ^ (i * 0x9E3779B97F4A7C15ULL);
subkey = (subkey ^ (subkey >> 30)) * 0xBF58476D1CE4E5B9ULL;
subkey = (subkey ^ (subkey >> 27)) * 0x94D049BB133111EBULL;
subkey = subkey ^ (subkey >> 31);
uint8_t shift1 = (uint8_t)((i * 8) & 0x3F);
uint8_t shift2 = (uint8_t)((24 + i * 8) & 0x3F);
uint8_t shift3 = (uint8_t)((56 + i * 8) & 0x3F);
uint8_t mask = (uint8_t)(subkey >> shift1)
^ (uint8_t)(subkey >> shift2)
^ (uint8_t)(subkey >> shift3);
data[i] ^= mask;
data[i] += key_xor_aa;
data[i] -= key_xor_aa_shr8;
}
}obfuscation process:
- use constants to derive values for add and sub operations
- mix in 'golden ratio' constants into a subkey to increase entropy
- generate shifts and final mask variable
- apply transformation to data
| stub.bin | stub.Oz.bin | stub.obfuscated.bin | stub.full.obf.bin | stub-arm64.bin | |
|---|---|---|---|---|---|
| description: | no optimization | aggressive size optimization | control flow flattening + instruction substitution | fully obfuscated (bogus control flow, splitting, flattening, substitution) | arm64 variant, -O1 optimized |
| size: | 17kb | 13kb | 17kb | 57kb | 5kb |
| tools: | clang/llvm | clang/llvm + Oz | clang/llvm + Oz + ollvm-22 | clang/llvm + Oz + ollvm-22 | clang/llvm + O1 |
| note: | basic | smallest/fastest | balanced | largest/slowest | now available in stubs/ folder |
requirements:
gcc:
- mingw64 tool suite available at
https://winlibs.com/ - windbg or other debugger
- python interpreter for
clean.py
llvm/clang:
- llvm 22 toolchain
- mingw64 tool suite
arm64 requirements:
- arm64 llvm/mingw64 toolchain (included in some bundles)
step 1: build stub object file
gcc:
.\gcc.exe stub.c -o stub.o -fno-asynchronous-unwind-tables -fno-ident -fno-stack-protector
llvm/clang:
clang --target=x86_64-pc-windows-gnu \
-I/llvm-mingw-20260311-ucrt-macos-universal/generic-w64-mingw32/include \
-masm=intel \
-fno-asynchronous-unwind-tables -fno-ident -fno-stack-protector -Oz \
-c stub.c -o stub.o
step 2: link and strip stub binary
both:
.\ld.exe stub.o -o stub.exe -nostdlib --build-id=none -s --entry=_start
.\objcopy.exe -O binary stub.exe stub.bin
.\windres.exe resource.rc -o resource.o
step 3: build obsidian ce
gcc:
.\gcc.exe obsidian.c resource.o -o obsidian.exe -lbcrypt
llvm/clang:
x86_64-w64-mingw32-clang \
-I/llvm-mingw-20260311-ucrt-macos-universal/generic-w64-mingw32/include -O1 \
obsidian.c resource.o -o obsidian.exe -lbcrypt
step 1: build stub object file
/llvm/llvm-mingw-20260311-ucrt-macos-universal/bin/aarch64-w64-mingw32-clang \
-fno-asynchronous-unwind-tables -fno-ident -fno-stack-protector -O1 \
-c stub-arm64.c -o stub-arm64.o
step 2: link and strip stub binary
.\ld.lld.exe stub.o -o stub.exe --build-id=none -s --entry=_start
.\objcopy.exe -O binary stub.exe stub.bin
.\windres.exe resource.rc -o resource.o
note: resource file step must happen after both arm64 and amd64 stubs are in .bin format
step 3: build obsidian ce
gcc:
.\gcc.exe obsidian.c resource.o -o obsidian.exe -lbcrypt
llvm/clang:
x86_64-w64-mingw32-clang \
-I/llvm-mingw-20260311-ucrt-macos-universal/generic-w64-mingw32/include -O1 \
obsidian.c resource.o -o obsidian.exe -lbcrypt




