Blog. Just Blog

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

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

Еще одна разновидность моей любимой игры в реверси - Smart Reversi. Игра выпущена уже давно, больше десяти лет назад, но для меня это значения не имеет. Игра классная, логика компьютера скучать не дает. Если бы не различные ограничения в триальной версии и необходимость покупки лицензии, то было бы вообще идеально.

Скачиваем дистрибутив, устанавливаем, смотрим что из этого получается. Сразу бросается в глаза, что главный исполняемый файл упакован навесным протектором ASProtect.

Наг-окно при запуске программы
Наг-окно при запуске программы

Я нашел несколько ограничений незарегистрированной программы: лимит в 14 дней работы, наг-окно при запуске программы, надпись в заголовке окна, надпись в окне "О программе", пункты регистрации в меню, невозможность сохранить и загрузить процесс игры.

Окно "О программе", меню и заголовок главного окна
Окно "О программе", меню и заголовок главного окна

Перевод системного времени показывает, что как минимум ограничение по времени работы программы реализовано средствами ASProtect. При удалении из реестра "часовых бомб" этого протектора триальный срок игры обнуляется.

Для начала надо избавиться от навесной защиты. Здесь использована очень старая версия ASProtect, с ней легко справляется даже статичный распаковщик CASPR. Отправляем распакованный файл в дизассемблер. Файл совсем крохотный, поэтому его анализ займет непродолжительное время. Наиболее приметный признак триальности - текст в заголовке окна. Попробуем найти эту строчку в файле:

Строка сообщения
Строка сообщения

Никаких проблем, строка лежит в открытом виде. Вернемся в дизассемблер и посмотрим, где же она используется:
  1. seg000:00403733                 push    offset ClassName ; "Smart Reversi"
  2. seg000:00403738                 push    eax             ; lpString1
  3. seg000:00403739                 call    ds:lstrcpyA
  4. ; Указатель на строку
  5. seg000:0040373F                 push    ds:lpString     ; lpString
  6. ; Получить длину строки
  7. seg000:00403745                 call    ds:lstrlenA
  8. seg000:0040374B                 mov     esi, ds:lstrcatA
  9. ; Длина строки не нулевая?
  10. seg000:00403751                 test    eax, eax
  11. ; Да, программа считается зарегистрированной
  12. seg000:00403753                 jnz     short loc_403780
  13. ; Надпись "UNREGISTERED" в заголовке окна
  14. seg000:00403755                 push    ds:dword_412F14
  15. seg000:0040375B                 lea     eax, [ebp+String2]
  16. seg000:00403761                 push    offset aUnregisteredDD
  17. ; " [UNREGISTERED %d days left]"
  18. seg000:00403766                 push    eax             ; LPSTR
  19. seg000:00403767                 call    ds:wsprintfA
  20. seg000:0040376D                 add     esp, 0Ch
  21. seg000:00403770                 lea     eax, [ebp+String2]
  22. seg000:00403776                 push    eax             ; lpString2
  23. seg000:00403777                 lea     eax, [ebp+String]
  24. seg000:0040377D                 push    eax             ; lpString1
  25. seg000:0040377E                 call    esi ; lstrcatA
Код чистенький, но поясню словами, что тут происходит. Берется строка по фиксированному адресу, проверяется ее длина. Если строка не пустая, то программа считается зарегистрированной. Чтобы внести еще большую ясность, стоит посмотреть в дизассемблере на перекрестные ссылки, относящиеся к этой строке:

Перекрестные ссылки на строку
Перекрестные ссылки на строку

Если вы имели дело с ASProtect, то сразу же узнаете название одной из функций API этого протектора - GetRegistrationInformation, в которой инициализируется эта строка. Это значит, что вся регистрация программы полностью завязана на навесном протекторе.
  1. seg000:004087A0 GetRegistrationInformation proc near
  2. seg000:004087A0 arg_0           = dword ptr  4
  3. seg000:004087A0                 mov     eax, [esp+arg_0]
  4. seg000:004087A4                 mov     ds:lpString, eax
  5. seg000:004087A9                 retn    4
  6. seg000:004087A9 GetRegistrationInformation endp
