Blog. Just Blog

Исследование защиты программы DzSoft PHP Editor

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

DzSoft PHP Editor - редактор PHP-скриптов и HTML страничек. В наличии имеется практически весь нужный инструментарий для разработки: подсветка синтаксиса, шаблоны, встроенный FTP-клиент, поддержка юникода, просмотр результатов в браузере и всякое такое. У каждого программиста для работы наверняка есть свой привычный, отобранный годами инструментарий, но может быть и этот редактор кому-нибудь пригодится. Лично мне в DzSoft PHP Editor не нравится то, что за программу требуется выкладывать деньги.

Забираем дистрибутив с офсайта или с альтернативной ссылки, устанавливаем, запускаем. Первым делом нас встречает триальное окно:

Триальноное окно
Триальноное окно

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

Окно "О программе"
Окно "О программе"

Третьим признаком будет ссылка на покупку в меню "Help". С исходными данными разобрались, переходим к анализу исполняемого файла. На нем навешан протектор ASProtect. Снять его можно в отладчике при помощи скрипта от VolX или автоматическим распаковщиком DecomAS. Особенность обоих способов в том, что корректно сделать это получается только на Windows XP, для этого у меня есть отдельный нетбук. На других более новых операционных системах распакованный файл получается нерабочим. На счет виртуальных машин ничего сказать не могу, при наличии физического железа с Windows XP я предпочитаю использовать его.

Распаковка ASProtect
Распаковка ASProtect

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

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

Ее индекс 65195 в десятичной системе счисления или 0FEABh в шестнадцатеричной. Ищем это значение в листинге:
  1. .text:004ED21C off_4ED21C      dd offset dword_6E07FC
  2. .text:004ED220                 dd 0FEABh
Дельфовая конструкция, которая уже неоднократно нам встречалась - указатель на указатель на индекс строки. Пошагово раскручиваем ее по перекрестным ссылкам.
  1. .data:006DD008 off_6DD008      dd offset off_4ED21C
И в конечном итоге выходим на код, где этот указатель используется:
  1. .text:006B0ECC                 lea     eax, [ebp+var_90]
  2. .text:006B0ED2                 push    eax
  3. .text:006B0ED3                 lea     edx, [ebp+var_98]
  4. ; Указатель на указатель на индекс строки сообщения
  5. .text:006B0ED9                 mov     eax, off_6DD008
  6. .text:006B0EDE                 call    sub_408258
  7. .text:006B0EE3                 mov     edx, [ebp+var_98]
  8. .text:006B0EE9                 lea     ecx, [ebp+var_94]
  9. .text:006B0EEF                 mov     eax, offset aConst_trialmsg
  10. ; "const_TrialMsg"
  11. .text:006B0EF4                 call    sub_4ED374
  12. .text:006B0EF9                 mov     eax, [ebp+var_94]
  13. .text:006B0EFF                 push    eax
Нам надо найти участок кода, который отвечает за переход в обход этого сообщения. Прокручиваем листинг вверх и попадаем на следующий участок:
  1. .text:006B0D9C                 mov     edx, off_6DD814
  2. .text:006B0DA2                 mov     edx, [edx]
  3. .text:006B0DA4                 call    sub_406384
  4. .text:006B0DA9                 mov     eax, [ebp+var_6C]
  5. .text:006B0DAC                 lea     edx, [ebp+var_68]
  6. .text:006B0DAF                 call    sub_40B418
  7. .text:006B0DB4                 mov     eax, [ebp+var_68]
  8. .text:006B0DB7                 xor     edx, edx
  9. .text:006B0DB9                 call    sub_40655C
  10. ; Перепрыгнуть все триальные сообщения
  11. .text:006B0DBE                 jnz     loc_6B0F87
  12. .text:006B0DC4                 mov     eax, off_6DD670
  13. .text:006B0DC9                 cmp     dword ptr [eax], 1
  14. .text:006B0DCC                 jge     loc_6B0E54
  15. .text:006B0DD2                 lea     eax, [ebp+var_70]
  16. .text:006B0DD5                 push    eax
  17. .text:006B0DD6                 lea     edx, [ebp+var_78]
  18. .text:006B0DD9                 mov     eax, off_6DD860
  19. .text:006B0DDE                 call    sub_408258
  20. .text:006B0DE3                 mov     edx, [ebp+var_78]
  21. .text:006B0DE6                 lea     ecx, [ebp+var_74]
  22. .text:006B0DE9                 mov     eax, offset aConst_trialexp
  23. ; "const_TrialExpiries"
  24. .text:006B0DEE                 call    sub_4ED374
  25. .text:006B0DF3                 mov     eax, [ebp+var_74]
  26. .text:006B0DF6                 mov     edx, off_6DCE90
  27. .text:006B0DFC                 mov     edx, [edx]
