Blog. Just Blog

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

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

Программа Smart Photo Import помогает переносить цифровые фотоснимки из камеры или с flash-карточек разного формата. При этом Smart Photo Import автоматически переименовывает файлы на основании EXIF-данных или по установленным пользователем правилам. Также может автоматически раскладывать скопированные файлы по каталогам. Польза от программы сомнительная, тем более от платной версии, но как объект исследования может и пригодится.

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

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

Поищем эту строчку. Файл не упакован, и искомая строка найдется в ресурсах под индексом 64798 в десятичной системе счисления или 0FD1Eh в шестнадцатеричной.

Строка в ресурсах
Строка в ресурсах

Отправляем файл в дизассемблер, ждем окончания его работы и теперь можно спокойно поискать, где в коде используется значение этого индекса. Шестнадцатеричного, естественно. Найдется типичный указатель на указатель.
  1. CODE:007AAE50 off_7AAE50      dd offset hModule
  2. CODE:007AAE54                 dd 0FD1Eh
Если вы ранее сталкивались с реверсом программ на Delphi, то такая конструкция у вас не вызовет никаких недоумений. Достаточно посмотреть на код, который ссылается на первый DWORD конструкции.
  1. ...
  2. CODE:007AAEBE                 call    sub_40C22C
  3. CODE:007AAEC3                 mov     eax, [ebp+var_4]
  4. ; Получить длину регистрационного имени
  5. CODE:007AAEC6                 call    sub_40445C
  6. ; Имя не может быть меньше 8 символов
  7. CODE:007AAECB                 cmp     eax, 8
  8. CODE:007AAECE                 jl      loc_7AAF62
  9. ; Преобразовать имя в регистрационный ключ
  10. CODE:007AAED4                 lea     edx, [ebp+var_14]
  11. CODE:007AAED7                 mov     eax, [ebp+var_4]
  12. CODE:007AAEDA                 call    sub_5DABDC
  13. ; Команда "cmpstr" - сравнение двух строк
  14. CODE:007AAEDF                 mov     edx, [ebp+var_14]
  15. CODE:007AAEE2                 mov     eax, [ebp+var_8]
  16. CODE:007AAEE5                 call    sub_40456C
  17. ; Если строчки не равны, то переход
  18. CODE:007AAEEA                 jnz     short loc_7AAF40
  19. ; Сохранить куда-то регистрационные данные
  20. CODE:007AAEEC                 lea     edx, [ebp+var_18]
  21. CODE:007AAEEF                 mov     eax, [ebx+2E0h]
  22. CODE:007AAEF5                 call    sub_43A4B4
  23. CODE:007AAEFA                 mov     ecx, [ebp+var_18]
  24. CODE:007AAEFD                 mov     edx, offset aUser_1 ; "user"
  25. CODE:007AAF02                 mov     eax, offset aRegistration_1
  26. ; "registration"
  27. CODE:007AAF07                 call    sub_5DBA48
  28. CODE:007AAF0C                 mov     eax, offset aRegistration_1
  29. ; "registration"
  30. CODE:007AAF11                 mov     ecx, [ebp+var_8]
  31. CODE:007AAF14                 mov     edx, offset aRegcode_1 ; "regcode"
  32. CODE:007AAF19                 call    sub_5DBA48
  33. CODE:007AAF1E                 push    0
  34. CODE:007AAF20                 lea     edx, [ebp+var_1C]
  35. CODE:007AAF23                 mov     eax, offset off_7AAE48
  36. CODE:007AAF28                 call    sub_4076B8
  37. CODE:007AAF2D                 mov     eax, [ebp+var_1C]
  38. CODE:007AAF30                 mov     cx, word_7AB024
  39. CODE:007AAF37                 mov     dl, 2
  40. CODE:007AAF39                 call    sub_460448
  41. CODE:007AAF3E                 jmp     short loc_7AAF82
  42. CODE:007AAF40 ; ---------------------------------------------------
  43. ; Вывод сообщения о неправильной регистрации
  44. CODE:007AAF40 loc_7AAF40:
  45. CODE:007AAF40                 push    0
  46. CODE:007AAF42                 lea     edx, [ebp+var_20]
  47. CODE:007AAF45                 mov     eax, offset off_7AAE50
  48. CODE:007AAF4A                 call    sub_4076B8
  49. CODE:007AAF4F                 mov     eax, [ebp+var_20]
  50. CODE:007AAF52                 mov     cx, word_7AB024
  51. CODE:007AAF59                 mov     dl, 2
  52. CODE:007AAF5B                 call    sub_460448
Этот участок кода нагляднее всего пройти под отладчиком. Что мы тут видим? Сперва вызывается функция вычисления длины регистрационного имени. Помните строку сообщения в ресурсах о том, что регистрационное имя не может быть меньше 8 символов? Так вот это оно и есть. Далее вычисляется какая-то строка, очевидно, что на основании регистрационного имени. Ну а потом вызывается функция сравнения двух строчек. Почему я в этом уверен? Обычно, если проверка кустарная и выполняется внутри какой-то функции, то ее результат возвращается в регистре EAX, а затем он сравнивается с нулем или единицей. В нашем случае в функцию передаются указатели на две строки в регистрах EAX и EDX, а условный переход выполняется на основании значения флага нуля ZF. Это типичное поведение функции проверки равенства строк. Перед проверкой регистры указывают на интересные значения:

Ссылки на строчки в регистрах отладчика
Ссылки на строчки в регистрах отладчика

EAX указывает на введенный нами заведомо неправильный серийный номер, EDX указывает на строку, которая очень похожа на серийный номер для имени "ManHunter/ PCL". Сохраним значение строчки из регистра EDX, перезапустим программу и попробуем зарегистрировать ее с найденной парой "имя-серийник".

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

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

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

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

Комментарии

Отзывы посетителей сайта о статье
user (02.08.2013 в 21:32):
Не ленитесь:
HKCU\Software\New_World_Software
brute (02.08.2013 в 07:17):
Число 64798 в иде не искал, hview -не люблю идеологически. В оле не нашёл, особо и не искал. В  IDR нашел процедуру проверки, стал отлаживать.. Увидел в регистрах, дампе и стеке строку рядом с reg_name. Попробовал ввести её в качестве пароля и прога зарегистрировалась - сам не понял и не запомнил как всё быстро получилось. Хотел пропатчить что-нибудь, а прога по Ctrl+F2 в оле уже не останавливается на вводе пароля (даже после переустановки).. Реестр чистить лень..

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

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

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