Поскольку навесной протектор снят, его API тут бесполезны, значит для обхода оставшихся защитных механизмов основной программы остается пропатчить все участки кода, где проверяется регистрация. Все они находятся по перекрестным ссылкам на строку регистрации. Часть из них отвечает за отображение наг-окна и изменение пунктов меню, а вот код сохранения и загрузки игры выглядит примерно следующим образом:
  1. seg000:00405E05                 push    ds:lpString     ; lpString
  2. seg000:00405E0B                 call    ds:lstrlenA
  3. seg000:00405E11                 xor     ebx, ebx
  4. seg000:00405E13                 test    eax, eax
  5. ; Проверить длину строки
  6. seg000:00405E15                 jnz     short loc_405E4C
  7. ; Если она нулевая, то показать сообщение о невозможности выполнения действия
  8. seg000:00405E17                 push    40h             ; uType
  9. seg000:00405E19                 push    offset Caption  ; "Smart Reversi"
  10. seg000:00405E1E                 push    offset aSaveAndLoadAre
  11. ; "Save and Load are available only in reg"...
  12. seg000:00405E23                 push    ds:hWnd         ; hWnd
  13. seg000:00405E29                 call    ds:MessageBoxA
  14. seg000:00405E2F                 push    ebx             ; dwInitParam
  15. seg000:00405E30                 push    offset sub_402CFB ; lpDialogFunc
  16. seg000:00405E35                 push    ds:hWnd         ; hWndParent
  17. seg000:00405E3B                 push    0B1h            ; lpTemplateName
  18. seg000:00405E40                 push    ds:hInstance    ; hInstance
  19. seg000:00405E46                 call    ds:DialogBoxParamA
  20. seg000:00405E4C loc_405E4C:
  21. ; Сюда выполняется переход, если программа зарегистрирована
  22. seg000:00405E4C                 jmp     short loc_405E52
  23. seg000:00405E4C ; --------------------------------
  24. seg000:00405E4E                 dw 5EBh
  25. seg000:00405E50 ; --------------------------------
  26. seg000:00405E50                 cdq
  27. seg000:00405E51                 cdq
  28. seg000:00405E52 loc_405E52:
  29. seg000:00405E52                 jmp     loc_40614B
  30. seg000:00405E52 ; --------------------------------
  31. seg000:00405E57                 db 0E0h
  32. seg000:00405E58       dd 0B372B1AFh, 12639987h, 0C85D4D71h, 3EF397CAh, 0FCA4F933h
  33. seg000:00405E58       dd 4DC4D812h, 0AE3B3A72h, 4CFC41DBh, 0CE5129A2h, 4D67B5CCh
  34. seg000:00405E58       dd 3E0C0833h, 4C21BCFDh, 6CE95E67h, 0C96456DDh, 5548DBDBh
  35. seg000:00405E58       dd 3DC14919h, 72EC96EBh, 0FA684A7Ah, 0CF427962h, 0D58A48Eh
  36. seg000:00405E58       dd 3D7658D7h, 0B9881E35h, 9F1E944Eh, 77DBC905h, 77D924BFh
  37. seg000:00405E58       dd 19870E08h, 71D71307h, 276E6E2Ah, 0C1B8867Fh, 2D9A2CD3h
  38. seg000:00405E58       dd 0FAC372BDh, 31620821h, 0C5EBD6A4h, 0A79636Fh, 57AF3992h
  39. seg000:00405E58       dd 8B2E150Fh, 0E2222371h, 81FFB93Ah, 1FEFB1B6h, 29751F08h
  40. seg000:00405E58       dd 4FF6386Bh, 3CA9F9AAh, 0EC997986h, 5E0E8C6Ch, 3C42A759h
  41. ...
