
Macro-cabecera para ofuscación de C en tiempo de compilación (tcc, win x86/x64)

obfus.h es una biblioteca de solo macros para ofuscar aplicaciones C en tiempo de compilación, diseñada específicamente para Tiny C (tcc) (puedes descargarlo aquí -> Tiny-C-Compiler/releases). Está adaptada para plataformas Windows x86 y x64 y soporta casi todas las versiones del compilador. ¡Una armadura muy fiable para tus programas en C!
Integrar obfus.h en tu proyecto es un proceso sencillo. Solo incluye la siguiente línea en tu código:
#include "obfus.h"
Esto ofuscará automáticamente tu código durante la compilación, garantizando la protección y confidencialidad de tu propiedad intelectual.
Opciones disponibles para configurar la protección:
// Advanced code protection (see the "Virtualization" part of the documentation!) #define VIRT 1 // Allows you to use the functions of a math VM // Additional options #define CFLOW_V2 1 // More powerful Control Flow obfuscation (slowly!) #define ANTIDEBUG_V2 1 // Use better dynamic anti-debugging protection #define FAKE_SIGNS 1 // Adds fake signatures of various protectors or packers // Disabling default features #define NO_OBF 1 // Don't obfuscate (for debugging) #define NO_CFLOW 1 // Don't use Control-Flow obfuscation #define NO_ANTIDEBUG 1 // Don't build in debugging protectiono úsalo con argumentos del compilador:
tcc "app.c" -w -D NO_CFLOW -D ANTIDEBUG_V2 -D FAKE_SIGNS -D VIRT
[!WARNING] Al compilar una aplicación con ofuscación, usa el argumento
-wpara suprimir las advertencias. De lo contrario, la consola mostrará numerosos logs intimidantes que no tienen impacto en el resultado final. No hay necesidad de alarmarse por ellos.
🔐 La protección contra depuración se activa mediante llamadas a muchas funciones básicas de MSVCRT.
En lugares críticos del código puedes usar la construcción ANTI_DEBUG;. Por ejemplo:
ANTI_DEBUG;
if (!licenseExpired()) {
// ...
}
HIDE_STRING(str) ofusca y oculta visualmente las cadenas mutándolas, complicando significativamente su descubrimiento y parcheo en el código fuente. Cuando se declaran de esta manera, las cadenas se ensamblan en la pila mediante instrucciones mov en lugar de cargarse de una sola vez. Este método garantiza que las cadenas no se declaren estáticamente y, en su lugar, se construyan en tiempo de ejecución, haciéndolas menos susceptibles al análisis estático. Sin embargo, es importante tener en cuenta que esta característica no se puede usar para ocultar campos estáticos durante su declaración, ya que implica una llamada a función.
[!IMPORTANT] Algunos descompiladores aún pueden revelarlas debido a optimizaciones estáticas. En la salida del desensamblador, el código aparecerá complejo y engorroso, lo que puede disuadir un análisis sencillo, pero puede no prevenir por completo los esfuerzos decididos de ingeniería inversa.
Un ejemplo de llamada a la función printf de la biblioteca estándar con ocultación estática del mensaje y su descifrado en la pila:
char *hidden_message = HIDE_STRING("Hello, world!");
// ...
printf(hidden_message);
Esta es una técnica de protección en la que ciertos cálculos se realizan a través de una máquina virtual integrada mediante comandos. ¡Hace que el análisis de operaciones matemáticas sea muy difícil! Funcionará con la opción VIRT habilitada (¡y solo con ella!). De lo contrario, todos los comandos de la máquina virtual serán reemplazados por operadores matemáticos ordinarios.
[!WARNING] La virtualización en ubicaciones críticas puede afectar la optimización. Úsala con precaución solo en áreas donde sea realmente necesaria
La máquina virtual no soporta algunas operaciones básicas de comparación de
double.
Puedes usar operadores lógicos que utilizan llamadas a la máquina virtual para complicar aún más la comprensión de tu código:
| Operador | Descripción |
|---|---|
VM_IF |
Esto no es un reemplazo completo de if/else, sino solo una complicación de los operadores estándar.
Un ejemplo sencillo de uso de la virtualización:
// ...
#define VIRT 1
// ...
// 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
}
Puedes encontrar ejemplos de uso de todas las funciones de la máquina virtual en el archivo tests/virtualmachine.c
Si necesitas protección avanzada contra reversers expertos, usa las opciones CFLOW_V2 y ANTIDEBUG_V2.
// Let's obfuscate your code!
#include <stdio.h>
#define VIRT 1 // [+] Use math virtual machine
#define CFLOW_V2 1 // [+] ControlFlow v2
#define FAKE_SIGNS 1 // [+] Fake signatures
#define ANTIDEBUG_V2 1 // [+] AntiDebug v2
#define NO_OBF 0 // [-] Don't obfuscate (disable all)
#define NO_CFLOW 0 // [-] Disable ControlFlow
#define NO_ANTIDEBUG 0 // [-] Disable AntiDebug
#include "obfus.h"
void main() {
char *out = malloc(256);
strcpy(out, HIDE_STRING("Hello, world!\n"));
if (out) {
printf(out);
} else {
printf("Error!\n");
}
free(out);
int result = VM_ADD(5, 7); // 5 + 7
VM_IF (VM_EQU(result, 12)) { // (5 + 7) == 12
printf("5 + 7 == 12");
}
}
Se recomienda usar la última versión de Tiny C (0.9.27). Desafortunadamente, algunas versiones del compilador no soportan la funcionalidad necesaria para una ofuscación completa. Visual C, GCC y Clang no son compatibles y es poco probable que lo sean.
Puedes usar el script especial para Windows para obtener las últimas versiones de obfus.h descargando el paquete del repositorio oficial. Esto es útil si necesitas automatizar las actualizaciones de seguridad sin usar git.
Por ejemplo, puedes usarlo antes de compilar tu proyecto:
+ C:\...> call obfh-update C:\...> tcc app.c -wEl script actualizará el contenido del archivo obfus.h en el directorio actual (según la configuración especificada)
El código de un programa (y su lógica original) protegido con obfus.h es casi imposible de recuperar (desofuscar). Sin embargo, usar este ofuscador no garantiza una protección completa contra todos los tipos de amenazas. Es importante desarrollar y mantener los sistemas de seguridad internos del programa.
Así es como se verá el código esquemático después de la ofuscación:
El reverser verá algo como esto si intenta usar un descompilador:
Así es como se ven todas las cadenas ocultas mediante la función
HIDE_STRINGen el desensamblador (arquitectura x86-64):; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; 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 . . . ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Gracias a todos los que ayudaron en el desarrollo de este proyecto. ¡Lo aprecio! ❤️
Y gracias a ti 🤝 por prestar atención a este proyecto.
| Función | Tipo | Op | Descripción | Ejemplo |
|---|
VM_ADD | long | + | Suma dos números | VM_ADD(5, 3) = 8 |
VM_SUB | long | - | Resta dos números | VM_SUB(5, 3) = 2 |
VM_MUL | long | * | Multiplica dos números | VM_MUL(5, 3) = 15 |
VM_DIV | long | / | Divide dos números | VM_DIV(6, 3) = 2 |
VM_MOD | long | % | Calcula el módulo de dos números | VM_MOD(5, 3) = 2 |
VM_EQU | BOOL | == | Comprueba si dos números son iguales | VM_EQU(5, 5) = true |
VM_NEQ | BOOL | != | Comprueba si dos números no son iguales | VM_NEQ(5, 3) = true |
VM_LSS | BOOL | < | Comprueba si el primer número es menor que el segundo número | VM_LSS(3, 5) = true |
VM_GTR | BOOL | > | Comprueba si el primer número es mayor que el segundo número | VM_GTR(5, 3) = true |
VM_LEQ | BOOL | <= | Comprueba si el primer número es menor o igual que el segundo número | VM_LEQ(3, 5) = true |
VM_GEQ | BOOL | >= | Comprueba si el primer número es mayor o igual que el segundo número | VM_GEQ(5, 3) = true |
VM_ADD_DBL | long double | + | Suma dos números dobles | VM_ADD_DBL(5.5, 3.2) = ≈8.7 |
VM_SUB_DBL | long double | - | Resta dos números dobles | VM_SUB_DBL(5.5, 3.2) = ≈2.3 |
VM_MUL_DBL | long double | * | Multiplica dos números dobles | VM_MUL_DBL(5.5, 3.2) = ≈17.6 |
VM_DIV_DBL | long double | / | Divide dos números dobles | VM_DIV_DBL(6.0, 3.0) = ≈2.0 |
VM_LSS_DBL | BOOL | < | Comprueba si el primer número doble es menor que el segundo número doble | VM_LSS_DBL(3.5, 5.2) = true |
VM_GTR_DBL | BOOL | > | Comprueba si el primer número doble es mayor que el segundo número doble | VM_GTR_DBL(5.5, 3.2) = true |
Úsalo en lugar de if |
VM_ELSE_IF | Úsalo en lugar de else if |
VM_ELSE | Úsalo en lugar de else |