Blog. Just Blog

Исследование защиты программы STOIK Panorama Maker

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

STOIK Panorama Maker - очень удобная программа для создания панорамных снимков из нескольких отдельных кадров, причем можно делать как горизонтальные, так и вертикальные панорамы. Все операции выполняются буквально за несколько кликов мышкой, а результат получается потрясающий. Более простой и удобной программы для создания панорам я пока не встречал. А любой хороший софт просто обязан быть (или стать) бесплатным.

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

Окно регистрации программы
Окно регистрации программы

Аффтары пишут, что программа в течение 15-дневного триального срока полнофункциональная. На самом деле это не так. В бесплатном режиме результат невозможно сохранить, и, как вы уже догадались, сейчас мы будем обходить все эти ограничения. На ввод неправильных регистрационных данных программа реагирует сообщением "Wrong activation key!", поищем его в исполняемом файле.

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

Строка сообщения в ресурсах файла имеет индекс 346 или 15Ah в шестнадцатеричной системе счисления. С похожими ситуациями мы уже неоднократно сталкивались, поэтому как и в прошлые разы поищем это значение в листинге дизассемблера.
  1. .text:004AD136                 mov     ecx, esp
  2. .text:004AD138                 mov     [ebp+108h+var_120], esp
  3. .text:004AD13B                 push    edx
  4. .text:004AD13C                 call    ds:mfc90_300
  5. .text:004AD142                 lea     eax, [ebp+108h+var_120]
  6. .text:004AD145                 push    eax
  7. ; Вызвать функцию проверки
  8. .text:004AD146                 call    loc_4A1D80
  9. .text:004AD14B                 add     esp, 8
  10. ; По умолчанию будем считать, что программа не зарегистрирована (BL=1)
  11. .text:004AD14E                 mov     ebx, 1
  12. .text:004AD153                 push    offset aOk      ; "Ok"
  13. .text:004AD158                 mov     ecx, eax
  14. .text:004AD15A                 mov     byte ptr [ebp+108h+var_10C], bl
  15. .text:004AD15D                 mov     [ebp+108h+var_134], ebx
  16. ; Сравнить результат функции проверки со строкой 'Ok'
  17. .text:004AD160                 call    ds:mfc90_1603
  18. .text:004AD166                 test    eax, eax
  19. .text:004AD168                 jnz     short loc_4AD188
  20. ; Если совпадает, то программа действительно зарегистрирована
  21. .text:004AD16A                 push    ecx
  22. .text:004AD16B                 lea     edx, [ebp+108h+var_11C]
  23. .text:004AD16E                 mov     ecx, esp
  24. .text:004AD170                 mov     [ebp+108h+var_12C], esp
  25. .text:004AD173                 push    edx
  26. .text:004AD174                 call    ds:mfc90_300
  27. .text:004AD17A                 call    sub_4ACDC0
  28. .text:004AD17F                 add     esp, 4
  29. .text:004AD182                 cmp     eax, esi
  30. .text:004AD184                 jnz     short loc_4AD188
  31. ; После успешного прохождения всех проверок обнулить регистр BL
  32. .text:004AD186                 xor     bl, bl
  33. .text:004AD188 loc_4AD188:
  34. .text:004AD188                 lea     ecx, [ebp+108h+var_120] ; void *
  35. .text:004AD18B                 mov     [ebp+108h+var_10C], esi
  36. .text:004AD18E                 call    ds:mfc90_601
  37. ; Программа зарегистрирована (BL=0) ?
  38. .text:004AD194                 test    bl, bl
  39. .text:004AD196                 jz      short loc_4AD1AA
  40. .text:004AD198 loc_4AD198:
  41. ; Вывести сообщение "Wrong activation key!"
  42. .text:004AD198                 push    0FFFFFFFFh
  43. .text:004AD19A                 push    esi
  44. .text:004AD19B                 push    15Ah
  45. .text:004AD1A0                 call    mfc90_1182
  46. .text:004AD1A5                 jmp     loc_4AD2DA
Теперь посмотрим на вызываемую функцию проверки. Мы помним, что она должна вернуть строчку "Ok", поэтому поищем все, что так или иначе связано с этой строкой. Найдется вот такой кусочек кода:
  1. ; Выполнить сравнение
  2. .text:004A1EAE                 cmp     edx, eax
  3. ; Если не равно, то переход на возврат значения "Error"
  4. .text:004A1EB0                 jnz     short loc_4A1F15
  5. .text:004A1EB2                 inc     ecx
  6. .text:004A1EB3                 cmp     ecx, 6
  7. .text:004A1EB6                 jl      short loc_4A1E73
  8. .text:004A1EB8                 add     ebp, 7
  9. .text:004A1EBB                 cmp     ebp, 1Ch
  10. .text:004A1EBE                 jl      short loc_4A1E6D
  11. ; Вернуть значение "Ok"
  12. .text:004A1EC0                 mov     esi, [esp+18h]
  13. .text:004A1EC4                 push    offset aOk      ; "Ok"
  14. .text:004A1EC9                 mov     ecx, esi
  15. .text:004A1ECB                 call    ds:mfc90_310
  16. ...
  17. ; Часть второстепенного кода опущена
  18. ...
  19. .text:004A1F15 loc_4A1F15:
  20. .text:004A1F15                 mov     esi, [esp+18h]
  21. ; Вернуть значение "Error"
  22. .text:004A1F19                 push    offset aError_0 ; "Error"
  23. .text:004A1F1E                 mov     ecx, esi
  24. ...
