Blog. Just Blog

Исследование защиты программы Deep Green Reversi

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Темная сторона Силы | Автор: ManHunter
Скриншот программы Deep Green Reversi
Скриншот программы Deep Green Reversi

И снова мои любимые реверси! Сегодня это будут Deep Green Reversi. Дизайн у этой игрушки просто чудовищный, нагруженный свистоперделками и всякими спецэффектами по самое небалуйся. К счастью, практически все их можно отключить в настройках. Сайт разработчика тоже застрял где-то на заре интернета, когда считалось хорошим тоном оформлять странички вырвиглазными анимированными гифками и неоновыми шрифтами. Но все это сразу забывается, когда начинаешь играть. Кроме обычной настройки сложности, в Deep Green Reversi настраивается и стратегия игры компьютера, например, хитрый захват углов или смешанный режим игры. В результате компьютер становится отличным соперником. Если не хватает машинного интеллекта, можете сыграть с кем-нибудь по сети или с товарищем за одним компьютером. Еще в набор минусов следует отнести шароварность игры, но это дело как раз поправимо.

Скачиваем дистрибутив с офсайта, устанавливаем, запускаем, смотрим. Внешними признаками незарегистрированной программы являются характерные надписи в заголовке и в окне "О программе".

Программа не зарегистрирована
Программа не зарегистрирована

Еще на сайте что-то написано про 30 дней триального срока, но это пока оставим. Начнем с поиска строк "Unregistered".

Строка в файле
Строка в файле

Количество статей по исследованию защит уже давно перевалило за сотню, надо ли в очередной раз напоминать, что главный исполняемый файл после установки должен находиться на вскрытии в дизассемблере? Ну так вот, нужную строчку в файле мы нашли, поищем в листинге дизассемблера место, где она используется.
  1. .text:00401956                 mov     ecx, [ebx+5A4h]
  2. .text:0040195C                 push    ecx
  3. ; Вызвать функцию проверки
  4. .text:0040195D                 call    sub_40F954
  5. .text:00401962                 pop     ecx
  6. .text:00401963                 test    eax, eax
  7. ; Если она вернула EAX!=0, то в заголовок ничего не добавлять
  8. .text:00401965                 jnz     loc_401A26
  9. .text:0040196B                 mov     word ptr [esi+10h], 14h
  10. .text:00401971                 xor     eax, eax
  11. .text:00401973                 lea     edx, [ebp+var_8]
  12. .text:00401976                 mov     [ebp+var_8], eax
  13. .text:00401979                 mov     eax, ebx
  14. .text:0040197B                 inc     dword ptr [esi+1Ch]
  15. .text:0040197E                 call    @TControl@GetText$qqrv
  16. .text:00401983                 lea     edx, [ebp+var_8]
  17. .text:00401986                 push    edx
  18. ; Добавить в заголовок окна строчку "Unregistered"
  19. .text:00401987                 mov     edx, offset aUnregistered
  20. ; " - Unregistered"
  21. .text:0040198C                 lea     eax, [ebp+var_C]
  22. .text:0040198F                 call    sub_55FD64
  23. .text:00401994                 inc     dword ptr [esi+1Ch]
Ничего необычного, вызов функции проверки и условный переход по ее результатам. Все это мы тоже видели не один раз. Сама функция проверки совсем небольшая:
  1. .text:0040F954                 push    ebp
  2. .text:0040F955                 mov     ebp, esp
  3. .text:0040F957                 mov     eax, [ebp+arg_0]
  4. .text:0040F95A                 cmp     dword ptr [eax+80630h], 1
  5. .text:0040F961                 jnz     short loc_40F96A
  6. .text:0040F963                 mov     eax, 1
  7. .text:0040F968                 pop     ebp
  8. .text:0040F969                 retn
  9. .text:0040F96A ; -------------------------------
  10. .text:0040F96A loc_40F96A:
  11. .text:0040F96A                 xor     eax, eax
  12. .text:0040F96C                 pop     ebp
  13. .text:0040F96D                 retn
Можно просто пропатчить условный переход или команду XOR EAX,EAX, но меня тут смущает команда cmp dword ptr [eax+80630h], 1. Это проверка значения флага "зарегистрировано", который инициализируется где-то в другом месте. Так почему бы нам не превратить функцию проверки заодно в функцию инициализации флага? Патчить придется немного больше, но и результат буде лучше:

Функция проверки регистрации после патча
Функция проверки регистрации после патча

Вот теперь можно сохранять изменения и проверять работоспособность игры. Надписи в заголовке и в окне "О программе" пропали.

Программа успешно "зарегистрирована"
Программа успешно "зарегистрирована"

Для чистоты эксперимента переводим часы на пару месяцев вперед и вновь проверяем работоспособность. Ограничения по времени тоже нет. Цель достигнута, можно спокойно наслаждаться игрой.