Тут у нас условный переход, при срабатывании которого обходится сообщение об истечении пробного периода и триальное сообщение, которое мы уже видели. Заменяем условный переход на безусловный. Сохраняем изменения, запускаем. Программа сразу запускается без каких-либо лишних сообщений. В принципе, этого вполне достаточно для того, чтобы работать с программой без ограничений. Триал был реализован средствами навесного протектора, так что после его снятия лимита по времени больше нет. Триальное окно нейтрализовано. Но для полноценного взлома надо обойти еще два момента. Первый - надпись в окне "О программе". Если поискать в файле по набору стандартных строчек "registered", "licensed" и т.п., то найдется вот такая строка:

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

Наверняка именно она отображается, когда программа зарегистрирована. Поищем место в коде, где она используется.
  1. .text:0069E4A5                 mov     eax, [ebp-28h]
  2. .text:0069E4A8                 test    eax, eax
  3. .text:0069E4AA                 jz      short loc_69E4B1
  4. .text:0069E4AC                 sub     eax, 4
  5. .text:0069E4AF                 mov     eax, [eax]
  6. .text:0069E4B1 loc_69E4B1:
  7. .text:0069E4B1                 dec     eax
  8. ; Перепрыгнуть строчки "Licensed to"
  9. .text:0069E4B2                 jle     loc_69E5F8
  10. .text:0069E4B8                 mov     dl, 1
  11. .text:0069E4BA                 mov     eax, [ebx+384h]
  12. .text:0069E4C0                 call    sub_4C6A88
  13. .text:0069E4C5                 xor     edx, edx
  14. .text:0069E4C7                 mov     eax, [ebx+384h]
  15. .text:0069E4CD                 call    sub_4A1774
  16. .text:0069E4D2                 mov     eax, [ebx+384h]
  17. .text:0069E4D8                 mov     edx, [eax+44h]
  18. .text:0069E4DB                 sub     edx, 8
  19. .text:0069E4DE                 call    sub_4C6018
  20. .text:0069E4E3                 mov     eax, [ebx+384h]
  21. .text:0069E4E9                 mov     edx, [eax+4Ch]
  22. .text:0069E4EC                 add     edx, 10h
  23. .text:0069E4EF                 call    sub_4C6080
  24. .text:0069E4F4                 lea     edx, [ebp-4]
  25. .text:0069E4F7                 mov     eax, 2
  26. .text:0069E4FC                 call    sub_6CB168
  27. .text:0069E501                 cmp     dword ptr [ebp-4], 0
  28. .text:0069E505                 jz      short loc_69E517
  29. .text:0069E507                 lea     eax, [ebp-4]
  30. .text:0069E50A                 mov     ecx, [ebp-4]
  31. .text:0069E50D                 mov     edx, offset dword_69E69C
  32. .text:0069E512                 call    sub_405D58
  33. .text:0069E517 loc_69E517:
  34. .text:0069E517                 lea     eax, [ebp-2Ch]
  35. .text:0069E51A                 mov     edx, off_6DD814
  36. .text:0069E520                 mov     edx, [edx]
  37. .text:0069E522                 call    sub_405C1C
  38. .text:0069E527                 mov     eax, [ebp-2Ch]
  39. .text:0069E52A                 mov     edx, offset aUkrainianUserU
  40. ; "Ukrainian User\r\n\r\nUKRAYINA\r\nUkrainian L"...
  41. .text:0069E52F                 call    sub_405E68
  42. ; Используется локальная лицензия
  43. .text:0069E534                 jnz     short loc_69E54B
  44. .text:0069E536                 mov     edx, offset loc_69E6EC
  45. .text:0069E53B                 mov     eax, [ebx+384h]
  46. .text:0069E541                 call    sub_4C698C
  47. .text:0069E546                 jmp     loc_69E5DE
  48. .text:0069E54B ; ---------------------------------------
  49. .text:0069E54B loc_69E54B:
  50. .text:0069E54B                 call    sub_6CB254
  51. .text:0069E550                 fstp    qword ptr [ebp-10h]
  52. .text:0069E553                 wait
  53. .text:0069E554                 push    dword ptr [ebp-0Ch]
  54. .text:0069E557                 push    dword ptr [ebp-10h]
  55. ; Вывести сообщение о зарегистрированности
  56. .text:0069E55A                 mov     edx, off_6DD14C
  57. .text:0069E560                 mov     edx, [edx]
  58. .text:0069E562                 lea     eax, [ebp-8]
  59. .text:0069E565                 call    sub_40F6D4
  60. .text:0069E56A                 push    offset aLicensedTo ; "Licensed to "
  61. .text:0069E56F                 lea     edx, [ebp-34h]
  62. .text:0069E572                 mov     eax, 1
  63. .text:0069E577                 call    sub_6CB168
