Skip to content
DosX-devPublic

Latest commit

Β 

History

428 Commits

Folders and files

Repository files navigation

obfus.h β€” compile-time obfuscation

obfus.h

Aggressive polymorphic protection for native code. One header. Completely free.

Platform: Windows x86 / x64 Compiler: TinyCC License: MIT+

Get started β€’ Download the crackmes

obfus.h brings compile-time polymorphic obfuscation to C applications and libraries on Windows x86 and x64, built specifically for TinyCC. Turn familiar control flow into tangled paths, obscure calls, hide selected strings and virtualize sensitive calculations. Include the header and build: protection becomes part of your binary.

Just seeing obfus.h in your binary will make a reverse engineer question the existence of God.

What makes it worth using

  • 🧬 The same logic. Many different forms. Instruction sequences, constants and control-flow layouts vary across protected sites and build seeds.
  • πŸ”„ Familiar logic. Unfamiliar control flow. Automatic protection transforms conditions, loops and returns, complicating reconstruction of the original program structure.
  • πŸ›‘οΈ Protection beyond branches. Combine call obfuscation, runtime string construction, anti-debugging and optional virtualization. Common Windows API and CRT calls receive protection automatically.
  • πŸ“¦ One header. Direct integration. Build protection directly into your application during compilation, using your existing TCC build.
  • πŸ”“ Free, including commercial use. Open source, with every protection feature included. No paid tiers or feature gates.
  • πŸ•ΉοΈ Real binaries to take apart. Download generated crackmes at four difficulty levels and judge the protection yourself.

πŸ“– Protection in practice

Easy to integrate. Unpleasant to reverse. Polymorphic transformations complicate the path from machine code back to readable logic. They reshape branches, calls and calculations while preserving the intended behavior of the program.

The comparisons below illustrate the transformation. The resulting graph and decompiled output vary with the code, build settings and analysis tool.

Control-flow graph

Stylized illustration of control-flow graphs before and after obfuscation

Decompiled output

Example of decompiled output before and after obfuscation

πŸ•ΉοΈ Daily Crackmes

See the protection. Take it apart. Judge it yourself.

Four levels: Easy, Medium, Hardcore and Extreme. Generated verification logic changes the challenge itself, not just its password. Download ready-to-run Windows binaries, sharpen your reverse-engineering skills and explore the generated protection without setting up a compiler. Download. Disassemble. Find the password.

New crackmes are published daily. The scheduler is set for 13:00 Moscow time (UTC+3), but the actual publication time depends on GitHub Actions' mood.

🎯 Intended use

Protect the logic that makes your software yours. Apply protection to native components containing proprietary algorithms, licensing checks or other sensitive logic. Choose the mechanisms and settings that fit the component's performance requirements.

For larger projects, isolate that logic in C DLLs compiled with TCC. The main application can keep its existing toolchain β€” C#, C++, another language, or C compiled with GCC, LLVM/Clang or Visual C β€” and call the protected DLLs through their exported interfaces.

You can also combine the resulting binaries with commercial protectors and packers. Check compatibility with the chosen protector and settings before distribution.

Important

Make reverse engineering cost more time and effort. Layered, polymorphic protection complicates analysis and recovery of your program's logic. The goal is to raise the effort required to recover protected logic, rather than promise immunity to reverse engineering.

This project is intended to protect lawful software, including commercial applications and crackmes. Its author categorically opposes any malicious use. This statement is not a license condition, but projects involving malicious activity will receive no support from the author or the development team.

πŸ‘Ύ Usage

Download TinyCC 0.9.28rc from TinyCC-builder and place obfus.h in your project. Include it after standard and system headers, before the code you want to protect:

#include "obfus.h"

Build with TCC as usual. Automatic protection is enabled by default; use markers and HIDE_STRING for additional protection at selected points. IntelliSense remains available.

Automatic control-flow protection covers if, else, case, break, switch, while, for, return, continue, default and do. Use the BREAK_STACK_CFLOW; and STACK_PROXY_FUNCTIONS; markers to add protection at selected points in your code.

Enable OBFH_BETTER_CONTROL_FLOW for an additional layer of control-flow protection, with higher runtime cost.

Choose your build variants

OBFH_SEED is an unsigned 32-bit build seed (default: 0u). Change it to generate different protection layouts for the same program behavior. Source changes can also affect the generated protection.

For command-line builds, use -DOBFH_SEED=123456789u. The seed can be stored openly in your build configuration; reproducing a binary also requires matching the source, compiler and build settings.

Define options before including the header. For example, to enable the additional control-flow and anti-debugging mechanisms:

