Compile-time string encryption and import obfuscation for Windows PE32(+) binaries
-
🔒 Compile-Time String Encryption
Obfuscate strings at compile-time using the_X
operator to avoid plaintext exposure in binaries.auto str = "SensitiveData"_X; // Encrypted at compile-time printf(str.c_str());
-
🎯 JOAAT Hashing
Generate Jenkins One-At-A-Time (JOAAT) hashes at compile-time (_JOAAT
/_JOAAT64
) or runtime (joaat
/wjoaat
/joaat64
/wjoaat64
).constexpr auto hash32 = "Kernel32.dll"_JOAAT; // Compile-time hash constexpr auto hash64 = "Kernel32.dll"_JOAAT64; // Compile-time hash
-
🕵️ PEB Walking & Stealthy Imports
Resolve modules and exports withoutGetProcAddress
or static imports:auto hModule = ctninja::xport::get_module("Kernel32.dll"_JOAAT); auto pFunc = ctninja::xport::get_export(hModule, "CloseHandle"_JOAAT);
-
💻 Operator-Driven Function Calls
Call obfuscated imports directly via the$$
syntax:// Predefined in def.h: fpCreateThread, fpLoadLibraryA, fpCloseHandle, etc. $$(Kernel32.dll, CloseHandle, m_hPipeThread); // Resolves and calls at runtime
-
🛡️ Secure Runtime Value Obfuscation
Protect in-memory values with XOR + bit rotation usingSecureValue32
/SecureValue64
. Keys are re-rolled on every access. Most operators are implemented, and it will implicitly cast to it's template type, allowing you to use SecureValue as if it is a built-in type. -
PE32+ Focus
Built for modern Windows binaries, with minimal overhead.
CTNinja is built using Premake5. Follow these steps:
-
Generate Project Files
Runbuild.bat
(Visual Studio 2022) orpremake5 vs2022
. -
Build the Library
Compile the generated project to producectninja.lib
. -
Link in Your Project
Addctninja.lib
and include thectninja.h
header.
#include <ctninja/ctninja.h>
printf("Hello, Malware Analyst"_X.c_str());
Do not call c_str()
multiple times on the same object!
The data is decrypted on the stack when you call c_str()
. Calling it again will re-encrypt the data.
- ❌
auto str = "SensitiveData"_X; // Encrypted at compile-time printf(str.c_str()); printf(str.c_str());
- ✅
auto secstr = "SensitiveData"_X; // Encrypted at compile-time auto str = secstr.c_str(); printf(str); printf(str);
- ✅
printf("SensitiveData"_X.c_str()); printf("SensitiveData"_X.c_str());
#include <ctninja/ctninja.h>
HMODULE hKernel32 = ctninja::xport::get_module("Kernel32.dll"_JOAAT);
FARPROC pCreateFile = ctninja::xport::get_export(hKernel32, "CreateFileW"_JOAAT);
#define CTNINJA_MAGIC_IMPORT
#include <ctninja/ctninja.h>
HANDLE hFile = $$(Kernel32.dll, CreateFileW, L"file.txt", GENERIC_READ, ...);
For $$()
to work, you must define the function signature as fp<FunctionName>
in your code.
Predefined signatures for common Windows APIs (e.g., fpCreateThread
, fpLoadLibraryA
) are in ctninja/include/def.h
.
For custom functions, define the typedef before using $$()
:
// Example for a custom function
typedef BOOL (WINAPI* fpSomeObscureFunction)(DWORD param1, LPCSTR param2);
// Now call it via:
$$(SomeDll.dll, SomeObscureFunction, 123, "param");
- The typedef must match the exact function signature.
- The naming convention must be
fp<FunctionName>
(case-sensitive).
#include <ctninja/ctninja.h>
u32 ulHash32 = "hash_me"_JOAAT; // Compile-Time JOAAT for static strings
u64 ulHash64 = "hash_me"_JOAAT64; // Compile-Time JOAAT64 for static strings
#include <ctninja/ctninja.h>
u32 ulHash32 = ctninja::joaat("hash_me"); // Runtime JOAAT for dynamic strings
u64 ulHash64 = ctninja::wjoaat64(L"hash_me"); // Runtime JOAAT64 for dynamic strings
#include <ctninja/ctninja.h>
typedef ctninja::SecureValue32<float> SV_Float;
SV_Float secretFloat = 123.45f; // Stored encrypted in memory
// Use like a normal value (automatically encrypts/decrypts):
secretFloat += 10.0f;
printf("%f", (float)secretFloat);
#include <ctninja/ctninja.h>
// Architecture-agnostic definition (auto-chooses 32/64-bit)
#ifdef _M_X64
typedef ctninja::SecureValue64<BYTE*> SVP_BYTE;
#else
typedef ctninja::SecureValue32<BYTE*> SVP_BYTE;
#endif
SVP_BYTE pSec;
pSec = pArray;
*pSec = 0x1f;
pSec[1] = 0x2e;
- Windows Only: Designed for PE32(+) binaries (x86/x64).
- C++20 Required: Relies on
constexpr
/consteval
for compile-time magic. - Antivirus Warnings: Obfuscation may trigger heuristic detections. Test thoroughly.
- sub1to - Initial work - sub1to
See also the list of contributors who participated in this project.
MIT License. See LICENSE.MD
PRs and issues welcome! See CONTRIBUTING.MD for guidelines.