Вот тут становится очень интересно. Кроме условного перехода, который отвечает за вывод в окно "О программе" надписи о зарегистрированности, выполняется дополнительная проверка. Автор программы из Украины, и в программе, похоже, проверяется специальный серийник для жителей Незалежной. Это обычная практика, когда для своих соотечественников разработчики предоставляют особые условия покупки по сниженным ценам или вообще делают программу бесплатной при запуске ее на определенной локали. К этому мы еще вернемся, а пока заNOPим условный переход по адресу 0069E4B2. Сохраняем изменения, запускаем.

Окно "О программе"
Окно "О программе"

Вот, уже гораздо приятнее. Не совсем то, что надо, но зато надпись "UNREGISTERED" больше не появляется. Вернемся к украинской лицензии. Если после сравнения не выполнится условный переход по адресу 0069E534, то в окне "О программе" должны появиться данные локальной лицензии. NOPим условный переход, сохраняем изменения, запускаем.

Окно "О программе"
Окно "О программе"

Теперь программа считает, что она зарегистрирована на локального пользователя. Если релиз ориентирован на украинских пользователей, то тут можно больше ничего не делать. А для интернационального релиза можно заменить эту строку на что-нибудь другое, например, прописав вместо нее ваш ник и команду.

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

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

Можно остановиться и на этом шаге, основные косметические недостатки программы устранены. Но если вы хотите пойти до конца, то надо избавиться от надписи "BUY NOW" в меню "Help". Строка находится в ресурсах файла, в дельфовой форме:

Пункты меню в ресурсах
Пункты меню в ресурсах

Мы видим два пункта меню - "Check for Updates" с атрибутом Visible = False и интересующий нас пункт "BUY NOW". Если еще раз посмотреть меню, то пункта с проверкой обновления в нем нет. Значит оно появляется только в зарегистрированной версии и подменяет собой пункт о покупке. Можно конкретно заморочиться, найти в коде место, отвечающее за эти пункты, и исправить его нужным образом. А можно сделать проще. Там же в редакторе ресурсов переносим атрибут Visible = False с пункта обновления на пункт покупки:

Пункты меню в ресурсах
Пункты меню в ресурсах

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

Исправленное меню
Исправленное меню

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

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

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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (03.02.2019 в 21:26):
Так для личного использования же, в этом случае не стыдно :)
TEKTON (04.10.2018 в 19:13):
Молодцы авторы, которые не дерут "со своих" "в три шкуры".
Таких даже ломать как то совестно :)
Спасибо за статью.
ManHunter (22.09.2018 в 00:04):
Отслеживание GetSystemDefaultUILanguage, например. Если бесплатный вариант программы заточен на конкретное значение языка, то ищешь вызов, потом подменяешь возвращаемое значение или патчишь какой-нибудь условный переход.
Noobie (21.09.2018 в 12:47):
Статья, как обычно, нужная и подлежит изучению.
DimitarSerg,
Цитатапатчил проверку локали

А можно подробнее? Не про конкретную программу, а, так сказать, в общих чертах, как найти подобную проверку?
ManHunter (20.09.2018 в 08:39):
А я раньше ее релизил немного иначе. Подменял адрес серийника и впечатывал фейковый серийник в данные. Но это не так наглядно :)
DimitarSerg (19.09.2018 в 00:19):
ЦитатаНасколько я помню, эта программа бесплатна для жителей СНГ. Где то даже ключик от нее лежит. За статью спасибо!

Ага... Я ее когда-то так и ломал, патчил проверку локали )
3ton (18.09.2018 в 03:49):
Насколько я помню, эта программа бесплатна для жителей СНГ. Где то даже ключик от нее лежит. За статью спасибо!

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

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

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