#define OBFH_SEED                   123456789u
#define OBFH_BETTER_CONTROL_FLOW    1
#define OBFH_BETTER_ANTIDEBUG       1

#include "obfus.h"

Option reference

Choose individual options to match your protection and performance requirements.

Option Effect when set to 1
OBFH_BETTER_CONTROL_FLOW Add another layer of control-flow mutation, with higher execution cost.
OBFH_BETTER_ANTIDEBUG Add hardware-breakpoint checks to anti-debugging protection.
OBFH_FAKE_SIGNATURES Add fake protector/packer signatures for crackme and CTF challenges.

For debugging or selective disabling:

Option Effect when set to 1
OBFH_DISABLE_ANY_OBFUSCATION Disable obfuscation.
OBFH_DISABLE_CONTROL_FLOW Disable automatic control-flow protection.
OBFH_DISABLE_ANTIDEBUG Disable built-in anti-debugging protection.
OBFH_DISABLE_PDATA_DECOYS Disable additional x64 fake functions.

Warning

Reserve OBFH_FAKE_SIGNATURES for crackme/CTF challenges; avoid it in production software. Fake protector and packer signatures can trigger antivirus detections and cause tools such as Detect It Easy to flag the binary as suspicious or potentially malicious.

You can also select options on the command line:

tcc "app.c" -w -DOBFH_SEED=123456789u -DOBFH_BETTER_ANTIDEBUG=1

Tip

Use -w to suppress warnings generated by the protection during compilation.

Calls to many common MSVCRT functions automatically trigger anti-debugging checks. Place the ANTI_DEBUG; marker where you need an additional check:

ANTI_DEBUG;
if (!licenseExpired()) {
    // ...
}

🧢 Strings hiding

Hide selected string literals. Use the HIDE_STRING(str) construct inside functions to build strings at runtime instead of storing them as plain text in the binary.

The returned pointer remains valid until the enclosing block ends. For longer-lived or static storage, copy the string into your own buffer at runtime. Contents can be recovered through code analysis or runtime inspection.

char *hidden_message = HIDE_STRING("Hello, world!");
// ...
printf("%s", hidden_message);

An example of runtime string construction in x86-64 disassembly:

  ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
  ; PROTECTED STRING:                  ; ORIGINAL STRING:         ;
  mov eax, 48h                         lea rax, aHelloWorld       ;
  mov [rbp-0Fh], al                    mov r11, rax               ;
  mov eax, 65h                         ; . . .                    ;
  mov [rbp-0Eh], al                                               ;
  mov eax, 6Ch                                                    ;
  mov [rbp-0Dh], al                                               ;
  mov eax, 6Ch                                                    ;
  mov [rbp-0Ch], al                                               ;
  mov eax, 6Fh                                                    ;
  mov [rbp-0Bh], al                                               ;
  mov eax, 2Ch                                                    ;
  ; etc . . .                                                     ;
  ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

πŸ‘Ί Virtualization

Put selected calculations behind a virtual instruction set. Use VM_* markers to express sensitive arithmetic and comparisons through VM operations.

The virtual machine is included automatically when you use VM_* markers; unused VM functions add no weight to your binary. With OBFH_DISABLE_ANY_OBFUSCATION=1, these markers expand to ordinary calculations.

Warning

Focus virtualization on sensitive calculations. VM protection adds runtime overhead; measure performance when using it in frequently executed code.

Marker Type Op Description Example
VM_ADD long + Addition VM_ADD(5, 3) = 8
VM_SUB long - Subtraction VM_SUB(5, 3) = 2
VM_MUL long * Multiplication VM_MUL(5, 3) = 15
VM_DIV long / Division VM_DIV(6, 3) = 2
VM_MOD long % Remainder VM_MOD(5, 3) = 2
VM_AND unsigned int & Bitwise AND VM_AND(6, 3) = 2
VM_OR unsigned int | Bitwise OR VM_OR(6, 3) = 7
VM_XOR unsigned int ^ Bitwise XOR VM_XOR(6, 3) = 5
VM_NOT unsigned int ~ Bitwise NOT VM_NOT(0) = 0xFFFFFFFFu
VM_SHL unsigned int << Left shift VM_SHL(1, 3) = 8
VM_SHR unsigned int >> Right shift, zero-filled VM_SHR(8, 3) = 1
VM_EQU BOOL == Equal VM_EQU(5, 5) = true
VM_NEQ BOOL != Not equal VM_NEQ(5, 3) = true
VM_LSS BOOL < Less than VM_LSS(3, 5) = true
VM_GTR BOOL > Greater than VM_GTR(5, 3) = true
VM_LEQ BOOL <= Less or equal VM_LEQ(3, 5) = true
VM_GEQ BOOL >= Greater or equal VM_GEQ(5, 3) = true
VM_ADD_DBL long double + Addition VM_ADD_DBL(5.5, 3.2) = β‰ˆ8.7
VM_SUB_DBL long double - Subtraction VM_SUB_DBL(5.5, 3.2) = β‰ˆ2.3
VM_MUL_DBL long double * Multiplication VM_MUL_DBL(5.5, 3.2) = β‰ˆ17.6
VM_DIV_DBL long double / Division VM_DIV_DBL(6.0, 3.0) = β‰ˆ2.0
VM_LSS_DBL BOOL < Less than VM_LSS_DBL(3.5, 5.2) = true
VM_GTR_DBL BOOL > Greater than VM_GTR_DBL(5.5, 3.2) = true