В комментариях справедливо указали, что патчить совсем не обязательно, а можно подсмотреть правильный серийный номер при проверке введенных регистрационных данных. Начнем с того, как программа отреагирует на заведомо неправильные регистрационные данные:

Сообщение о неправильной регистрации
Сообщение о неправильной регистрации

Строчка легко обнаруживается в файле, но вот прямых ссылок на нее в дизассемблере найти не удалось. Автор позаботился об этом, и, по всей видимости, сделал косвенную адресацию. Но зато рядом с этим строками есть другие, на которые IDA любезно выдает подсказку, что ссылающаяся процедура называется "TRegistrationForm_RegBtnClick".
  1. .data:00587638 aXorolc_0       db '[Xorolc]',0
  2. ; DATA XREF: _TRegistrationForm_RegBtnClick
  3. .data:00587641 aXorolc@tno_c_1 db 'Xorolc@tNO.com',0
  4. .data:00587650 aDoYouFeelGuilt db 'Do you feel guilty using this registration?',0
  5. ...
  6. .data:0058772B                 db    0
  7. .data:0058772C aInvalidRegistr db 'Invalid Registration',0
  8. .data:00587741 aThankYouForReg db 'Thank you for Registering.',0
Похоже, что это забаненный ник и email, который уже релизили в публичный доступ. Что ж, неизвестный крякер нам помог, по перекрестной ссылке мы попадаем в функцию обработки нажатия на кнопку "Register". Она достаточно объемная, прямых ссылок на тексты сообщений, как я уже говорил, в ней нет, поэтому надо воспользоваться отладчиком. Зарузим игру под отладчиком, поставим точку останова на начало функции обработчика по адресу 004128B8 и повторим регистрацию с левыми данными. Когда сработает точка останова, в пошаговом режиме, не спеша, начнем трассировку. Сперва будет много проверок на то, что данные вообще введены, сравнения регистрационных данных с забаненными значениями и, наконец, мы выходим на следующий код:
  1. .text:00412B39                 mov     eax, off_59375C
  2. .text:00412B3E                 mov     ecx, [eax]
  3. .text:00412B40                 mov     eax, [ecx+5A4h]
  4. .text:00412B46                 push    eax             ; int
  5. ; Вызвать функцию проверки
  6. .text:00412B47                 call    sub_40F710
  7. .text:00412B4C                 add     esp, 14h
  8. ; Если она вернула EAX=1, то установить EDX=1
  9. .text:00412B4F                 test    eax, eax
  10. .text:00412B51                 setz    dl
  11. .text:00412B54                 and     edx, 1
  12. .text:00412B57                 lea     eax, [ebp+var_2C]
  13. ; Сохранить значение EDX в стеке
  14. .text:00412B5A                 push    edx
  15. .text:00412B5B                 mov     edx, 2
  16. .text:00412B60                 dec     dword ptr [esi+1Ch]
  17. .text:00412B63                 call    sub_55FEC4
  18. .text:00412B68                 dec     dword ptr [esi+1Ch]
  19. .text:00412B6B                 lea     eax, [ebp+var_28]
  20. .text:00412B6E                 mov     edx, 2
  21. .text:00412B73                 call    sub_55FEC4
  22. .text:00412B78                 dec     dword ptr [esi+1Ch]
  23. .text:00412B7B                 lea     eax, [ebp+var_24]
  24. .text:00412B7E                 mov     edx, 2
  25. .text:00412B83                 call    sub_55FEC4
  26. .text:00412B88                 dec     dword ptr [esi+1Ch]
  27. .text:00412B8B                 lea     eax, [ebp+var_20]
  28. .text:00412B8E                 mov     edx, 2
  29. .text:00412B93                 call    sub_55FEC4
  30. ; Забрать сохраненное значение из стека
  31. .text:00412B98                 pop     ecx
  32. ; CL=1 ?
  33. .text:00412B99                 test    cl, cl
  34. ; Да, переход
  35. .text:00412B9B                 jz      short loc_412BE9
  36. ; Вывести сообщение о неправильной регистрации
  37. .text:00412B9D                 mov     word ptr [esi+10h], 44h
  38. ; Вот здесь неявно загружается указатель на строку "Invalid Registration"
  39. .text:00412BA3                 lea     edx, [edi+0F4h]
  40. .text:00412BA9                 lea     eax, [ebp+var_30]
  41. .text:00412BAC                 call    sub_55FD64
  42. .text:00412BB1                 inc     dword ptr [esi+1Ch]
  43. .text:00412BB4                 mov     eax, [eax]
  44. ; Вывести сообщение
  45. .text:00412BB6                 call    @Dialogs@ShowMessage
  46. .text:00412BBB                 dec     dword ptr [esi+1Ch]
