Obfusk8
Obfusk8: lightweight Obfuscation library based on C++17 / Header Only for windows binaries
Install / Use
/learn @x86byte/Obfusk8README
Obfusk8: C++17-Based Obfuscation Library
Obfusk8 is a lightweight, header-only C++17 library designed to significantly enhance the obfuscation of your applications, making reverse engineering a substantially more challenging endeavor. It achieves this through a diverse set of compile-time and runtime techniques aimed at protecting your code's logic and data.
Table of Contents
- Core Obfuscation Strategies
- Dependencies
- Visualisation
- Engine Analysis and Detection Profile
- Structural and Forensic Characteristics
- Usage
- Building
- Demo
- contribution & Feedback
Core Obfuscation Strategies
1. main Function Wrapping (_main Macro)
The entry point of your application (main) is transformed into a complex, multi-layered obfuscation engine:
- Virtual Machine (VM) Execution (Conceptual): Before your actual
main_bodycode is executed, a mini-VM (simulated CPU) runs a sequence of "encrypted" instructions. This conceals the true entry point and initial operations. The VM's state (registers, program counter, dispatch key) is initialized with runtime-randomized values. - Indirect Control Flow Flattening (ICFF): Critical loops within the
_mainmacro (both in the prologue and epilogue) are transformed into intricate state machines. Control flow is not direct but determined by heavily "encrypted" state variables. The encoding/decoding keys for these state variables are dynamic, derived from VM state, loop counters, compile-time randomness (like__COUNTER__,__LINE__,__TIME__), and a global opaque seed. This makes static analysis of the control flow exceptionally difficult.- Two distinct ICFF engines (
obf_icff_ns_dcffandobf_icff_ns_epd) are used with different state transition logic and key generation, further complicating analysis.
- Two distinct ICFF engines (
- Bogus Control Flow (
OBF_BOGUS_FLOW_*macros): Numerous misleading jump patterns and convoluted conditional structures are injected throughout_main. These usegotostatements combined with opaque predicates (conditions that always evaluate to true or false but are computationally expensive or hard to determine statically). This creates a labyrinth of false paths for disassemblers and decompilers.- Includes
OBF_BOGUS_FLOW_LABYRINTH,OBF_BOGUS_FLOW_GRID,OBF_BOGUS_FLOW_SCRAMBLE,OBF_BOGUS_FLOW_WEAVER,OBF_BOGUS_FLOW_CASCADE, andOBF_BOGUS_FLOW_CYCLONEto generate diverse and complex bogus flows.
- Includes
- Anti-Analysis & Anti-Debug Tricks (
Runtimemacro, SEH):- Forced Exceptions & SEH: Structured Exception Handling (SEH) is used to create paths that involve forced exceptions. The
__exceptblocks can alter program state, making it hard to follow if the debugger skips exceptions. - Debugger Checks (Conceptual): The
Runtimemacro contains conditions that, if met (due to specific VM states or timing), could trigger__debugbreak()or throw exceptions, designed to disrupt debugging sessions.
- Forced Exceptions & SEH: Structured Exception Handling (SEH) is used to create paths that involve forced exceptions. The
2. Virtual ISA Engine (obf_vm_engine)
A core component of the _main macro's obfuscation:
- Custom Mini-CPU Simulation: Simulates a CPU with volatile registers (
r0,r1,r2), a program counter (pc), and adispatch_key. It executes custom "instructions" (handlers). - Obfuscated Instructions: VM instruction handlers perform operations that are heavily disguised using Mixed Boolean-Arithmetic (MBA) and bitwise manipulations. Handlers include arithmetic, bitwise logic, key mangling, junk sequences, conditional updates, memory simulation, and PC mangling.
- Dynamic Dispatch: The selection of the next VM instruction handler is randomized through multiple dispatch mechanisms:
- Register-based dispatch (
reg_dispatch_idx). - Memory-table based dispatch (scrambled function pointer table
get_mem_dispatch_table). - Mixed dispatch (
mixed_dispatch_idx). Thedispatch_keyis constantly mutated, making the sequence of executed handlers highly unpredictable.
- Register-based dispatch (
- Handler Table Mutation: The table of VM instruction handlers (
vm_handler_table) is itself mutated at runtime within the_mainprologue and epilogue, further obscuring the VM's behavior.
3. Compile-Time String Encryption (OBFUSCATE_STRING from AES8.hpp)
- Hidden Strings: Encrypts all string literals at compile-time using a modified AES cipher.
- Dynamic Keys: Encryption keys are unique per string instance, derived from string content, file location (
__FILE__,__LINE__), and build time (__DATE__,__TIME__). - Just-In-Time Decryption: Strings are decrypted on the stack only when accessed at runtime, minimizing their plaintext lifetime in memory.
- (Optional) Decoy PE Sections: Can store encrypted strings in custom PE sections designed to mimic common packer signatures, potentially misleading analysts (MSVC-specific feature from
AES8.hpp).
4. Stealthy Windows API Calling (STEALTH_API_OBFSTR / STEALTH_API_OBF from Resolve8.hpp)
- IAT Obscurity: Avoids leaving direct, easily identifiable entries for Windows APIs in the Import Address Table (IAT).
- PEB-Based Resolution: Dynamically finds base addresses of loaded DLLs and the addresses of API functions by directly parsing Process Environment Block (PEB) data structures at runtime. This bypasses standard
GetModuleHandleandGetProcAddressfor initial resolution if those themselves are not yet resolved by this mechanism. - Hashed Names: Uses compile-time hashing (custom algorithm
CT_HASH) of DLL and API names for lookups. This prevents plaintext DLL and API names from appearing in the binary's import-related data or string tables when using these macros.
5. Indirect Syscall Engine (K8_SYSCALL)
Obfusk8 now integrates a state-of-the-art Indirect Syscall mechanism to bypass User-Mode Hooks (EDRs/AVs) and static analysis checks.
- "The Sorting Hat" Resolution: Instead of reading the .text section of ntdll.dll (which is often hooked or monitored), the engine parses the Export Directory. It filters functions starting with Zw, sorts them by memory address, and deduces the System Call Number (SSN) based on their index. This allows SSN resolution without ever touching executable code.
- Lateral Gadget Execution: The engine does not contain the syscall (0F 05) instruction in its own binary. Instead, it locates a valid syscall; ret gadget inside ntdll.dll memory at runtime. Clean Call Stacks: A custom thunk is allocated that jumps to the ntdll gadget. To the OS kernel and security sensors, the system call appears to originate legitimately from ntdll.dll, maintaining a clean call stack.
- Usage:
Simply use
K8_SYSCALL("ZwOpenProcess", ...)instead of NtOpenProcess.
6. Method-Based Obfuscation with (OBF_METHOD)
Obfusk8 now provides granular control over your binary's security through Method-Based Obfuscation. Instead of obfuscating your entire project (which can impact performance), you can now selectively protect specific, high-value functions or class methods.
How to Use
-
Include the Pass
Ensure you include the method obfuscation logic in your project:#include "../transform/PASSES/obf_cmethods.cxx" -
The Macro Syntax
Define your method using theOBF_METHODmacro:OBF_METHOD(ret_type, func_name, params, method_body)ret_type: The return type of your function (e.g.,bool,int,void*).func_name: The name of the method.params: The function parameters (must be enclosed in parentheses).method_body: The actual logic of your function enclosed in{ }.
Example: Standard vs Obfuscated methods
In this example, PrintStatus is a normal, readable function. Obfusk8_PrintStatus is protected by Obfusk8.
#include "../Instrumentation/materialization/state/Obfusk8Core.hpp"
#include "../Instrumentation/materialization/transform/K8_UTILS/k8_utils.hpp" // for the printf_, u can change the printf_ with anything else...
class Obfusk8_C
{
public:
// standard method which is visible to reverse engineers
void PrintStatus(void)
{
printf_("method\n");
}
// Obfuscated method protected by Obfusk8
OBF_METHOD_(void, Obfusk8_PrintStatus, (void),
{
printf_("same method but Obfuscated\n");
})
};
_main({
Obfusk8_C *pp = new Obfusk8_C;
pp->PrintStatus();
pp->Obfusk8_PrintStatus();
delete pp;
})
You can view the full example here: obfusk8_methods.cpp
6. API Abstraction Classes with Built-in Stealth
Obfusk8 provides helper classes that encapsulate common sets of Windows APIs. These classes automatically use the stealthy API resolution mechanism (STEALTH_API_OBFSTR) during their construction, ensuring that the underlying Windows functions are resolved without leaving obvious static import traces.
K8_ProcessManipulationAPIs::ProcessAPI(k8_ProcessManipulationAPIs.hpp):- Provides convenient access to Windows APIs for process manipulation, such as
OpenProcess,TerminateProcess,CreateRemoteThread,VirtualAllocEx,WriteProcessMemory,ReadProcessMemory,GetProcAddress,GetModuleHandleA,NtQueryInformationProcess,SuspendThread, andGetCurrentProcessId. - Automatic Stealth Resolution: Resolves necessary functions from
kernel32.dllandntdll.dllstealthily. - Simplifies performing process-related operations with a reduced static analysis footprint. Includes the `P
- Provides convenient access to Windows APIs for process manipulation, such as