Простыми патчами на возврат EAX=1 тут не обойтись, но достаточно забить командами NOP единственный условный переход по адресу 004A1EB0, ведущий к возврату ошибки. После этого программа примет любой регистрационный ключ как родной. Код около места патча достаточно "приметный", так что можно легко выделить сигнатуру для поиска и сделать универсальный патч для всех последующих версий программы.

При анализе ассемблерного листинга в районе вызова проверок серийного номера я несколько раз натыкался на файл под названием "stpnm2.key". Поискав на диске этот файл я обнаружил, что он находится в папке %ProgramData%\stpnm2.key и в него в текстовом виде записывается введенный регистрационный ключ плюс первым байтом длину ключа. То есть мало того, что программа гадит в реестре, так еще и распихивает свои файлы куда ни попадя. Причем при деинсталляции файл ключа не удаляется. В который раз убеждаюсь, что хорошие манеры программирования сейчас большая редкость. Но может быть эта информация будет полезной для любителей делать портативные сборки разного софта.

С патчами все понятно, теперь попробуем разобрать алгоритм проверки и, соответственно, алгоритм генерации правильного серийного номера. Для этого поставим точку останова на начало уже знакомой нам функции проверки по адресу 004A1D80 и пройдем ее под отладчиком, введя какой-нибудь неправильный серийный номер. Еще в листинге дизассемблера бросается в глаза интересная конструкция, в которой из строки получаются значения по определенной маске.
  1. ...
  2. .text:004A1E03                 push    edx
  3. .text:004A1E04                 push    offset a6c6c6c6c6c6c6c
  4. ; "%6c-%6c-%6c-%6c-%6c-%6c-%6c-%6c"
  5. .text:004A1E09                 lea     ecx, [esp+0A4h]
  6. .text:004A1E10                 call    ds:mfc90_910
  7. .text:004A1E16                 push    eax
  8. .text:004A1E17                 call    ds:sscanf
  9. ...
Теперь мы знаем формат серийного номера - 8 групп по 6 символов, разделенных черточками. Что интересно, полученные после этой операции данные нигде не используются и даже не проверяются на валидность. Ладно, зная формат, придумаем какой-нибудь серийный номер заведомо неправильный, но подходящий по формату, например, "AAAAAA-BBBBBB-CCCCCC-DDDDDD-EEEEEE-FFFFFF-GGGGGG-HHHHHH". Стартуем программу под отладчиком, вводим его в окно регистрации и в пошаговом режиме доходим до уже знакомого кода, но на этот раз уже с целью добиться понимания алгоритма проверки:
  1. ...
  2. ; Взять следующий символ из серийного номера
  3. .text:004A1E73                 movsx   eax, byte ptr [esi+ecx]
  4. ; Умножить на 343FDh
  5. .text:004A1E77                 imul    eax, 343FDh
  6. ; Прибавить 269EC3h
  7. .text:004A1E7D                 add     eax, 269EC3h
  8. .text:004A1E82                 mov     dword_504F84, eax
  9. ; Двоичный сдвиг
  10. .text:004A1E87                 shr     eax, 10h
  11. ; Сброс всех битов кроме первых 8
  12. .text:004A1E8A                 and     eax, 7FFFh
  13. ; Обнулиить EDX
  14. .text:004A1E8F                 cdq
  15. ; Поделить на 24h (значение видно под отладчиком)
  16. .text:004A1E90                 idiv    edi
  17. ; Если результат вышел за некие границы, то серийник неправильный
  18. .text:004A1E92                 test    edx, edx
  19. .text:004A1E94                 jl      loc_4A1F35
  20. .text:004A1E9A                 cmp     edx, edi
  21. .text:004A1E9C                 jge     loc_4A1F35
  22. ; Взять символ из проверочного массива и сравнить его с символом из серийника
  23. ; Проверочный массив - строка "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  24. ; Индекс элемента - значение регистра EDX
  25. .text:004A1EA2                 movzx   edx, byte ptr [ebx+edx]
  26. .text:004A1EA6                 lea     eax, [ecx+ebp]
  27. .text:004A1EA9                 movsx   eax, byte ptr [esp+eax+4Ch]
  28. .text:004A1EAE                 cmp     edx, eax
  29. ; Не совпало - серийный номер неправильный
  30. .text:004A1EB0                 jnz     short loc_4A1F15
  31. ; Следующий символ
  32. .text:004A1EB2                 inc     ecx
  33. .text:004A1EB3                 cmp     ecx, 6
  34. ; Группа символов обработана?
  35. .text:004A1EB6                 jl      short loc_4A1E73
  36. ; Следующая группа
  37. .text:004A1EB8                 add     ebp, 7
  38. .text:004A1EBB                 cmp     ebp, 1Ch
  39. .text:004A1EBE                 jl      short loc_4A1E6D
  40. ; Все символы соответствуют, серийный номер правильный
  41. .text:004A1EC0                 mov     esi, [esp+18h]
  42. .text:004A1EC4                 push    offset aOk      ; "Ok"
  43. .text:004A1EC9                 mov     ecx, esi
  44. ...
