Button Up
StarForce C++ Obfuscator

StarForce C++ Obfuscator

Эффективное решение, предназначенное для обфускации (преобразования) исходных текстов программ, написанных на языках C и C++ (поддерживает стандарты C++98, С++ 03, С++ 11, С++ 14, С++ 17), с целью их защиты от реверс-инжиниринга. В результате обфускации код программы получает надежную защиту от анализа, выполняемого как человеком, так и машиной.

Протестировать StarForce C++ Obfuscator


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;
}
 

download



Наши клиенты


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

Крис Касперски

shield В результате защиты обфусцированным получается как исходный текст, так и бинарный код, что значительно увеличивает уровень взломостойкости.
tools

Обфускатор поддерживает более 30 методов обфускации, которые можно независимо включать, выключать и настраивать с помощью конфигурационного файла. Среди наиболее эффективных методов можно назвать:


преобразование кода С++ в код виртуальной машины;
шифрование строк и массивов;
преобразование кода в цифровой автомат;
введение ложных связей;
объединение участков кода.
OS Поддержка любых операционных систем: Windows, macOS, Linux, iOS, Android.
app Отдельное приложение, которое устанавливается на стороне заказчика.
clock Различные модели лицензирования (с ограничением и без ограничения по времени использования).
clock Возможность устанавливать разные настройки для разных участков кода.
clock Запуск из командной строки.

Защита кода от анализа и модификации в играх


Защита кода игр


Описание ситуации


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


Решение


Продукт StarForce C++ Obfuscator защищает код от анализа и модификации. При этом разработчик сам определяет уровень защиты для разных участков кода, чтобы не снижать производительность игры. В результате обфускации каждый раз получается новая версия бинарного кода, что делает невозможным использование старых читов.


Защита исходного кода при передаче программы третьим лицам


Защита кода от третьих лиц


Описание ситуации


Может возникнуть ситуация, когда нужно защитить код от анализа и модификации. Причины могут быть различны – защита уникальных алгоритмов, сокрытие части кода, блокировка возможности вносить изменения и т.д.


Решение


Использование StarForce C++ Obfuscator защищает от обратного инжиниринга и позволяет сохранить тайны вашей программы в секрете.


Защита от потери ключей при использовании стандартных DRM


Защита от потери ключей DRM


Описание ситуации


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


Решение


StarForce C++ Obfuscator позволяет защитить программное обеспечение, предназначенное для передачи, приёма или воспроизведения цифрового аудио или видеопотока, защищённого с использованием стандартных систем DRM. В результате обфускации код, отвечающий за работу с ключами, надежно защищен от анализа и модификации.


Защита клиентской части системы стандартной DRM

Защита клиентской части DRM


Описание ситуации


Клиентская часть любой стандартной DRM-системы, например, OMA DRM, подвержена атакам, сводящимся к анализу, модификации и отключению защиты. В зависимости от DRM, эта атака может привести к компрометации либо одного защищённого объекта, либо всех защищённых объектов одного пользователя, либо всех защищённых объектов системы.


Решение


StarForce C++ Obfuscator позволяет снизить риск взлома DRM благодаря существенному увеличению сложности анализа. Детали использования обфускатора (т. е. что и как нужно обфусцировать) сильно зависят от системы. Для оптимального решения проблемы рекомендуется консультация технических специалистов StarForce.


Защита собственной DRM от анализа


Защита клиентской части 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 Провести тестирование скомпилированного приложения и убедиться в том, что оно функционально эквивалентно приложению, скомпилированному из необфусцированных файлов.

Для более удобного использования обфускатора используйте возможность интеграции его в процесс сборки приложения.

Обфускатор может работать на следующих операционных системах


Windows 7 32/64-bit. Windows Vista 32/64-bit.
Windows 8 32/64-bit. Windows 10 32/64-bit.
Windows Server 32/64-bit. Linux (опция).
macOS (Wine).

Обфускатор требует для работы


350 Mb дискового пространства для установки. 4 Гб RAM.

Обфускатор имеет следующие параметры совместимости с С++


Поддерживаемые компиляторы

MSVC6.0, MSVC7.0, MSVC7.1+. GCC 3.
GCC 4.

Поддерживаемые стандарты C++ ISO/IEC

C++98. C++03.
C++11. C++14.
C++17.

Поддерживаемые целевые платформы для C++


Windows. Linux.
Android. macOS.
iOS.


Не поддерживается обфускация следующих языковых конструкций


Функции, содержащие Structured Exception Handling (SEH). Конструкторы и деструкторы.
Шаблоны (template) функций и методы шаблонных классов (template classes). Некоторые другие конструкции, используемые реже перечисленных. Полный список ограничений содержится в руководстве пользователя.

Техническая документация


Документ Описание Действие
StarForce C++ Obfuscator. Описание продукта Описание продукта: функциональные характеристики, состав, системные требования Открыть
Лицензия Цена
Лицензия на защиту неограниченного числа продуктов без ограничения по времени (первое рабочее место) 700000 рублей
Лицензия на защиту неограниченного числа продуктов без ограничения по времени (каждое дополнительное рабочее место) Запросить
Лицензия на защиту 1 продукта на 2 рабочих места, с ограничением по времени на 1 год Запросить
Лицензия на защиту 1 продукта на 1 рабочее место, с ограничением по времени на 1 год Запросить

Протестировать StarForce C++ Obfuscator

Новости компании

29.02.2024
07.02.2024
06.02.2024
25.10.2023
������ ����� � ����� ��� macOS
������ ������ �� USB