StarForce C++ Obfuscator рекомендуется для защиты программного обеспечения (ПО), к которому предъявляются повышенные требования по взломостойкости, например, защита ключей DRM, защита игр от внедрения постороннего кода (читов и ботов) и защита исходников при передаче/продаже.
StarForce C++ Obfuscator внесен в реестр российского ПО
Существует два подхода к обфускации кода
 |
 |
Обфускация исходного кода |
Обфускация кода с изменением логики программы |
Программа удаляет комментарии, незначащие пробелы и переименовывают макросы/переменные/функции в нечто вида OO000O, при этом, не меняя логику программы. То есть бинарные коды обфусцированного и необфусцированного текста будут выглядеть одинаково. Обычно применяется, когда по условию лицензионного соглашения необходимо предоставить исходный код. |
В этом случае добавляются лишние ветвления, циклы, вызовы функций и т.д. Бинарные коды обфусцированного и необфусцированного текста будут сильно отличаться. При этом каждый раз создается новая версия. Например, для того, чтобы перестали работать существующие читы и боты в игре достаточно заново обфусцировать исходный код, не меняя ничего внутри. Этот вариант обеспечивает самый высокий уровень защиты от анализа и модификации. |
StarForce C++ Obfuscator относится ко второму типу. Он меняет логику программы, используя разные алгоритмы. В настоящий момент этот продукт является одним из лучших на рынке, благодаря использованию большого выбора методов защиты и многолетней работе без компрометации.
Другим преимуществом StarForce C++ Obfuscator является его универсальность: данный продукт может применяться для защиты программ, создаваемых для любых операционных систем и процессоров, в том числе для защиты программно-аппаратных прошивок (firmware).
Пример использования StarForce C++ Obfuscator
Исходный код |
После обфускации |
#include <stdio.h>
// Euclidian algorithm for calculating greatest common divisor (before obfuscation)
int gcd( int n, int m )
{
if( n < 1 || m < 1 ) return -1;
while( n != m )
{
if( n > m ) n -= m;
else m -= n;
}
return n;
}
// Tests in triplets { n, m, expected_gcd( n, m ) }
int tests[][ 3 ] = {
{ 1, 2, 1 },
{ 3, 3, 3 },
{ 42, 56, 14 },
{ 249084, 261183, 111 },
};
// Perform tests
int main( int, char*[] )
{
printf( "Performing tests of gcd function:\n" );
bool passed = true;
for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); i++ )
{
int n = tests[ i ][ 0 ];
int m = tests[ i ][ 1 ];
int expected_gcd = tests[ i ][ 2 ];
int calculated_gcd = gcd( n, m );
printf( " %d. gcd( %d, %d ) = %d, ", i + 1, n, m, calculated_gcd );
if( calculated_gcd == expected_gcd )
{
printf( "OK.\n" );
}
else
{
printf( "error.\n" );
passed = false;
}
}
printf( "Tests %s.\n", passed ? "passed" : "failed" );
return passed ? 0 : 1;
}
|
#include <stdio.h>
// Euclidian algorithm for calculating greatest common divisor (after obfuscation)
int gcd( int n_0, int m_1 )
{
bool temp_12;
unsigned int temp_13;
unsigned int temp_14;
unsigned int temp_15;
unsigned int temp_17;
int temp_26;
int temp_35;
bool temp_36;
unsigned int temp_37;
bool temp_38;
int temp_39;
int temp_40;
int temp_41;
int temp_42;
bool state0_43;
bool state1_44;
bool state2_45;
bool state3_46;
bool state4_47;
bool state5_48;
bool state6_49;
bool state7_50;
L1:
L0:
state0_43 = (bool)1;
state1_44 = (bool)state0_43;
state2_45 = (bool)state1_44;
state3_46 = (bool)state2_45;
goto L126;
L6:
temp_37 = ( unsigned int )(temp_17);
temp_38 = ( bool )( temp_36 == 0 );
if (state0_43) goto L158; else goto L40;
L14:
temp_41 = ( int )(temp_17);
temp_38 = ( bool )( temp_36 == 0 );
if (state0_43) goto L160; else goto L128;
L22:
temp_26 = ( int )(temp_41);
if (state4_47) goto L70; else goto L72;
L24:
temp_41 = (int)state6_49;
temp_42 = temp_41 - temp_40;
temp_26 = (int)temp_42;
temp_35 = temp_39 + temp_42;
temp_39 = (int)temp_35;
if (state1_44) goto L30; else goto L26;
L26:
temp_42 = ( int )( state0_43 == 0 );
temp_26 = temp_42 - temp_39;
temp_41 = (int)temp_26;
temp_35 = temp_40 + temp_26;
temp_40 = (int)temp_35;
goto L30;
L30:
temp_36 = temp_39 != temp_40;
if (temp_36) goto L22; else goto L82;
L38:
state1_44 = ( bool )( state5_48 == 0 );
temp_26 = temp_39 + temp_35;
temp_42 = ( int )( state5_48 == 0 );
temp_42 = temp_42 - temp_35;
temp_40 = temp_26 + temp_42;
temp_41 = (int)1495809726u;
// The next string is really just an assignment on 32bit platform
temp_41 = ( int )( ( size_t )( temp_41 ) + ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) >> 15 ) );
goto L44;
L40:
goto L128;
L42:
if (state3_46) goto L82; else goto L84;
L44:
temp_35 = temp_40 ^ temp_41;
temp_42 = (int)1495809726u;
if (state1_44) goto L6; else goto L100;
L46:
temp_41 = ( int )( state4_47 == 0 );
if (state3_46) goto L22; else goto L98;
L48:
// The next string is really just an assignment on 32bit platform
temp_41 = ( int )( ( size_t )( temp_41 ) + ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) >> 15 ) );
if (state7_50) goto L66; else goto L96;
L52:
temp_35 = temp_41 + temp_42;
if (state2_45) goto L76; else goto L94;
L54:
// The next string is really just an assignment on 32bit platform
temp_26 = ( int )( ( size_t )( temp_26 ) + ( ( ( size_t )( temp_26 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_26 ) << 31 ) << 1 ) >> 15 ) );
if (state2_45) goto L14; else goto L102;
L56:
temp_36 = temp_39 <= temp_41;
temp_26 = ( int )(temp_17);
if (state5_48) goto L80; else goto L92;
L58:
temp_37 = (unsigned int)state6_49;
temp_42 = ( int )(temp_38);
if (state2_45) goto L48; else goto L90;
L60:
state2_45 = ( bool )( state6_49 == 0 );
temp_38 = (bool)0u;
if (temp_36) goto L74; else goto L146;
L62:
temp_35 = (int)0;
if (state3_46) goto L26; else goto L104;
L64:
temp_41 = ( int )(temp_17);
state3_46 = ( bool )( state6_49 == 0 );
state4_47 = ( bool )( state6_49 == 0 );
temp_35 = (int)state6_49;
temp_36 = temp_40 <= temp_35;
if (state0_43) goto L162; else goto L154;
L66:
state7_50 = (bool)state6_49;
state5_48 = (bool)state2_45;
temp_39 = (int)-1;
temp_40 = (int)1495809726u;
if (state6_49) goto L22; else goto L42;
L68:
temp_39 = (int)-1;
if (state7_50) goto L88; else goto L86;
L70:
temp_36 = temp_39 > temp_40;
temp_17 = ( unsigned int )(temp_36);
if (temp_36) goto L24; else goto L62;
L72:
temp_42 = temp_35 | temp_26;
temp_41 = temp_35 & temp_26;
temp_17 = ( unsigned int )(temp_42);
temp_37 = ( unsigned int )(temp_41);
temp_38 = temp_17 < temp_37;
if (temp_38) goto L154; else goto L148;
L74:
temp_35 = temp_39 - temp_40;
if (state3_46) goto L106; else goto L14;
L76:
temp_41 = ( int )( state0_43 == 0 );
temp_26 = temp_41 - temp_39;
temp_35 = temp_40 + temp_26;
temp_40 = (int)temp_35;
temp_36 = temp_39 != temp_40;
if (state2_45) goto L154; else goto L40;
L80:
temp_42 = temp_39 + temp_35;
temp_26 = (int)temp_42;
temp_40 = temp_42 - temp_35;
temp_13 = ( unsigned int )(state7_50);
temp_14 = (unsigned int)131u;
temp_13 = temp_13 * temp_14;
temp_14 = (unsigned int)1495809857u;
temp_13 = temp_14 - temp_13;
temp_41 = ( int )( ( ptrdiff_t )( ( temp_13 ) & 0xFFFFFFFF ) );
// The next string is really just an assignment on 32bit platform
temp_41 = ( int )( ( size_t )( temp_41 ) + ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) >> 15 ) );
if (state3_46) goto L164; else goto L152;
L82:
temp_17 = ( unsigned int )(temp_42);
// The next string is really just an assignment on 32bit platform
temp_40 = ( int )( ( size_t )( temp_40 ) + ( ( ( size_t )( temp_40 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_40 ) << 31 ) << 1 ) >> 15 ) );
temp_35 = temp_39 ^ temp_40;
if (state7_50) goto L38; else goto L108;
L84:
// The next string is really just an assignment on 32bit platform
temp_40 = ( int )( ( size_t )( temp_40 ) + ( ( ( size_t )( temp_40 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_40 ) << 31 ) << 1 ) >> 15 ) );
temp_35 = temp_39 ^ temp_40;
temp_41 = (int)1495809726u;
if (state5_48) goto L68; else goto L64;
L86:
// The next string is really just an assignment on 32bit platform
temp_41 = ( int )( ( size_t )( temp_41 ) + ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_41 ) << 31 ) << 1 ) >> 15 ) );
temp_17 = ( unsigned int )(temp_42);
if (state7_50) goto L68; else goto L110;
L88:
state7_50 = ( bool )( state0_43 == 0 );
temp_40 = (int)1495809726u;
state5_48 = ( bool )( state6_49 == 0 );
goto L42;
L90:
temp_38 = (bool)state2_45;
temp_17 = ( unsigned int )(temp_37);
goto L150;
L92:
state2_45 = (bool)state5_48;
temp_37 = (unsigned int)0u;
temp_17 = (unsigned int)0u;
state4_47 = ( bool )( state7_50 == 0 );
temp_26 = ( int )(temp_39);
goto L58;
L94:
temp_26 = (int)836078487u;
goto L156;
L96:
temp_39 = temp_35 ^ temp_41;
temp_17 = ( unsigned int )(temp_36);
return temp_39;
L98:
state2_45 = (bool)state6_49;
temp_42 = (int)836078487u;
// The next string is really just an assignment on 32bit platform
temp_42 = ( int )( ( size_t )( temp_42 ) + ( ( ( size_t )( temp_42 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_42 ) << 31 ) << 1 ) >> 15 ) );
goto L52;
L100:
temp_36 = ( bool )(temp_39);
// The next string is really just an assignment on 32bit platform
temp_42 = ( int )( ( size_t )( temp_42 ) + ( ( ( size_t )( temp_42 ) << 31 ) << 1 ) + ( ( ( ( size_t )( temp_42 ) << 31 ) << 1 ) >> 15 ) );
state6_49 = (bool)state2_45;
temp_39 = temp_35 ^ temp_42;
return temp_39;
L102:
temp_41 = temp_35 - temp_26;
state2_45 = ( bool )( state3_46 == 0 );
state5_48 = ( bool )( state7_50 == 0 );
goto L56;
L104:
temp_42 = ( int )(temp_17);
state3_46 = (bool)state2_45;
temp_36 = temp_40 <= temp_35;
state4_47 = (bool)state0_43;
state5_48 = ( bool )( state6_49 == 0 );
if (temp_36) goto L54; else goto L30;
L106:
temp_17 = ( unsigned int )(temp_40);
temp_41 = temp_35 + temp_26;
goto L152;
L108:
temp_41 = (int)1495809726u;
goto L148;
L110:
temp_39 = temp_35 ^ temp_41;
return temp_39;
L122:
temp_39 = temp_41 - temp_26;
goto L30;
L126:
state4_47 = (bool)state3_46;
state5_48 = (bool)state4_47;
state6_49 = ( bool )( state5_48 == 0 );
state7_50 = ( bool )( state6_49 == 0 );
goto L40;
L128:
state3_46 = ( bool )( state7_50 == 0 );
temp_40 = (int)m_1;
temp_39 = (int)n_0;
goto L46;
L144:
temp_36 = temp_39 > temp_40;
if (temp_36) goto L146; else goto L52;
L146:
temp_36 = ( bool )(temp_37);
temp_42 = ( int )(temp_17);
temp_41 = ( int )(temp_39);
temp_17 = ( unsigned int )(temp_40);
if (state3_46) goto L74; else goto L44;
L148:
if (state7_50) goto L144; else goto L58;
L150:
if (state2_45) goto L44; else goto L60;
L152:
temp_38 = ( bool )(temp_17);
temp_37 = ( unsigned int )(temp_41);
temp_36 = ( bool )(temp_38);
if (state4_47) goto L122; else goto L62;
L154:
temp_17 = ( unsigned int )(temp_36);
if (temp_36) goto L156; else goto L56;
L156:
if (state2_45) goto L46; else goto L54;
L158:
if (temp_38) goto L152; else goto L64;
L160:
if (temp_38) goto L48; else goto L86;
L162:
state5_48 = ( bool )( state6_49 == 0 );
if (temp_36) goto L14; else goto L30;
L164:
state1_44 = ( bool )( state3_46 == 0 );
goto L150;
}
// Tests in triplets { n, m, expected_gcd( n, m ) }
int tests[][ 3 ] = {
{ 1, 2, 1 },
{ 3, 3, 3 },
{ 42, 56, 14 },
{ 249084, 261183, 111 },
};
// Perform tests
int main( int, char*[] )
{
printf( "Performing tests of gcd function:\n" );
bool passed = true;
for( int i = 0; i < sizeof( tests ) / sizeof( tests[ 0 ] ); i++ )
{
int n = tests[ i ][ 0 ];
int m = tests[ i ][ 1 ];
int expected_gcd = tests[ i ][ 2 ];
int calculated_gcd = gcd( n, m );
printf( " %d. gcd( %d, %d ) = %d, ", i + 1, n, m, calculated_gcd );
if( calculated_gcd == expected_gcd )
{
printf( "OK.\n" );
}
else
{
printf( "error.\n" );
passed = false;
}
}
printf( "Tests %s.\n", passed ? "passed" : "failed" );
return passed ? 0 : 1;
}
|

