A single-header C++17 library that hides strings from strings(1) and casual
static analysis by encrypting them at compile time and decrypting them at
runtime on the GPU.
I have been researching malware anti-analysis techniques and the idea of utilizing the GPU instead of the CPU seemed interesting to me so i experimented a bit and made this POC.
GPU-based obfuscation is designed to break emulation and basic sandboxes.
The technique exploits the fact that:
-
Most sandboxes and CPU emulators (Unicorn, QEMU-based sandboxes, x86 emulation in tools like CAPE) only emulate the CPU instruction stream. They have no GPU device model at all.
-
If the decryption routine offloads the actual rc4/XOR/whatever work to a compute kernel via vulkan and d3d11 api, a pure-CPU emulator either:
- Fails the API call (no real GPU driver present) and the malware branches to a bail-out/sleep path, or
- Hangs/errors out because the emulator doesn't know how to service the driver call at all. Either way, the strings never get decrypted in that environment, so string-based detection, static "decrypt and dump" scripts, and behavioral sandboxes that rely on seeing plaintext IOCs all come up empty.
From the malware author's side, this technique trades stealth for a lot of fragility. Downsides:
- Requires an actual GPU with a compatible driver. A huge share of real-world targets (servers, VDI instances, budget laptops, virtualized corporate endpoints, etc...) have no discrete GPU or only a basic integrated one without full compute driver support installed.
- If the target has no GPU/driver, the malware's decryption never succeeds, so the payload simply fails to execute correctly on a meaningful fraction of intended victims. That's a self-inflicted loss of reach that pure-CPU crypto doesn't have.
- Loading
d3d11.dllor vulkan from a process that has no legitimate reason to touch a GPU is itself an anomalous, fairly rare signal and easy for the EDR to flag.
- You write
shobf::decrypt(SHOBF_OBFUSCATE("Hello, world!", "key"))in plain C++. - At compile time the literal is encrypted into opaque ciphertext bytes.
- At runtime a tiny GPU compute shader (Vulkan, or Direct3D 11 on Windows) decrypts it back, so a reverse engineer has to chase the data through the GPU to recover it.
See crackme.cpp and main.cpp as example usages.
// XOR cipher (default)
std::string a = shobf::decrypt(SHOBF_OBFUSCATE("secret", "key"));
// RC4 cipher
std::string b = shobf::decrypt(SHOBF_OBFUSCATE_RC4("secret", "key"),
"key", shobf::Algorithm::Rc4);
// Auto: key derived from SHOBF_BUILD_SEED
std::string c = shobf::decryptAuto(SHOBF_OBFUSCATE("secret", shobf::seedKey()));A complete program with a runtime flag check:
#include "shader_obfuscate.hpp"
#include <iostream>
#include <string>
int main()
{
// Compile-time encrypted; SHOBF_BUILD_SEED is the only secret in the binary.
const auto obfFlag = SHOBF_OBFUSCATE("FLAG{sh4d3r_0bfusc4t3d}", shobf::seedKey());
const std::string flag = shobf::decryptAuto(obfFlag);
std::string guess;
std::cout << "Enter flag: ";
std::getline(std::cin, guess);
std::cout << (guess == flag ? "Correct!" : "Wrong!") << std::endl;
}cmake -S . -B build
cmake --build build -j
./build/crackme # guess: vulk4n_1s_n0t_crypt0
./build/shader-obfuscatorOr build just one target:
cmake --build build --target crackmeThe default Vulkan backend builds natively on Linux with g++ or clang++ and a
Vulkan SDK (or distro Vulkan headers + loader). Requirements: CMake >= 3.16, a
C++17 compiler, and the Vulkan headers/loader (e.g. vulkan-headers /
vulkan-loader on most distros).
cmake -S . -B build
cmake --build build -j
./build/crackme # guess: vulk4n_1s_n0t_crypt0
./build/shader-obfuscatorA clean release-only build of a single target:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --target crackme -jBuilds with Visual Studio (MSVC) or MinGW-w64. Backends: Vulkan (default) or Direct3D 11.
Vulkan needs the Vulkan SDK (VULKAN_SDK):
cmake -S . -B build
cmake --build build --config Release -j
build\Release\crackme.exe # guess: vulk4n_1s_n0t_crypt0
build\Release\shader-obfuscator.exeDirect3D 11 (d3d11.dll ships with Windows, no Vulkan SDK):
cmake -S . -B build-d3d -DSHOBF_BACKEND_D3D11=ON
cmake --build build-d3d --config Release
build-d3d\Release\crackme.exeAdd -DSHOBF_D3D11_PRECOMPILED=ON to embed a precompiled DXBC blob instead of
HLSL text. CMake runs build_shader.py (needs Python 3 + MSVC cl.exe via vcvarsall.bat; SHOBF_MSVC_VCVARS overrides the path).
Every option is a macro you #define before #include "shader_obfuscate.hpp".
CMake forwards them as compile definitions:
cmake -S . -B build -DSHOBF_BACKEND_D3D11=ON -DSHOBF_D3D11_PRECOMPILED=ON| Define / option | What it does |
|---|---|
SHOBF_BACKEND_D3D11 |
Use D3D11 instead of Vulkan (non-Windows fails with #error). |
SHOBF_D3D11_PRECOMPILED |
Embed a prebuilt DXBC blob so no HLSL text ships (with D3D11 backend). |
SHOBF_NO_DEBUG |
No validation/exceptions and failures return empty. |
SHOBF_BUILD_SEED |
64-bit seed for the decryptAuto session key. |
If SHOBF_BUILD_SEED is omitted, the header hashes __DATE__/__TIME__, so
the key changes on every rebuild.
crackme.cpp is a small game that decrypts its banner, prompt, secret
passphrase, and win/fail messages on the GPU at runtime.
cmake --build build --target crackme -j # built by the default config
strings build/crackme | grep -c passphrase # 0
./build/crackme # guess: vulk4n_1s_n0t_crypt0To cross-compile a Windows/D3D11 build from Linux, configure with CMake and a
MinGW toolchain file and set SHOBF_BACKEND_D3D11=ON (add
SHOBF_D3D11_PRECOMPILED=ON to embed a prebuilt shader.
- C++17 compiler (g++ / clang++ / MinGW-w64 / MSVC), CMake >== 3.16, and python.
- Vulkan (default): Vulkan headers + loader and a GPU with a compute queue.
- D3D11 (
SHOBF_BACKEND_D3D11, Windows):d3d11.dll. Precompiled mode (SHOBF_D3D11_PRECOMPILED) additionally needs Python 3 and either MinGW-w64g++or the MSVC toolchain (found automatically), pluswine64when cross-compiling on Linux.
This project is intended strictly for research purposes.
It was developed to explore GPU-based obfuscation techniques, anti-analysis methods, and the practical challenges of offloading decryption to graphics hardware.
This project was developed with the assistance of AI-powered tools for code generation, documentation, and debugging. The underlying research, threat modeling, and obfuscation techniques are the original work of the author.
MIT License.
