Всем привет. Многие знают об этой замечательной игре — LIMBO! Вы даже наверняка покупали ее в Стиме, или качали с торрентов…
Я тоже ее купил когда-то (что и вам советую!), и прошел). Но, как всегда, мне было этого мало, и я, из спортивного интереса, решил изучить ее защиту. Так и появился кейген к игре LIMBO.
В этой статье я расскажу и покажу вам, как я это делал.
Прежде, чем начинать, помните: все действия вы выполняете на свой страх и риск. Уважайте работу геймдевелоперов.
Этап первый: Поверхностный осмотр пациента
Полный инсталлятор игры можно скачать здесь. Установив игру, первым делом, как обычно, выясняем, на чем написан главный исполняемый файл. Я воспользуюсь для этого ExeInfo PE.
Видим: Visual Studio 2008. IDA Pro прекрасно с ней справляется, поэтому туда и отправим. Я буду пользоваться связкой IDA Pro + HexRays, т.е. с декомпилятором — для ускорения работы.
Этап второй: что мы ищем?
Первым делом, дадим Иде проанализировать limbo.exe — главный исполняемый файл игры.
Далее, нужно определить, что именно мы, собственно, хотим найти здесь. Запустим игру:
Видим волшебную надпись "UNLOCK FULL GAME". На нее и нажмем. Далее нас ожидает нежданчик (по крайней мере, я, когда первый раз выбирал этот пункт меню, я ожидал увидеть поле ввода на графическом движке игры, или типа того, а оказалось все гораздо проще...):
Да, да! Именно обычное окошко! Нам же легче. Попробуем что-нибудь ввести, и нажать Unlock. Как-то так:
Ну что ж, поищем по тексту в IDA, чтобы затем от него отталкиваться, и найти место проверки. И тут меня ожидал облом…
По тексту сообщения в окне ошибки Ида мне ничего не нашла! То же самое сказал мне и поиск по содержимому через Total Commander. Возможно, сообщение зашифровано. Можно попробовать найти вызов окна отталкиваясь от вызова MessageBoxA/W. Но, я пошел другим путем, который, почему-то, мало где в статьях описывают.
Этап третий: Нажми меня
Мы поступим следующим образом. Откроем любой удобный Вам редактор ресурсов, затащим в него ехе-шник, найдем окошко диалога ввода ключа, а в нем — кнопку Unlock. Сказано — сделано:
На скрине я выделил ID нашей кнопки. По нему мы и будем искать, где именно обрабатывается нажатие. Откроем Иду, нажмем Alt+I (Search -> immediate value...), введем число 203 (без 0x, т.к. десятичное), и посмотрим, что найдется. А нашлось вот это:
Видите те строчки, которые Ида пометила как ; nIDDlgItem? С них и начнем. Двойным кликом переходим на первый из таких результатов:
Зеленой стрелкой я обозначил место, на которое указала Ида, а чуть ниже (привычка: прокручивать выше/ниже искомого места) — стрелкой обозначено место вызова одной интересной API-функции: GetDlgItemTextA. Судя
Почему я сразу не искал по ID поля ввода? Можно, конечно и так было сделать. Но, мало ли какие действия происходят после нажатия кнопки, еще до вычитывания текста из поля.
Итак, проследим, куда уходит полученный серийник. Прокручиваем листинг, чтобы видеть место вызова API-функции целиком:
Мой "намыленный" взгляд подсказывает мне, что полученный буфер (Ида обозначила его как var_134) передается прямиком в следующую за вызовом GetDlgItemTextA функцию, которая возвращает в al нулевое, либо ненулевое значение (похоже на результат проверки ключа). Давайте проверим догадку…
Этап четыре: Декомпиляция
Заходим в функцию. Видим там прыжок на еще один адрес — переходим по нему. Видим нормальный код, поэтому смело жмем там F5 (вызываем HexRays Decompiler).
bool __cdecl sub_48D410(int a1)
{
int v1; // esi@7
char *v2; // ebp@7
unsigned int v3; // edi@7
int v4; // ST28_4@9
int v5; // edx@9
int v6; // eax@12
bool result; // al@12
char v8; // [sp+4h] [bp-44h]@8
char v9; // [sp+Ch] [bp-3Ch]@12
char v10; // [sp+1Ch] [bp-2Ch]@7
char v11; // [sp+3Ch] [bp-Ch]@12
if ( strlen((const char *)a1) != 37
|| *(_BYTE *)(a1 + 5) != 45
|| *(_BYTE *)(a1 + 11) != 45
|| *(_BYTE *)(a1 + 17) != 45
|| *(_BYTE *)(a1 + 23) != 45
|| *(_BYTE *)(a1 + 30) != 45 )
{
result = 0;
}
else
{
v1 = 0;
v2 = &v10;
v3 = 0;
do
{
v8 = *(_BYTE *)(v3 + a1);
if ( v8 != 45 )
{
v4 = (char)sub_412EBD(v8);
v1 += v4 << 5 * (3 - v5);
if ( v5 == 3 )
{
v2 += sprintf(v2, "%05lx", v1);
v1 = 0;
}
}
++v3;
}
while ( v3 < 0x25 );
v6 = sub_40C48C(&v10, 32);
sprintf(&v9, "%08x", v6);
result = strcmp(&v9, &v11) == 0;
}
return result;
}
Теперь можно попытаться привести этот код к более адекватному.
Первым делом, замечаем, что входной параметр имеет тип int, что не совсем правда. Обозначим его как "char *". Для этого становимся на имя функции и жмем там клавишу Y (Set item type). Исправляем тип и имя входного параметра (я обозвал его как key).
Далее… Видим строчку:
if ( strlen(key) != 37 || key[5] != 45 || key[11] != 45 || key[17] != 45 || key[23] != 45 || key[30] != 45 )
Т.к. наш входной параметр — строка, давайте в тех местах, где символы ключа сверяются с числами, исправим на сравнение с символами. Для этого на каждом из таких чисел нажмем R (Char). Уже лучше:
if ( strlen(key) != 37 || key[5] != '-' || key[11] != '-' || key[17] != '-' || key[23] != '-' || key[30] != '-' )
Теперь цикл:
v1 = 0;
v2 = &v10;
v3 = 0;
do
{
v8 = key[v3];
if ( v8 != 45 )
{
v4 = (char)sub_412EBD(v8);
v1 += v4 << 5 * (3 - v5);
if ( v5 == 3 )
{
v2 += sprintf(v2, "%05lx", v1);
v1 = 0;
}
}
++v3;
}
while ( v3 < 0x25 );
Для наглядности дадим v3 имя i, т.к. похоже, что она используется как итератор. Переименовываем нажатием на имени клавиши N (Name).
Замечаем, что в цикле происходит взятие каждого символа из ключа, и передача его в пока неизвестную нам функцию. Предлагаю выяснить, что это за функция. Двойным щелчком переходим в нее. Видим там вызов еще одной функции, переходим туда. И, вот оно — обработка одиночного символа! (Здесь есть куча работы для клавиши R, но я лишь покажу сразу результат обработки).
char __cdecl convert_char(char C)
{
char _C; // al@1
_C = C;
if ( C < '0' )
return -1;
if ( C <= '9' )
return C - '0';
if ( C < 'A' )
return -1;
if ( C <= 'Z' )
{
if ( C != 'I' && C != 'L' && C != 'O' && C != 'U' )
{
if ( C >= 'U' )
_C = C - 1;
if ( _C >= 'O' )
--_C;
if ( _C >= 'L' )
--_C;
if ( _C >= 'I' )
--_C;
return _C - '7';
}
return -1;
}
if ( C < 'a' || C > 'z' || C == 'i' || C == 'l' || C == 'o' || C == 'u' )
return -1;
if ( C >= 'u' )
_C = C - 1;
if ( _C >= 'o' )
--_C;
if ( _C >= 'l' )
--_C;
if ( _C >= 'i' )
--_C;
return _C - 'W';
}
Прекрасно! Теперь возвращаемся назад клавишей Esc до основной функции. Замечаем, что IDA сама переопределила для нас тип результата возвращаемого функцией обработки символа. Именуем дальше, обозначаем типы, и получаем следующий код цикла:
sum = 0;
x5buf = v10;
i = 0;
do
{
C = key[i];
if ( C != '-' )
{
new_c = j_convert_char(C);
sum += new_c << 5 * (3 - itr);
if ( itr == 3 )
{
x5buf += sprintf(x5buf, "%05lx", sum);
sum = 0;
}
}
++i;
}
while ( i < 0x25 );
Если вы заметили, то тут есть одна интересная бага декомпилера. Видим, что переменная, обозначенная у меня как itr, совершенно не инкрементируется. Чтобы выяснить, что на самом деле происходит, жмем ПКМ -> Copy to assembly, и смотрим, где же используется наша itr. Выясняем: она инкрементируется прямо в этом цикле (чего и стоило ожидать), а до цикла — обнуляется. Учтем это при написании кейгена.
Теперь вторая часть функции проверки ключа… У нас осталась одна неисследованная функция, которая, кстати, очень похожа на функцию подсчета CRC32. Результат обработки (пусть и на скорую руку, но читаемый):
int __cdecl calc_crc32(char *my_key, int len)
{
int i; // ebp@1
unsigned int _xor; // ecx@1
char *_my_key; // edi@2
char C; // al@3
signed int mask; // edx@3
int B; // esi@3
bool bit; // al@4
int crc32; // eax@10
signed int _len; // edx@10
i = len;
_xor = 0xFFFFFFFF;
if ( len )
{
_my_key = my_key;
do
{
C = *_my_key;
--i;
++_my_key;
mask = 1;
B = (unsigned __int8)C;
do
{
bit = (_xor & 0x80000000) == 0x80000000;
_xor *= 2;
if ( B & mask )
bit = bit == 0;
if ( bit )
_xor ^= 0x4C11DB7u;
mask *= 2;
}
while ( (_BYTE)mask );
}
while ( i );
}
crc32 = _xor & 1;
_len = 0x1F;
do
{
_xor >>= 1;
crc32 = _xor & 1 | 2 * crc32;
--_len;
}
while ( _len );
return ~crc32;
}
Оставшийся кусок (преобразованный):
crc32 = j_calc_crc32(my_key, 32);
sprintf(crc32_, "%08x", crc32);
result = strcmp(crc32_, &my_key[32]) == 0;
Этап пять: написание кейгена
Задача: определить, что именно происходило с ключом, чтобы написать обратную функцию. Писать я буду, вопреки здравому смыслу и выдаче HexRays, на Delphi, а Вы можете писать на том языке, который проще именно Вам.
Путем отладки выясняем произошедшее:
- Игре нужен ключ в 32 символа без дефисов (37 — с дефисами).
- Берется по четыре символа из ключа (не учитываются дефисы). Каждый из них пропускается через функцию convert_char и суммируется по формуле: sum += new_c << 5 * (3 — itr);
- Каждая такая сумма преобразовывается в lower-case хекс-строку (5 символов) и доклеивается до имеющейся (итого 40 символов);
- Берется CRC32 от первых 32-х символов получившейся строки и сравнивается с оставшимися восемью символами полученной в предыдущем пункте строки;
- Если строки не совпали — наш ключ неправильный.
Обратное мышление:
- Написать функцию, преобразующую 40-символьный хэш обратно в ключ;
- Сгенерировать 32-символьный хэш;
- Посчитать от него 8-символьный CRC32;
- Склеить строки, полученные на этапах (2) и (3);
- Передать в функцию (1) — получим искомый ключ.
Мысли о преобразующей функции:
- Т.к. входной хэш был получен из восьми 5-символьных хэш-кусков, будем обрабатывать его так же, по "пятеркам";
- Каждая "пятерка" была получена из четырех символов ключа;
- Т.к. при каждом вычислении "пятерки", она сдвигалась на 5 бит влево, получается, что на каждый символ ключа приходится 5 бит;
- Внимательное рассмотрение кода функции convert_char приводит нас к такой мысли, что набор символов ключа ограничивается лишь символами набора "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
- Итого: 32 символа хэша генерятся из "пятерок". 32 % 5 = 24 целых символа и 2 в остатке — т.е. два символа нам придется просто догенерить.
function GenHash(len: byte): string;
var
i, k: byte;
sum: integer;
begin
Randomize;
Result := '';
sum := 0;
k := 0;
for i := 1 to len do
begin
sum := sum + (Random(Length(alphabet)) shl ((3 - k) * 5));
Inc(k);
if k = 4 then
begin
Result := Result + AnsiLowerCase(Int2Hex(sum, 5));
sum := 0;
k := 0;
end;
end;
Result := Result + 'a0'; // Решил не баловаться, а оставить два случайных хекс символа
end;
Далее считаем CRC32 от хэша:
var
key, hash, crc32: string;
begin
hash := GenHash(24);
crc32 := Crc32b(hash); // нашел первый попавшийся модуль, реализующий данный хэш-алгоритм
Код функции-преобразователя:
function Hash2Code(const Hash: string): string;
var
s: string;
five: integer;
begin
Result := '';
s := Hash;
while Length(s) > 0 do
begin
five := Hex2Int(Copy(s, 1, 5));
Delete(s, 1, 5);
Result := Result + alphabet[(five and $F8000 shr 15) + 1] +
alphabet[(five and $07C00 shr 10) + 1] +
alphabet[(five and $003E0 shr 05) + 1] +
alphabet[(five and $0001F shr 00) + 1];
end;
end;
Ну и, наконец, результирующее получение лицензионного ключа:
key := Hash2Code(hash + crc32);
lic_code := Format('%s-%s-%s-%s-%s-%s', [Copy(key, 1, 5),
Copy(key, 6, 5),
Copy(key, 11, 5),
Copy(key, 16, 5),
Copy(key, 21, 6),
Copy(key, 27, 6)
]);
Проверяем, и… Ввод сгенеренного ключа активировал игру, пункт активации исчез!
Итоги
Главное при написании кейгена — уметь обратно думать. Т.е. уметь написать такой алгоритм, который будет обратным тому, который вы имеете. Это непростая задача, но, и она решаема в большинстве случаев.
P.S.
Возможно, статья получилась слишком сумбурной, не знаю. Главная идея, которую я хотел донести: кейген — не такая и сложная штука, если есть мозги, и желание вместе с усидчивостью.
P.P.S.
В следующей статье я опишу, как я писал кейген к другой игре — Unepic.
Комментарии (76)
robert_ayrapetyan
17.04.2015 05:43+13Самая интересная и крутая защита, которую приходилось отламывать:
Прога под дос, переходит в защищенный режим, делает кучу телодвижений с таблицами дескрипторов, попутно распаковываясь, затем читает определенные сектора HDD через порты. Время: две недели почти круглосуточно, т.к. фактически приходилось эмулировать все действо в Win SoftICE. Назначение софта: некая оболочка для работы с швейным оборудованием.DrMefistO Автор
17.04.2015 09:43+4У меня тоже есть свой опыт «самой крутой» ненавесной защиты. Но описать ее кейгенинг в статье просто нереально, т.к. будет множество отсылок на «набитую руку» и «намыленный взгляд».
vmchaz
17.04.2015 13:59+4Читать про такое всегда интересно.
Нестандартные приёмы работы с ОС (а порой и оборудованием) и их обход — это читается как детектив.
Так что пишите!
vmchaz
17.04.2015 13:54В каком году это было?
Возможно ли было заэмулировать всё это дело в Bochs, к примеру? (там есть встроенный отладчик)robert_ayrapetyan
17.04.2015 18:31Более 10 лет назад, про Bochs тогда еще не слышал… Сомневаюсь что получилось бы проще.
kelevra
17.04.2015 06:42+5такое и защитой-то язык не поворачивается назвать. уж очень громкое название статьи :)
Scratch
17.04.2015 09:26-26Мне тоже непонятно, почему автор решил открыть тут филиал кряклаба для самых маленьких. Таких статей базилион на профильных сайтах. Но если пипл хавает, то пусть будет.
DrMefistO Автор
17.04.2015 09:40+14Не так уж и много статей по кейгенингу. Их раз-два и обчелся.
Scratch
17.04.2015 09:50-1Давайте я поясню почему я к вам придираюсь. Мне кажется, что на хабр следует писать статьи, в которых описывается что то новое и эксклюзивное. Вот ВМПрот, например, еще публично никто не разобрал, это было бы интересно. А такие вот новичковые статьи про патчинг, кейгены из CRC32, которых реально сотни, я считаю не совсем тут к месту.
DrMefistO Автор
17.04.2015 09:52+7Дайте мне в личку хоть одну статью про "кейгены из CRC32". Тогда я с вами соглашусь.
И почему новая статья о процессе кейгенинга известного продукта не является «новой и эксклюзивной»?Scratch
17.04.2015 10:01-4exelab.ru/art/?action=list&f=8 Выбирайте на свой вкус. Куча статей о кейгенах к реальным известным продуктам. Продуктов много, а статей об интересных защитах единицы
DrMefistO Автор
17.04.2015 10:08+3Читал я эти статьи. Не все из них простые для понимания и не ко всем из них уже можно достать ломаемый софт. Затем, я решил воспользоваться новыми (с 2005 года — даты последней статьи) представившимися возможностями в плане софта: IDA Pro (именно статья, в которой используется IDA Pro), HexRays, возможность втиснуть скриншоты. На exelab все статьи чисто текстовые.
DrMefistO Автор
17.04.2015 09:56+2VMProtect публично никто не хочет разбирать лишь потому, чтобы софт, защищенный им, можно было ломать, не опасаясь выхода новой версии протектора. Собственно, так со многими навесными защитами и происходит, если они достаточно тяжелые для снятия.
Dim0FF
17.04.2015 22:47+1А вот вы могли бы на пальцах объяснить, что такого делает VMProtect, что его настолько сложно взломать?
Ну то есть в программе всё равно где-то должна быть проверка вроде if (key.IsValid()), где можно всегда возвращать условный true.
Очевидно, что это не так, но в чём сложности и как именно запутывают не осознаю.JKornev
22.04.2015 17:13На самом деле VMProtect не такой уж и крутой протектор, его фишкой является возможность обфускации кода или интерпритация на собственных виртуальных машинах, такое сложно исследовать и патчить, так как условный переход может быть размазан на десяток ветвлений и т.п.
cher11
17.04.2015 10:00+20И много в последнее время на Хабре нового и эксклюзивного? Внезапно — для меня этим оказались две статьи DrMefistO.
Почему вы отсылаете людей на всякие непонятные профильные ресурсы, если все отлично (и в тему) расписано тут?MennyCalavera
17.04.2015 10:48-2Туториалы по взлому — тема скользкая. Наверняка рано или поздно этот пост увидит и создатель игры (кто-нибудь ему/им ссылку-то точно скинет на Гугл Транслейт). И тогда это приобретет неприятный оттенок. Можно исследовать что угодно, но не стояло выкладывать алгоритм генерации на Хабр — это мерзко. Статья могла остаться интересной и без него.
А по поводу самой защиты — соглашусь с тем, кто сказал, что её тут и нет вовсе. Разработчики достаточно наивно подошли к этому вопросу. С верой в лучшее, так сказать.DrMefistO Автор
17.04.2015 10:50+5Вы правы. Поэтому некоторые моменты я сознательно опускал, чтобы прям целиком не выкладывать работающий код.
Но, в свое оправдание, я могу сказать, что авторам писал еще давным давно, с той целью, чтобы они улучшили алгоритм. Плюс, ажиотаж к игре прошел.
NeuroTechnic
23.04.2015 09:04Пфф, есть мнение, что наличие кряка на продажах не особо отражается. Для массового софта.
К тому же rip этого лимбо на любом торрент-трекере можно найти и даже кейгеном пользоваться не придется.
DrMefistO Автор
17.04.2015 09:36+1В моем понимании лицензионная защита — это то, каким образом сделана лицензионная система в программе.
dvserg
17.04.2015 10:00+1А где традиционное… «Вся приведенная в статье информация предназначена исключительно для образовательных целей. Все ваши действия вы производите на свой страх и риск. Автор не несет ответственности ни за какие последствия Ваших действий»?
megaDRONe
17.04.2015 09:18+21Покупайте хорошие инди игр, не ломайте их. Маленькие независимые разработчики игр, все же, в первую очередь думают, как игру сделать, а не защиту похитрее написать. Говорю от лица инди гейм девелоперов. :)
Вот статья про взлом защиты какого-нибудь энтерпрайз софта была бы намного интереснее и циничнее имхо.DrMefistO Автор
17.04.2015 09:38Я полностью с вами согласен! Но, опять же, цель не в том, чтобы обидеть разрабов (им я писал, но ответа не получил), а чтобы кто-то не сделал это с плохой целью (например, барыженье ключами).
dvserg
17.04.2015 10:08Можете сразу от интересного к полезному перейти — предложить разработчикам методы улучшения защиты ))
DrMefistO Автор
17.04.2015 10:10+1Ответа на мое письмо, отправленное разрабам еще 12.04.13, я не получил. Значит улучшать защиту они не хотят. Да и смысла нету уже: все кто хотели, купили и сыграли.
megaDRONe
17.04.2015 10:22+3Я думаю, что они и без вас прекрасно понимают, что их игру легко сломать и не пытались это решить, в надежде, что найдутся люди, которые принципиально купят, даже если кряк будет лежать по соседней ссылке.
В любом случае, статься достаточно интересная, хоть и косвенно поощряет не самые порядочные пути в жизни.DrMefistO Автор
17.04.2015 10:24+8=) Я всегда считал и буду считать: "If you like it, you will buy it!"
siemdi
17.04.2015 10:09+12Выше в комментариях я встретил упоминание что это не защита и т.д.
Так вот что я хочу сказать, если Вы прочитали просто много статей про обход защиты и Вам кажется что это слишком просто, то попробуйте на примере автора обойти своими ручками ходить одну защиту, даже самую простую.
Автору спасибо, т.к. эта тема очень специфическая и очень интересная.REU
17.04.2015 11:30А если человек делает вывод не по прочитаным статьям, а по реальному опыту, тогда что?
siemdi
17.04.2015 12:13Если кому — то просто, то не стоит заходить в топик. darked
REU Предполагается что Вы родились сразу со «скилом» Взлома?)REU
17.04.2015 12:45+2Когда я начинал у меня не было интернета и статей ) а были диски с варезом и в каком-то из них было пару хтмл о отладке и патчинге винрара выдраных с какого-то сайта, пропатчил по ней винрар, немного понял суть, пропатчил вторую, третью,… программу. Потом появился кое какой интернет и желание кейгенить, решил попробовать на простеньком кейгенми, алгорит понимал, но как обратить нет, создал тему на кряклабе (одна с первых :) ) мне там объяснили (да, тогда еще там помагали новичкам :) ) я снова понял суть, и снова много практики во время которой постигаешь новые приемы и техники, всё. )
DrMefistO Автор
17.04.2015 13:43А я начинал вообще с перевода консольных игр на русский язык. Отсюда появилась тяга к реверсу.
Дальше: статьи кряклаба, крякмисы… Писал много статей по патчингу популярных программ.
А затем я понял, что патчи — не тот уровень уже. Надо бы и кейгены научиться делать. Так я и написал свой первый кейген.)
Столько воды утекло.
Потом, списавшись с одним челом по поводу ArtMoney (о которой я тоже как-нибудь напишу), я решил попробовать вступить в одну реверс-команду. Так я и стал участником той тимы, которая чуть ниже в комментах засветилась на скрине)
darked
17.04.2015 11:58+5Поддерживаю всех поддерживающих автора ) Спасибо за статью. Если кому — то просто, то не стоит заходить в топик.
Интересен не сам взлом как таковой — а как логическая задача. Интересно почитать ход мыслей, посмотреть примеры пользование инструментарием.
Spin7ion
17.04.2015 12:17Скажите, а возможно ли модифицировать функцию sub_48D410 чтобы она возвращала всегда корректность ключа, так ли создаются таблетки?
Статья очень интересная, спасибо.vmchaz
17.04.2015 13:49+1Да, можно, и так делают самые простые патчи.
У этого способа есть один минус — меняется исполняемый код. Т.е. из другого места можно просканировать собственный код и понять, правили его или нет.
К примеру, если где-то в дальше игре есть код, который вычисляет MD5 участка кода с защитой, и полученным числом расшифровывает какие-нибудь ресурсы, которые используются ближе к концу игры, то это может вызвать некоторое недовольство воспользовавшихся патчем (а обычно просто проверяют — запустилось или нет). Кстати, такое поведение вполне может стимулировать продажи игры.
Кстати, ещё можно вызывать функцию CheckSerial() с заведомо неправильным номером и, если она вернула True, считать код пропатченным и действовать соответственно.DrMefistO Автор
17.04.2015 13:53+1Именно поэтому кейген всегда лучше! Но он и усилий больших требует, понятное дело.
MrAnonymous
17.04.2015 13:01+14А я сделал реверсинг картинке :)
Restorator 2007 — D:\TPORT\unepic_ko\limbo\limbo.exe
Я прав?DrMefistO Автор
17.04.2015 13:39Вы правы!) Просто не хотел папку палить) Ибо это цель следующей статьи) Да и имя тимы светится)
Неудачно получилось))
AndreyDmitriev
17.04.2015 16:20+1первым делом, как обычно, выясняем, на чем написан главный исполняемый файл.
Видим: Visual Studio 2008.
Это ещё как бы ни о чём не говорит. Вот вам, для разнообразия, крякми, который Exeinfo PE распознаётся как «Microsoft Visual C++ 9.0 — Visual Studio 2008», но написан не на VS:
CrackMeLV.7z
Кстати, сможете отреверсить пароль, который приведёт к результату, отличному от Access Denied? Ну или как минимум модифицировать исполняемый файл, так, чтобы в ответ на любой пароль получить доступ (это сильно проще)?
Вирусов там нет, деструктивных действий код не выполняет, все рантайм библиотеки приложены, исходники естественно вышлю по запросу. Пароль существует и однозначно реверсится из кода.DrMefistO Автор
17.04.2015 16:22+4Это челендж?)
AndreyDmitriev
17.04.2015 16:30Челендж — если будет угодно.
Я знаю, как бы я стал ломать эту штуку (но у меня подход предвзятый, поскольку сам её и написал), но любопытно, как вы подойдёте к снаряду (если есть время недолгими весенними вечерами). Там есть пара забавных мест. Зубодробительных алгоритмов для проверки пароля и обфускаций там не заложено, а изюминка — именно в использованном, скажем так, несколько нетрадиционном, средстве разработки.
DrMefistO Автор
17.04.2015 16:27Программы идентификаторы подсказывают, чем скомпилирована программа, в первую очередь.
REU
17.04.2015 17:10Что-то оно не похоже на крякми…
DrMefistO Автор
17.04.2015 17:11Ну, тут либо крякать, либо кейгенить. Вполне можно.
REU
17.04.2015 17:16Я к тому что внутри много чего лишнего
AndreyDmitriev
17.04.2015 17:34Это так. Рантайм там весьма увесистый. Собственно в коде лишнего почти нет, хотя я немного «разнёс» места, где производится нажатие и собственно сравнение. Но чтобы туда добраться, придётся продраться через дебри рантайма, да.
AndreyDmitriev
17.04.2015 17:24Чем же не похоже? Мне казалось, крякми примерно так и выглядят — ну разве что поле «Password» — его кто «Key», кто «Serial» называет. А в остальном — есть исходный код, он скомпилирован в исполняемый файл. Все библиотеки, что там в архиве — они к среде исполнения относятся (их там два рантайма). По идее их надо было инсталляторами разворачивать, но я их бросил в ту же директорию для удобства.
Если крякми с вашей точки зрения по-другому должен выглядеть — напишите как.
Бывает ещё кейгенми — там обычно два поля, связанных алгоритмом и требуется написать программку, воспроизводящую зашитый туда алгоритм.
Gol
17.04.2015 21:05Я правильно понимаю, если игрушку защитить чем-то таким — написать кряк или ещё как-то поломать вообще не получится?
robert_ayrapetyan
17.04.2015 21:29отсутвующий код или часть приложения никогда ни при каких условиях не покидает доверенные сервера
Как минимум, если это правда, приложение без доступа в инет вообще будет неработоспособно (очень сомнительная защита).
В студенческие годы пытался создать нечто подобное, но с реализацией в аппаратном устройстве со спец. FPGA процем, идея была в том что без этого спец. устройства код, даже сграбленый, будет тормозить на настольном ПК, но дальше теорий все это не ушло.
Если наврали — то как минимум одному человеку придется таки купить, ну а потом собрать «полную локальную версию» — дело техники )Gol
17.04.2015 21:51Ну, я так понял что защита для сетевых игрушек, которые без инета и так не работают нормально
robert_ayrapetyan
17.04.2015 22:31Как правило, в сетевых игрушках и так легко вычислить\забанить левых пользователей не особо изощряясь, поэтому польза от такой навороченной защиты сомнительна. Неизвестно, есть ли у них вообще поддержка js и пр. В примере на сайте у них «Сапер» и Notepad++ на сях, и метки именно в код в VS встроены, похоже они ориентированы на защиту «локального» десктопного софта.
Но вообще все это попытки продать то, что умерло 10 лет назад, под новым соусом…Gol
17.04.2015 23:08Про js не знаю, на сайте вроде ничего нету про такое. Про игрушки знаю только что тренировались на Doom 3 и на TTD, вроде норм работает.
А что 10 лет назад умерло, если не секрет?robert_ayrapetyan
17.04.2015 23:35Ну весь этот рынок навесных защит, armadillo, execryptor и т.п. Вообще в первую очередь «умер» рынок десктопного софта, все ушло в веб и на моб. платформы…
Stiver
17.04.2015 23:39Выше правильно заметили про ассиметричную криптографию. Смотрел как-то софт, а там обычная RSA, простенько и со вкусом. Повезло, что 256-битная оказалась, удалось разложить. А начиная самое позднее с 1024 можно тушить свет.
foxmuldercp
18.04.2015 01:06Эм, это имеется в виду однонавправленное шифрование серийника в наборе процедур которые скажут «серийник валиден, работай на здоровье»?
Ivan_83
Было бы не так весело будь там асимметричное крипто. Впрочем вводить такое руками тоже не весело.
DrMefistO Автор
Я понимаю. Поэтому для статьи я выбирал наиболее простой вариант, чтобы на нем можно было обучить.