README.md

July 5, 2026 · View on GitHub

obsidian logo

obsidian community edition - universal pe packer
advanced, open-source obfuscation

obsidian badge tor native badge nostdlib badge

clearnettori2p


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.


obsidian splashscreen

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:

  1. install the offical MSYS2 UCRT64 package from https://www.msys2.org/
  2. open the terminal, then run pacman -Syu && pacman -S --needed mingw-w64-ucrt-x86_64-gcc
  3. use the same MSYS2 terminal to open cmd.exe then navigate to obsidian-pyinstaller cloned folder
  4. 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.

  1. run obsidian with the --pyinstaller flag from the obsidian-pyinstaller working directory:
.\obsidian.ce.universal.exe --pyinstaller script.py obfuscated-py.exe

obsidian logo

obsidian pro:

Static Badge

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:

clearnettori2p

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

putty debugging output detect-it-easy detect-it-easy

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:

  1. use constants to derive values for add and sub operations
  2. mix in 'golden ratio' constants into a subkey to increase entropy
  3. generate shifts and final mask variable
  4. apply transformation to data

stub reference sheet:

stub.binstub.Oz.binstub.obfuscated.binstub.full.obf.binstub-arm64.bin
description:no optimizationaggressive size optimizationcontrol flow flattening + instruction substitutionfully obfuscated (bogus control flow, splitting, flattening, substitution)arm64 variant, -O1 optimized
size:17kb13kb17kb57kb5kb
tools:clang/llvmclang/llvm + Ozclang/llvm + Oz + ollvm-22clang/llvm + Oz + ollvm-22clang/llvm + O1
note:basicsmallest/fastestbalancedlargest/slowestnow 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

Ask DeepWiki License used by repo Approximate number of clones Static Badge

arm64 supported amd64 supported donation button