README.md
July 5, 2026 · View on GitHub
advanced, open-source obfuscation
introduction:
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. obsidian ce (community edition) supports ARM64 natively with a specialized stub. we also recently added support for pyinstalled exectuables with a special fork of the pyinstaller bootloader. see the packing with pyinstaller section below.
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. when the --pyinstaller flag is used and a .py file is targeted, obsidian uses pyinstaller to build an exe and then immediately obfuscates and outputs the file.
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.
features:
community edition-v1.4:
- pyinstalled executables now supported
- ARM64 fully supported
- 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
packing with pyinstaller:
in order to obfuscate a python script with obsidian, you first need to make sure you have installed pyinstaller via pip. then clone and compile the forked obsidian-pyinstaller repo found here. here are the steps on Windows:
- install the offical MSYS2 UCRT64 package from
https://www.msys2.org/ - open the terminal, then run
pacman -Syu && pacman -S --needed mingw-w64-ucrt-x86_64-gcc - use the same MSYS2 terminal to open
cmd.exethen navigate toobsidian-pyinstallercloned folder - compile the forked pyinstaller package with
python waf all
once complete, copy contents of obsidian-pyinstaller/pyinstaller/bootloader/Windows-64bit-intel directory to the system installation of pyinstallers bootloader (usually found in the site-packages/PyInstaller/bootloader folder of you python installation). it is recommended to backup the old bootloader before doing this step otherwise you will have to reinstall pyinstaller to use it without packing.
- run obsidian with the
--pyinstallerflag from theobsidian-pyinstallerworking directory:
.\obsidian.ce.universal.exe --pyinstaller script.py obfuscated-py.exe
obsidian pro:
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
to-do:
community edition:
- qol (quality of life) improvements for pyinstaller
- spec-file handling
- arm64 code path
- patch already built pyinstaller bundles
- modified bootloaders as resources
- 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
usage:
.\obsidian.ce.universal.exe program.exe packed.exe
ce obfuscation engine:
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 reference sheet:
| 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 |
compile:
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)
amd64 commands:
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
arm64 commands:
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