Что получается? Серийный номер условно разделяется на две половины по 4 группы символов. При этом каждый символ из первой половины преобразуется в определенное значение (индекс элемента массива) по описанному выше алгоритму. Затем по этому индексу берется символ (элемент) из проверочного массива "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" и он сравнивается с соответствующим символом из той же позиции второй половины серийника. В нашем примере для латинской буквы "A" из первой половины серийника в проверочном массиве будет соответствовать символ "8", это хорошо видно в отладчике. Контрольное значение "8" сравнивается с введенным символом "E" из второй половины серийника:

Сравнение символа со значением из массива
Сравнение символа со значением из массива

Формула получения индекса в более привычной записи будет выглядеть примерно так:

index = ((serial[i] * 343FDh + 269EC3h) >> 10h) & 7FFFh) mod 24h
Выяснив одно единственное совпадение, можно сразу же узнать один из валидных серийный номеров, в котором будет первая и вторая половина будут состоять из одинаковых символов. Например, правильным серийным номером для регистрации будет "AAAAAA-AAAAAA-AAAAAA-AAAAAA-888888-888888-888888-888888". Попробуем зарегистрировать программу с этим ключом. Никаких сообщений о правильной регистрации не появится, однако надпись "TRIAL" в заголовке программы пропадет. Если теперь попробовать сделать панораму и сохранить результат, то и тут никаких ограничений не будет. Окно регистрации при запуске программы также пропало. То есть регистрационный ключ подобран правильно. Рабочий кейген теперь вы можете написать самостоятельно. Подобным образом обходится защита и других программ от STOIK. Новых побед вам в реверсинге и творческих успехов в фототворчестве!

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

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

Комментарии

Отзывы посетителей сайта о статье
brute (17.03.2016 в 09:55):
я запатчил по другим адресам: 004A271E и 004A9B32. Заменил jnz на jmp. Аналогично ChVL: один байт убирает окно ввода серийника и триал, а второй включает сохранение. (Это на XP, где адреса загрузки постоянны).
ChVL (03.12.2012 в 06:17):
Хороший разбор CrackMe получился. Для начинающих весьма познавательно и полезно.
Защита у сабжа простенькая (вернее, никакой), а потому для себя патчится максимум за 10 мин с учётом выпитого кофе. Всего-то слегка поправить два байта: один по адресу 4A5A03 - убирается триал, другой по адресу 4AA8FE - подключается сохранение проекта. В обоих случаях условный переход заменяется безусловным.
Swo (21.11.2012 в 20:20):
Привет,сегодня только наткнулся на ваш форум, изучаю методы отладкию
Вопрос а чему вы дизесамблируете код?
Dmitry (22.07.2012 в 20:55):
Собственно, программа не очень сильно загружает многоядерные процессоры (12%), а время просчёта довольно велико. Результат не поразил. Более адекватно работает Kolor Autopano Giga 2.5.
За разбор Спасибо!
ManHunter (21.06.2012 в 11:02):
Конечно. И очень много.
Max (20.06.2012 в 18:08):
А существует ли защита, которую вам не удалось сломать?
ManHunter (18.06.2012 в 11:30):
Почему не в курсе? Неоднократно встречал шифрованные или как-то иначе модифицированные строки. Только это их все равно не спасает. Можно ведь ловить не строки, а, например, открытие окна, обращения к файловой системе, реестру, и так далее. Занимает чуть больше времени, но результат все равно одинаковый.
Балбес (18.06.2012 в 11:28):
Читаю тут статьи о взломе, и мне становится дико интересно: неужели никто из девелоперов до сих пор не в курсе, что такие строки можно и зашифровать?
ManHunter (18.06.2012 в 09:03):
Сама программа, кстати, очень понравилась. А защита лажовая, это да.
AyTkACT (18.06.2012 в 01:38):
>>>> Подобным образом обходится защита и других программ от STOIK.
Никак не решу что хуже софт от STOIK или их "защита".
з.ы. Шикарный разбор! =)

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

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

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