Хоть я и привел нужный код с самого начала, выйти на него удалось только в момент загрузки в регистр EDX неявного указателя на строку "Invalid Registration" (адрес 00412BA3). И только после этого можно раскрутить в обратном порядке его логику. Теперь переходим непосредственно к функции проверки серийника. Ее также надо пройти под отладчиком, я же буду выкладывать ее по частям с комментариями:
  1. .text:0040F725                 jmp     short loc_40F72E
  2. .text:0040F727 ; -------------------------------
  3. .text:0040F727 loc_40F727:
  4. .text:0040F727                 movsx   eax, byte ptr [esi]
  5. .text:0040F72A                 add     ebx, eax
  6. .text:0040F72C                 inc     edi
  7. .text:0040F72D                 inc     esi
  8. .text:0040F72E loc_40F72E:
  9. .text:0040F72E                 mov     edx, [ebp+s]
  10. .text:0040F731                 push    edx             ; s
  11. .text:0040F732                 call    _strlen
  12. .text:0040F737                 pop     ecx
  13. .text:0040F738                 cmp     edi, eax
  14. .text:0040F73A                 jb      short loc_40F727
Здесь берется регистрационное имя и побайтно суммируется.
  1. .text:0040F743                 jmp     short loc_40F74C
  2. .text:0040F745 ; -------------------------------
  3. .text:0040F745 loc_40F745:
  4. .text:0040F745                 movsx   eax, byte ptr [esi]
  5. .text:0040F748                 add     ebx, eax
  6. .text:0040F74A                 inc     edi
  7. .text:0040F74B                 inc     esi
  8. .text:0040F74C loc_40F74C:
  9. .text:0040F74C                 mov     edx, [ebp+arg_8]
  10. .text:0040F74F                 push    edx             ; s
  11. .text:0040F750                 call    _strlen
  12. .text:0040F755                 pop     ecx
  13. .text:0040F756                 cmp     edi, eax
  14. .text:0040F758                 jb      short loc_40F745
Здесь аналогичным циклом к сумме байт имени добавляется сумма байт регистрационной почты. Весь итог хранится в регистре EBX.
  1. ; Прибавить к EBX константу 9C5h и занести это все в EDX
  2. .text:0040F7A7                 lea     edx, [ebx+9C5h]
  3. .text:0040F7AD                 push    edx
  4. : Перевести число в строку
  5. .text:0040F7AE                 call    unknown_libname_25
  6. ; BCC v4.x/5.x & BCB v1.0/v7.0 BDS2006 win32 runtime
  7. .text:0040F7B3                 add     esp, 0Ch
  8. .text:0040F7B6                 mov     edx, [ebp+arg_C]
  9. ; Побайтно сравнить с первой частью введенного серийника
  10. .text:0040F7B9 loc_40F7B9:
  11. .text:0040F7B9                 mov     cl, [eax]
  12. .text:0040F7BB                 cmp     cl, [edx]
  13. .text:0040F7BD                 jnz     loc_40F941
  14. .text:0040F7C3                 test    cl, cl
  15. .text:0040F7C5                 jz      short loc_40F7DD
  16. .text:0040F7C7                 mov     cl, [eax+1]
  17. .text:0040F7CA                 cmp     cl, [edx+1]
  18. .text:0040F7CD                 jnz     loc_40F941
  19. .text:0040F7D3                 add     eax, 2
  20. .text:0040F7D6                 add     edx, 2
  21. .text:0040F7D9                 test    cl, cl
  22. .text:0040F7DB                 jnz     short loc_40F7B9
Здесь к сумме символов добавляется константа 9C5h, затем полученное значение переводится в четырехзначное десятичное число и сравнивается с первой половиной серийника. Отлично, половина дела сделана.
  1. ; Заполнить массив константами
  2. .text:0040F76C                 mov     [ebp+var_404], 0D87h
  3. .text:0040F776                 mov     [ebp+var_400], 2234h
  4. .text:0040F780                 mov     [ebp+var_3FC], 2231h
  5. .text:0040F78A                 mov     [ebp+var_3F8], 128Bh
  6. .text:0040F794                 mov     [ebp+var_3F4], 15ADh
  7. ...
  8. ...
  9. ...
  10. .text:0040F7EC                 mov     eax, ebx
  11. .text:0040F7EE                 mov     ecx, 5
  12. .text:0040F7F3                 xor     edx, edx
  13. ; Разделить сумму символов на 5
  14. .text:0040F7F5                 div     ecx
  15. ; Остаток - индекс массива с константой
  16. .text:0040F7F7                 mov     eax, [ebp+edx*4+var_404]
  17. .text:0040F7FE                 push    eax
  18. ; Перевести константу в строку
  19. .text:0040F7FF                 call    unknown_libname_25
  20. ; BCC v4.x/5.x & BCB v1.0/v7.0 BDS2006 win32 runtime
  21. .text:0040F804                 add     esp, 0Ch
  22. .text:0040F807                 mov     edx, [ebp+arg_10]
  23. ; Побайтно сравнить со второй половиной серийника
  24. .text:0040F80A loc_40F80A:
  25. .text:0040F80A                 mov     cl, [eax]
  26. .text:0040F80C                 cmp     cl, [edx]
  27. .text:0040F80E                 jnz     loc_40F941
  28. .text:0040F814                 test    cl, cl
  29. .text:0040F816                 jz      short loc_40F82E
  30. .text:0040F818                 mov     cl, [eax+1]
  31. .text:0040F81B                 cmp     cl, [edx+1]
  32. .text:0040F81E                 jnz     loc_40F941
  33. .text:0040F824                 add     eax, 2
  34. .text:0040F827                 add     edx, 2
  35. .text:0040F82A                 test    cl, cl
  36. .text:0040F82C                 jnz     short loc_40F80A
  37. .text:0040F82E loc_40F82E:
  38. .text:0040F82E                 jnz     loc_40F941
  39. .text:0040F834                 mov     eax, [ebp+arg_0]
  40. ; Установить флаг "Зарегистрировано"
  41. .text:0040F837                 mov     dword ptr [eax+80630h], 1