For floating-point comparisons, use VM_LSS_DBL and VM_GTR_DBL.

The following markers route condition checks through a VM proxy layer, adding another layer of complexity to branch analysis:

Marker Description
VM_IF Use instead of if
VM_ELSE_IF Use instead of else if
VM_ELSE Use instead of else

For example:

// ...

// if ((2 + 2) == 4) { ... }
VM_IF(VM_EQU(VM_ADD(2, 2), 4)) {
    printf("2 + 2 == 4!");
}

// if (condition1) { ... }
// else if (condition2) { ... }
// else { ... }
VM_IF(condition1) {
    // if
} VM_ELSE_IF(condition2) {
    // else if
} VM_ELSE {
    // else
}

See tests/vm.c for further examples of VM markers.

❓ Example

This example combines automatic protection, HIDE_STRING and VM markers with enhanced control-flow and anti-debugging options.

Save it as app.c next to obfus.h and build with tcc app.c -w -o app.exe.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define OBFH_SEED                   123321u
#define OBFH_BETTER_CONTROL_FLOW    1          // Additional control-flow mutation; higher runtime cost
#define OBFH_BETTER_ANTIDEBUG       1          // Additional hardware-breakpoint checks
#define OBFH_FAKE_SIGNATURES        0          // Enable only for crackme/CTF challenges

#include "obfus.h"

int main(void) {
    ANTI_DEBUG;

    char *out = malloc(256);
    STACK_PROXY_FUNCTIONS;

    if (out) {
        strcpy(out, HIDE_STRING("Hello, world!\n"));
        printf("%s", out);
    } else {
        printf("Allocation failed!\n");
        return 1;
    }

    free(out);

    int result = VM_ADD(5, 7);
    BREAK_STACK_CFLOW;

    VM_IF(VM_EQU(result, 12)) {
        printf("5 + 7 == 12\n");
    }

    return 0;
}

πŸ€– How it works

Overview of the obfuscation process

πŸ›  Compiler (important)

Use TinyCC 0.9.28rc from TinyCC-builder, which includes the Windows headers, libraries and obfh-update.cmd. Use this package to get the compiler version required by the protection.

Note

To build the latest compiler yourself, download TinyCC-builder and double-click build.cmd; sources and dependencies are downloaded automatically.

🌐 obfus.h updater

obfh-update.cmd is already included in the standard TinyCC-builder package, next to tcc.exe.

Run it manually from your project directory or add it to your build pipeline. It downloads the latest obfus.h into the current directory:

call "C:\TinyCC\obfh-update.cmd"
if errorlevel 1 exit /b 1
"C:\TinyCC\tcc.exe" app.c -w

To update another directory, pass its relative or absolute path. The directory must exist; the filename is always obfus.h:

call "C:\TinyCC\obfh-update.cmd" "include"
call "C:\TinyCC\obfh-update.cmd" "C:\My project\include"

For standalone use, download the script separately.

🦎 Security Research and Community

Research feeds back into the protection. Community analysis and CTF writeups help identify weaknesses and guide improvements. Each article examines a specific sample and version, rather than establishing a universal method for removing protection.

πŸ“„ License

MIT with a compiled-distribution exception. Distributed EXEs, DLLs and other compiled binaries do not need to include attribution or the license text for obfus.h. When distributing obfus.h source code, modified versions or substantial portions of it, retain the copyright notice and license text. You do not need to disclose your application's source code.

🌈 Special thanks

I (DosX) couldn’t have made this project what it is today without your help. Thank you! ❀️

  • πŸ‘¨πŸΌβ€πŸ’» @horsicq (for help with the code and advice)
  • 🐺 @ac3ss0r (for cool ideas and their solutions)
  • πŸ›‘οΈ @AsoiX-exe (for testing and security audits)
  • πŸ€– OpenAI (for providing development grants)

And thanks to you 🀝 for paying attention to this project!

Releases

Packages

Used by

Contributors

Languages