
Макро-заголовок для обфускации C на этапе компиляции (tcc, win x86/x64)

obfus.h — это библиотека только на макросах для обфускации C-приложений во время компиляции, предназначенная специально для Tiny C (tcc) (скачать можно здесь -> Tiny-C-Compiler/releases). Она ориентирована на платформы Windows x86 и x64 и поддерживает почти все версии компилятора. Очень надёжная броня для ваших C-программ!
Интеграция obfus.h в ваш проект — простой процесс. Просто добавьте следующую строку в ваш код:
#include "obfus.h"
Это автоматически обфусцирует ваш код во время компиляции, обеспечивая защиту и конфиденциальность вашей интеллектуальной собственности.
Доступные опции для настройки защиты:
// 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 protectionили используйте их с аргументами компилятора:
tcc "app.c" -w -D NO_CFLOW -D ANTIDEBUG_V2 -D FAKE_SIGNS -D VIRT
[!WARNING] При компиляции приложения с обфускацией используйте аргумент
-wдля подавления предупреждений. В противном случае в консоли появится множество устрашающих логов, которые никак не влияют на конечный результат. Не стоит их пугаться.
🔐 Защита от отладки активируется вызовами многих базовых функций MSVCRT.
В критических местах кода вы можете использовать конструкцию ANTI_DEBUG;. Например:
ANTI_DEBUG;
if (!licenseExpired()) {
// ...
}
Макрос HIDE_STRING(str) обфусцирует и визуально скрывает строки, мутируя их, что значительно усложняет их поиск и патчинг в исходном коде. При таком объявлении строки собираются на стеке через инструкции mov, а не загружаются целиком. Этот метод гарантирует, что строки не объявляются статически, а создаются во время выполнения, что делает их менее уязвимыми для статического анализа. Однако важно отметить, что эту возможность нельзя использовать для скрытия статических полей при их объявлении, так как она включает вызов функции.
[!IMPORTANT] Некоторые декомпиляторы всё же могут раскрыть их из-за статических оптимизаций. В выводе дизассемблера код будет выглядеть сложным и громоздким, что может отпугнуть поверхностный анализ, но не всегда полностью предотвратит целеустремлённые попытки реверс-инжиниринга.
Пример вызова функции printf из стандартной библиотеки со статическим скрытием сообщения и его расшифровкой на стеке:
char *hidden_message = HIDE_STRING("Hello, world!");
// ...
printf(hidden_message);
Это техника защиты, при которой некоторые вычисления выполняются через встроенную виртуальную машину по команде. Делает анализ математических операций очень сложным! Работает только при включённой опции VIRT (и только!). В противном случае все команды виртуальной машины будут заменены обычными математическими операторами.
[!WARNING] Виртуализация в критических местах может повлиять на оптимизацию. Используйте с осторожностью только там, где это действительно необходимо
Виртуальная машина не поддерживает некоторые базовые операции сравнения с
double.
Вы можете использовать логические операторы, которые задействуют вызовы виртуальной машины, чтобы ещё сильнее запутать понимание вашего кода:
| Operator | Description |
|---|---|
VM_IF |
Это не полная замена if/else, а лишь усложнение стандартных операторов.
Простой пример использования виртуализации:
// ...
#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
}
Примеры использования всех функций виртуальной машины можно найти в файле tests/virtualmachine.c
Если вам нужна продвинутая защита от опытных реверсеров, используйте опции CFLOW_V2 и 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");
}
}
Для использования рекомендуется последняя версия Tiny C (0.9.27). К сожалению, некоторые версии компилятора не поддерживают функциональность, необходимую для полной обфускации. Visual C, GCC и Clang не поддерживаются и вряд ли будут поддерживаться.
Вы можете использовать специальный скрипт для Windows, чтобы получить последние версии obfus.h, загрузив пакет из официального репозитория. Это полезно, если вам нужно автоматизировать обновления безопасности без использования git.
Например, вы можете использовать его перед сборкой проекта:
+ C:\...> call obfh-update C:\...> tcc app.c -wСкрипт обновит содержимое файла obfus.h в текущем каталоге (согласно указанной конфигурации)
Код программы (и её исходная логика), защищённый с помощью obfus.h , почти невозможно восстановить (деобфусцировать). Однако использование этого обфускатора не гарантирует полной защиты от всех типов угроз. Важно разрабатывать и поддерживать внутренние системы безопасности программы.
Как будет выглядеть код после обфускации:
Реверсер увидит примерно это, если попытается использовать декомпилятор:
Вот как все скрытые строки через функцию
HIDE_STRINGвыглядят в дизассемблере (архитектура 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 . . . ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Спасибо всем, кто помогал в разработке этого проекта. Я ценю это! ❤️
И спасибо вам 🤝 за то, что обратили внимание на этот проект!
| Function | Type | Op | Description | Example |
|---|
VM_ADD | long | + | Складывает два числа | VM_ADD(5, 3) = 8 |
VM_SUB | long | - | Вычитает два числа | VM_SUB(5, 3) = 2 |
VM_MUL | long | * | Умножает два числа | VM_MUL(5, 3) = 15 |
VM_DIV | long | / | Делит два числа | VM_DIV(6, 3) = 2 |
VM_MOD | long | % | Вычисляет остаток от деления двух чисел | VM_MOD(5, 3) = 2 |
VM_EQU | BOOL | == | Проверяет, равны ли два числа | VM_EQU(5, 5) = true |
VM_NEQ | BOOL | != | Проверяет, не равны ли два числа | VM_NEQ(5, 3) = true |
VM_LSS | BOOL | < | Проверяет, меньше ли первое число второго | VM_LSS(3, 5) = true |
VM_GTR | BOOL | > | Проверяет, больше ли первое число второго | VM_GTR(5, 3) = true |
VM_LEQ | BOOL | <= | Проверяет, меньше или равно ли первое число второму | VM_LEQ(3, 5) = true |
VM_GEQ | BOOL | >= | Проверяет, больше или равно ли первое число второму | VM_GEQ(5, 3) = true |
VM_ADD_DBL | long double | + | Складывает два числа типа double | VM_ADD_DBL(5.5, 3.2) = ≈8.7 |
VM_SUB_DBL | long double | - | Вычитает два числа типа double | VM_SUB_DBL(5.5, 3.2) = ≈2.3 |
VM_MUL_DBL | long double | * | Умножает два числа типа double | VM_MUL_DBL(5.5, 3.2) = ≈17.6 |
VM_DIV_DBL | long double | / | Делит два числа типа double | VM_DIV_DBL(6.0, 3.0) = ≈2.0 |
VM_LSS_DBL | BOOL | < | Проверяет, меньше ли первое число double второго числа double | VM_LSS_DBL(3.5, 5.2) = true |
VM_GTR_DBL | BOOL | > | Проверяет, больше ли первое число double второго числа double | VM_GTR_DBL(5.5, 3.2) = true |
Используйте вместо if |
VM_ELSE_IF | Используйте вместо else if |
VM_ELSE | Используйте вместо else |