Тут снова берется сумма символов, делится на 5, остаток является индексом от 0 до 4 в массиве с константами [0D87h, 2234h, 2231h, 128Bh, 15ADh]. То есть вторая половина серийника может быть только одним из этих пяти значений. Перед сравнением константа из массива переводится в строку с десятичным числом. Подставляем найденные значения в форму регистрации.

Программа успешно зарегистрирована
Программа успешно зарегистрирована

Кейген теперь вы можете написать самостоятельно. Кстати, регистрацию это чудо хранит аж в "c:\Program Files\Common Files\Fileid.bin". Ну да, чего ж еще ожидать от программы с такиим наворотами. Вот теперь действительно все.

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 1568 | Комментариев: 10

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
brute (16.11.2015 в 21:20):
До самого конца так и нет логического выхода на адрес 0040F954.. В IDR видна процедура обработки регистрации (по названию и форме) - 4128b8, также (методом тыка, по надписи "Invalid Registration" в стеке) находится переход на правильную регистрацию: 00412B99 test cl,cl (что не ведёт к регистрации - только сообщение!). Написано про ф-ю по адресу 00412B47, которая должна вернуть 1, причём принудительное mov dl,1 вместо sete dl не помогает!! Привел разбор ф. 00412B47: " Установить флаг "Зарегистрировано" .text:0040F837 mov   dword ptr [eax+80630h], 1".  Вот это и непонятно: как узнал, что В ЭТОЙ функции какой-то "левый" байт[eax+80630h] регистрирует программу?  (и как нашёл 0040F954?). От 0040F82E jnz loc_40F941 до сообщения о регистрации километр кода!!!
Игорь (22.10.2015 в 23:16):
Mahnhunter а можете статью написать по снятию защиты с какой-нибудь программы упакованную asprotect 2.1/2.2./2.3SKE?
X-Wing Top Ace (19.10.2015 в 11:13):
Кряк получился очень элегантный. С таким можно и не подсматривать регистрационный номер.
ManHunter (19.10.2015 в 10:31):
Ага, я это тоже заметил, когда подбирал серийник. Поэтому пришлось искать, куда оно сохраняет регу, чтобы пройти регистрацию уже в нормальном режиме.
Noobie (19.10.2015 в 09:45):
Забавно другое: если во время трассировки устанавливать флаг Z во время сравнения произвольного и правильного номера, то программа перепишет файл bin и будет считать себя зарегенной, при любых значениях серийника, то есть его проверка осуществляется только в момент ввода, а дальше рояли не играет. Поэтому сериал 1234-5678 вполне валидный :-)
user (19.10.2015 в 03:02):
ЦитатаЗачем?

)) Затем, что программы не на одном компьютере работают, и на них регулярно чистки случаются. Или просто распаковать программу и работать с нею, или ещё возиться с "регистрациями". Даже если в виде .reg-файла - всё равно напряжно.
ManHunter (19.10.2015 в 00:05):
Добавил полный разбор алгоритма регистрации.
Vnv (18.10.2015 в 18:36):
Цитатапостоянно вводить єту абракадабру?

Зачем? Один раз ввел, подсмотрел свой код и ... Вот мой:
Vnv
com@com.com
3882-8756
user (18.10.2015 в 18:27):
ЦитатаСумма всех букв имени и e-mail

- а потом постоянно вводить єту абракадабру? - Извините..
Vnv (18.10.2015 в 11:00):
Сумма всех букв имени и e-mail, какие-то преобразования и сверка регистрационного номера, который можно подсмотреть: 0040F710

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0055 сек.) / Память: 4.5 Mb
Наверх