Наши клиенты
Будущее обфускации готовит хакерам совсем не радужные перспективы. … В практическом плане это означает полный мрак стандартным методам анализа кода. Если теоретически возможно (но практически очень и очень сложно) вычистить мусор и удалить избыточность, внесенную «запутывателями», то «распутать» байт-код Сетей Петри уже невозможно. Этот процесс однонаправленный, и развернуть его на 180 градусов практически невозможно.
Крис Касперски
Защита кода от анализа и модификации в играх

Описание ситуации
Основная монетизация игр free-to-play осуществляется за счет продажи платных контента/ресурсов/артефактов. Игроки используют различные мошеннические инструменты (читы и боты), чтобы получить желаемое бесплатно. Чтобы встроить чит, нужно проанализировать код игры и понять, как он работает. При успешной интеграции мошеннического инструмента в игру, издатель теряет свой доход и, как результат, заинтересованность в развитии проекта.
Решение
Продукт StarForce C++ Obfuscator защищает код от анализа и модификации. При этом разработчик сам определяет уровень защиты для разных участков кода, чтобы не снижать производительность игры. В результате обфускации каждый раз получается новая версия бинарного кода, что делает невозможным использование старых читов.
Защита исходного кода при передаче программы третьим лицам

Описание ситуации
Может возникнуть ситуация, когда нужно защитить код от анализа и модификации. Причины могут быть различны – защита уникальных алгоритмов, сокрытие части кода, блокировка возможности вносить изменения и т.д.
Решение
Использование StarForce C++ Obfuscator защищает от обратного инжиниринга и позволяет сохранить тайны вашей программы в секрете.
Защита от потери ключей при использовании стандартных DRM

