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


Скриншот программы PHP Locker

В поисках очередных пациентов для PHPiD наткнулся на софтину под названием PHP Locker. "Мощная программа для шифрования ваших PHP-скриптов. Она превращает исходный код в нечто трудное для понимания и реверсивного исследования. В отличие от других систем шифрования, не требует установки дополнительных модулей на серверную часть". Это мнение о программе самих разработчиков, так что "мопед не мой, я просто разместил объяву" :) Там же на офсайте вывешен целый иконостас орденов и медалей, коими наградили этот продукт различные популярные софтообозревательные сайты. И да, к слову, цена за персональную лицензию 180$, а за корпоративную аж все 2800$.

Посмотрим на это чудо повнимательнее. Скачиваем дистрибутив, устанавливаем. Предварительным анализом файла определяем, что исполняемый файл ничем не упакован и написан на Delphi. На попытку ввода неправильных регистрационных данных программа реагирует сообщением "The wrong username or registration code!" Поиск строки в файле показывает, что она находится в секции ресурсов. Но и просмотр этой секции особо не поможет, потому что файл написан на Delphi, зато мы можем узнать название формы, в которой открывается сообщение об ошибке - TfrmError.


Форма в ресурсах

Для борьбы с Delphi на помощь приходит другой инструмент - декомпилятор для Delphi под названием DeDe. Эта программа написана уже давно, но она до сих пор помогает в исследованиях. Загоняем в нее исполняемый файл, ждем когда закончится декомпиляция, сохраняем проект. В папке с проектом поиском по файлам по строке "TfrmError" находится вот такой кусок кода:
* Reference to TfrmError instance
|
004F6C4D   A150F65100             mov     eax, dword ptr [51F650]
004F6C52   8B00                   mov     eax, [eax]
 
* Reference to: Forms.TCustomForm.Show(TCustomForm);
|
004F6C54   E8E7A7F9FF             call    00491440
004F6C59   33C0                   xor     eax, eax
004F6C5B   5A                     pop     edx
004F6C5C   59                     pop     ecx
004F6C5D   59                     pop     ecx
004F6C5E   648910                 mov     fs:[eax], edx

Конструкция Forms.TCustomForm.Show как раз и отвечает за открытие окна с сообщением о неправильной регистрации. Отлично, теперь мы знаем, в каком месте файла по какому адресу происходит интересующее нас действие. От декомпилятора переходим к дизассемблеру, смотрим в нем условия срабатывания этой ветки алгоритма. Можно, конечно, это сделать и в листинге декомпилятора, но в дизассемблере как-то привычнее.
...
; Вызвать процедуру проверки регистрации
CODE:004F6BD3                 call    sub_510B10
; Если она вернула AL=0, то программа незарегистрирована
CODE:004F6BD8                 test    al, al
CODE:004F6BDA                 jz      short loc_4F6C4D
; Сохранить регистрационные данные
CODE:004F6BDC                 mov     eax, ds:off_51F6A0
CODE:004F6BE1                 mov     eax, [eax]
CODE:004F6BE3                 mov     ecx, [eax+314h]
CODE:004F6BE9                 mov     dl, 1
CODE:004F6BEB                 mov     eax, off_43E728
CODE:004F6BF0                 call    sub_43E7D8
CODE:004F6BF5                 mov     ebx, eax
CODE:004F6BF7                 mov     eax, [ebp+var_8]
CODE:004F6BFA                 push    eax
CODE:004F6BFB                 mov     ecx, offset aUsername_0 ; "username"
CODE:004F6C00                 mov     edx, offset aUser_info ; "user_info"
CODE:004F6C05                 mov     eax, ebx
CODE:004F6C07                 mov     edi, [eax]
CODE:004F6C09                 call    dword ptr [edi+4]
CODE:004F6C0C                 mov     eax, [ebp+var_C]
CODE:004F6C0F                 push    eax
CODE:004F6C10                 mov     ecx, offset aRegcode ; "regcode"
CODE:004F6C15                 mov     edx, offset aUser_info ; "user_info"
CODE:004F6C1A                 mov     eax, ebx
CODE:004F6C1C                 mov     edi, [eax]
CODE:004F6C1E                 call    dword ptr [edi+4]
CODE:004F6C21                 mov     eax, ebx
CODE:004F6C23                 call    sub_403DD4
CODE:004F6C28                 mov     eax, ds:off_51F6A0
CODE:004F6C2D                 mov     eax, [eax]
CODE:004F6C2F                 mov     ecx, [ebp+var_C]
CODE:004F6C32                 mov     edx, [ebp+var_8]
CODE:004F6C35                 call    sub_511AC0
; Вывести сообщение об удачной регистрации
CODE:004F6C3A                 mov     eax, offset aThankYouForReg
; "Thank you for registering PHP Locker,pl"...
CODE:004F6C3F                 call    sub_43871C
CODE:004F6C44                 mov     eax, esi
CODE:004F6C46                 call    sub_491438
CODE:004F6C4B                 jmp     short loc_4F6C59
CODE:004F6C4D ; -------------------------------------------
; Триальная ветка алгоритма, сообщение о неуспешной регистрации
CODE:004F6C4D loc_4F6C4D:
...