Сперва выполняется проверка регистрации, если ключа нет, то выводится сообщение, иначе выполняется переход на неидентифицируемую мешанину из бинарных данных, обрамленную безусловными переходами. Опять же, если вы ранее сталкивались с ASProtect, то должны знать, что одна из опций защиты - шифрование кода. Если правильный ключ установлен, то только в этом случае защищенный код будет расшифрован и выполнен, иначе он будет просто пропущен. Здесь как раз такой случай. От навесного протектора и триальных сообщений мы избавились, но функции сохранения и загрузки игры расшифровываются по ключу. Ключа у нас нет, стало быть и доступа к шифрованному коду тоже, и обойти это никак не получится. Увы, но придется ограничиться лишь косметическими изменениями. Впрочем, в данном случае это не страшно, игра автоматически сохраняется при выходе и загружается при старте, а принудительным сохранением и загрузкой я ни разу не пользовался.

Это же касается и окна "О программе". Даже с пропатченными проверками в нем все равно написано, что это ознакомительная версия. Эта небольшая проблемка легко решается в редакторе ресурсов, где можно заменить строку на любую другую, например, вписать вместо нее регистрационное имя:

Исправляем строку в редакторе ресурсов
Исправляем строку в редакторе ресурсов

Сохраняем изменения, запускаем игру. Стартовое наг-окно исчезло вместе с ограничением по времени, в меню больше нет пунктов регистрации, в заголовке окна тоже все в порядке. При попытке сохранить или загрузить игру ничего не происходит, но об этом я уже написал выше.

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

В окне "О программе" отображается регистрационное имя, вписанное в редакторе ресурсов. Будем считать, что защита практически полностью нейтрализована, можно приступать к игре.

Поделиться ссылкой ВКонтакте
Просмотров: 5037 | Комментариев: 7

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (10.03.2015 в 22:04):
На планшете Андроида я иногда вот так дрючу: http://rghost.ru/7GY9HMCgv/image.png
Это на средней сложности. На сложной "сухого" счета пока не получалось.
user (10.03.2015 в 21:46):
Блин. Не умею я играть в эту реверси. Не умею.
Дрючит меня на уровне новичка, как котёнка..
ManHunter (10.03.2015 в 18:47):
Инлайн и лоадеры надо использовать только если не удается распаковать файл до рабочего состояния. Здесь все прекрасно распаковывается, за исключением шифрованных участков, конечно.
user (10.03.2015 в 01:15):
В данном конкретном случае - это слишком гомоздко.
Потенциально нехорошие вещи - получение API недокументированным способом и выделение памяти. Да плюс к тому потом ещё и патч кода во время выполнения.
Это костыли.
brute (09.03.2015 в 21:53):
чтобы было "меньше хирургии", надо применять "aev_injector" (Armadillo Reducer и им подобные программы). Зарегистрированная программа меняет свой код, поэтому, зная места регистрации можно "быстро зарегистрировать" даже не распаковывая. Совсем вручную "с нуля" современные (и будущие) протекторы (имхо) не снять (без многолетних наработок в виде скриптов, скрывающих плагинов, хитрых дамперов и восстановителей ресурсов)
user (09.03.2015 в 15:47):
Добавлю.
Пару раз внаглую удавалось восстановить пошифрованный функционал, имея предыдущую версию с верным ключом и, вынув из неё верно расшифрованные фрагменты, адаптировать их к новой версии, которая без ключа.
Но такие случаи редкость.
user (09.03.2015 в 14:42):
Позволю себе уточнить.
В случае с ASPR'ом удобно найти все ссылки на пустое место в динамической памяти, где должен быть указатель на строку-имя юзера, и поправить их, эти ссылки, на статическую память, где есть пустое место. В том пустом месте статической памяти поместить указатель на следующий DWORD и в нём записать любую желаемую строку(типа имя юзера).
Например, все DWORDs в файле <dd 0041С104h> позаменять на <dd 0040F820h> (7 штук), по этому адресу .40F820h записать <dd 0040F824> (указатель на следующий DWORD)и по этому адресу .40F824: положить любую строку. 
Это чтоб поменьше хирургии. Зачастую эта строка-имя потом отображается и в About'е поправленной программы.

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

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

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