Описание ситуации
Стандартные DRM, такие как AACS или HDCP используются для ограничения доступа к аудио-, видеопотокам. Их особенностью является наличие секретных ключей для каждой модели пользовательских устройств (телевизоров, плееров, приставок). Утечка ключа устройства приводит к пиратскому распространению контента и в результате отзыву скомпрометированного ключа. После этого устройство перестает работать, а для получения нового ключа производителю приходится заплатить крупную сумму представителю DRM. В некоторых случаях за утечку ключа устройства может быть предусмотрен штраф или приостановка лицензии.
Решение
StarForce C++ Obfuscator позволяет защитить программное обеспечение, предназначенное для передачи, приёма или воспроизведения цифрового аудио или видеопотока, защищённого с использованием стандартных систем DRM. В результате обфускации код, отвечающий за работу с ключами, надежно защищен от анализа и модификации.
Защита клиентской части системы стандартной DRM

Описание ситуации
Клиентская часть любой стандартной DRM-системы, например, OMA DRM, подвержена атакам, сводящимся к анализу, модификации и отключению защиты. В зависимости от DRM, эта атака может привести к компрометации либо одного защищённого объекта, либо всех защищённых объектов одного пользователя, либо всех защищённых объектов системы.
Решение
StarForce C++ Obfuscator позволяет снизить риск взлома DRM благодаря существенному увеличению сложности анализа. Детали использования обфускатора (т. е. что и как нужно обфусцировать) сильно зависят от системы. Для оптимального решения проблемы рекомендуется консультация технических специалистов StarForce.
Защита собственной DRM от анализа