По адресу 004F6BD3 происходит вызов процедуры проверки введенного ключа. Криптоанализаторы показывают наличие в ней Blowfish, бороться с этим криптоалгоритмом у меня нет никакого желания. Поэтому просто пропатчим процедуру по адресу 00510B10, записав в ее начало команды MOV AL,1; RET. После этого программа из триального режима переходит в зарегистрированный, снимаются все ограничения, в окне регистрации кнопка Register становится неактивной.


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

Последний штрих: открываем в Блокноте файл registration.ini, который находится в папке с программой, и вписываем в него нужное регистрационное имя и какой-нибудь серийный номер. Теперь это имя будет отображаться в заголовке окна.
[user_info]
username="Manunter / PCL"
regcode="Have a Nice Day!"
serial=

C программой закончили, теперь посмотрим на результаты ее творчества, заодно проверим, не осталось ли в ней каких-нибудь еще скрытых триальных ограничений. Закодируем какой-нибудь простейший скрипт в несколько строчек, получим примерно такой текст:
<? $d='t';$h='hudgu';$b = str_replace($h,$d,'eJw1jb0KgzAYAF/FIRBDXSy1COK
ggkPhudguUGhudgu/bBeJ8VOoP4lGrfr0FaHbHRwcqm2cYgvlNgY68++Ki2Irsu+SDkRFGag
o11ChudguYTghudgun0jK8d674by1oS79958n17/QveCBvvnEvKIV87UxvJJDeyuN3YsHUU/
N+Pw0Y8cZHs4QYmLBSCu1WIaG8Vp0IKWaUgnHQ5IB49l6Xwgh1g+UGTlD');eval(gzuncom
press(base64_decode($b))); ?>

Для распаковки этого чуда нам понадобится обычный Блокнот и настроенный web-сервер, или какая-нибудь IDE для разработки на PHP со своим встроенным сервером. Подразумевается, что с самим языком PHP вы уже знакомы. Запускаем секундомер. Первый шаг: в Блокноте заменяем слово eval на echo и запускаем скрипт на выполнение. Получаем на экране что-то типа:
$m='b';$f='eayow';$z = str_replace($f,$m,'eJzjSssvUtBQyeayowQ1sFZQyeayow
QxBFPa2poK1eayowxcCgqpyRn5CkoeqTk5+YoKSta8XLW8XAAuVAuQ');eval(gzuncompre
ss(base64_decode($z)));

Копируем полученный текст обратно в Блокнотик, дополняем открывающими и закрывающими PHP-тегами, заменяем eval на echo, сохраняем и снова запускаем. На этот раз у нас получается полностью открытый исходный код скрипта. В моем случае это был вот такой коротенький пример:
for ($i=0; $i<10; $i++) {
  echo "Hello! ";
}

Как видите, за два несложных шага скрипт расшифровался в точности до исходного кода, со всеми переносами строк и отступами, имена переменных тоже не тронуты. Останавливаем секундомер. Затраченное время на расшифровку - меньше минуты. Вот мне и непонятно, как можно требовать за подобную "защиту" такие деньги? И как могут доверять аффтары свои ненаглядные скрипты этой поделке почти за три килобакса, если защита снимается в обычном Блокноте? Грустно :)
Теги:
защита, взлом
Добавлено: 21 Сентября 2013 12:26:28 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...