Описание ситуации
Разработка собственной DRM – затратная задача. Если разработчик идёт на это, ему в любом случае необходимо решить задачу защиты от анализа кода DRM, работающего на стороне конечного пользователя. При этом разработчик получает 2 проблемы:
 |
Существенные трудозатраты на создание эффективной защиты от анализа. |
 |
Риск получения недостаточной эффективности защиты от анализа. |
Решение
StarForce C++ Obfuscator позволяет сэкономить время на разработку системы защиты DRM от анализа. При его использовании также обеспечивается высокий и известный заранее уровень эффективности. Оценка уровня эффективности производится разработчиком при принятии решения о приобретении обфускатора на основе анализа результатов обфускации.
StarForce C++ Obfuscator представляет собой stand-alone приложение, защищённое от копирования с помощью продукта StarForce ProActive for Business. На вход обфускатор принимает незащищённые CPP-файлы, в которых с помощью специальных атрибутов помечены функции, требующие защиту от анализа. На выход обфускатор также выдаёт CPP-файлы, но в них соответствующие функции уже обфусцированы.
Использование продукта состоит из следующих шагов:
1 |
Установить StarForce C++ Obfuscator на компьютере разработчика. |
2 |
Активировать продукт. Для этого необходимо запустить исполняемый файл omniform.exe и в появившемся окне ввести серийный номер. |
3 |
Произвести тестовую обфускацию. Для этого нужно: |
А |
Создать файл test_input.cpp со следующим содержимым:
__attribute__((obfuscate(0))) int f1( int a, int b )
{
if( a > b ) return a;
else return b;
}
|
B |
Запустить обфускатор командой obfrun.exe test_input.cpp test_output.cpp. |
C |
Убедиться, что файл test_output.cpp содержит обфусцированный код. |
4 |
Подготовить исходные файлы к обфускации, расставив перед нужными функциями атрибут obfuscate. |
5 |
Настроить обфускатор на работу с нужным компилятором, отредактировав конфигурационные файлы. Подробности описаны в руководстве пользователя. |
7 |
Произвести обфускацию с помощью команды obfrun.exe. |
8 |
Скомпилировать обфусцированные файлы. |
9 |
Провести тестирование скомпилированного приложения и убедиться в том, что оно функционально эквивалентно приложению, скомпилированному из необфусцированных файлов. |
Для более удобного использования обфускатора используйте возможность интеграции его в процесс сборки приложения.