Исследование защиты программы PHP Locker
Скриншот программы PHP Locker
В поисках очередных пациентов для PHPiD наткнулся на софтину под названием PHP Locker. "Мощная программа для шифрования ваших PHP-скриптов. Она превращает исходный код в нечто трудное для понимания и реверсивного исследования. В отличие от других систем шифрования, не требует установки дополнительных модулей на серверную часть". Это мнение о программе самих разработчиков, так что "мопед не мой, я просто разместил объяву" :) Там же на офсайте вывешен целый иконостас орденов и медалей, коими наградили этот продукт различные популярные софтообозревательные сайты. И да, к слову, цена за персональную лицензию 180$, а за корпоративную аж все 2800$.
Посмотрим на это чудо повнимательнее. Скачиваем дистрибутив, устанавливаем. Предварительным анализом файла определяем, что исполняемый файл ничем не упакован и написан на Delphi. На попытку ввода неправильных регистрационных данных программа реагирует сообщением "The wrong username or registration code!" Поиск строки в файле показывает, что она находится в секции ресурсов. Но и просмотр этой секции особо не поможет, потому что файл написан на Delphi, зато мы можем узнать название формы, в которой открывается сообщение об ошибке - TfrmError.
Форма в ресурсах
Для борьбы с Delphi на помощь приходит другой инструмент - декомпилятор для Delphi под названием DeDe. Эта программа написана уже давно, но она до сих пор помогает в исследованиях. Загоняем в нее исполняемый файл, ждем когда закончится декомпиляция, сохраняем проект. В папке с проектом поиском по файлам по строке "TfrmError" находится вот такой кусок кода:
Code (Assembler) : Убрать нумерацию
- * 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
Code (Assembler) : Убрать нумерацию
- ...
- ; Вызвать процедуру проверки регистрации
- 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:
- ...
Программа успешно "зарегистрирована"
Последний штрих: открываем в Блокноте файл 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, сохраняем и снова запускаем. На этот раз у нас получается полностью открытый исходный код скрипта. В моем случае это был вот такой коротенький пример:
Code (PHP) : Убрать нумерацию
- for ($i=0; $i<10; $i++) {
- echo "Hello! ";
- }
Просмотров: 5633 | Комментариев: 15
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Андрей
(04.10.2010 в 19:25):
У меня к сожалению не получается снять защиту с программы. (((
bodrox
(29.06.2010 в 22:01):
каков уровень обозревателей из софтверных сайтов, которые высоко оценили эту галиматью?
64-ядерный процессор
(24.05.2010 в 23:41):
ManHunter, я вот всегда тестирую "многообещающий" софт на виртуальной машине - во многих случаях все изъяны выявляются. Да и в некоторых случаях потом приходиться ОС на виртуальной машине переустанавливать.
ManHunter
(24.05.2010 в 20:12):
Цель та же самая, что и у PE-пакеров и протов. Некоторые [ч|м]удаки пытаются заработать, продавая свои скрипты. Еще некоторые [м|ч]удаки шифруют всякие шеллы и трояны, но это малая часть. Основная целевая аудитория подобных поделок - шароварщики.
Isaev
(24.05.2010 в 19:56):
ManHunter ещё вопросик: Для чего шифровать php скрипт вообще если можно просто ограничить доступ к нему и его и так никто не увидит?
Или иногда это необходимо?
Или иногда это необходимо?
64-ядерный процессор
(22.05.2010 в 22:13):
Вот поэтому я никогда таким софтом не пользуюсь. Зачем? Ведь то что можно зашифровать через общедоступный алгоритм, то можно легко и расшифровать.
ManHunter
(22.05.2010 в 21:39):
Isaev, про _некоторые_ возможные грабли ниже в камментах написал MaxIkar, я тоже добавил. После обработки триальной версией скрипты получаются НЕ работоспособны, из-за принудительного добавления в код ихней дебильной ссылки. Плюс еще грабля: теоретически не везде на хостингах есть поддержка gzip, а тут эта функция дефолтная и не отключается. Ну а о "стойкости" защиты я все написал в статье.
Isaev
(22.05.2010 в 17:28):
Хостинг крутой для столь дорогой утильки :)))) 4.4 кб/с отдача!
На счёт патча я промолчу :) Хотя снова слабенькое RSA вроде и можно было бы сделать прикольный пример с криптокейгеном, хотя внимательно не смотрел... Где ты находишь такие идеальные поделки для новичков?
А может она этого и не заслуживает... Столько понавешать всего и сделать слабое место с патчем в 1 байт! Хмм... Стоит ли пользоваться такой поделкой?
А как защита с точки зрения программиста php?
И какие последствия для исполняемого скрипта? (в смысле скорости исполнения или может дополнительные ограничения для используемого хостинга)
А дочитал на счёт защиты, класс :))))))))))
На счёт патча я промолчу :) Хотя снова слабенькое RSA вроде и можно было бы сделать прикольный пример с криптокейгеном, хотя внимательно не смотрел... Где ты находишь такие идеальные поделки для новичков?
А может она этого и не заслуживает... Столько понавешать всего и сделать слабое место с патчем в 1 байт! Хмм... Стоит ли пользоваться такой поделкой?
А как защита с точки зрения программиста php?
И какие последствия для исполняемого скрипта? (в смысле скорости исполнения или может дополнительные ограничения для используемого хостинга)
А дочитал на счёт защиты, класс :))))))))))
MaxIkar
(21.05.2010 в 12:57):
ManHunter, ага, я так и понял по нотису на их сайте.
Мол, это не баг, это фича)
А что еще могут сделать такие мега-кодеры? Защита под стать информации о продукте в шароварной версии.
Мол, это не баг, это фича)
А что еще могут сделать такие мега-кодеры? Защита под стать информации о продукте в шароварной версии.
ManHunter
(21.05.2010 в 12:39):
Это еще фигня :) В триальной версии в каждый скрипт записывается html-ссылка на их сайт. И эта фича "документирована" в программе, типа "если у вас вывалится ошибка что заголовки уже отосланы и все такое, то это типа так у нас работает триалка". На скриншоте как раз виден этот нотис. И если бы вдруг у меня даже возникло желание и возможность купить эту поделку, то после таких закидонов это желание точно бы пропало.
У нормальных шароварщиков в подобном софте ограничение по количеству скриптов, по времени работы, по доступным функциям, а тут решили выебнуться.
У нормальных шароварщиков в подобном софте ограничение по количеству скриптов, по времени работы, по доступным функциям, а тут решили выебнуться.
MaxIkar
(21.05.2010 в 12:34):
Эх... Как же хорошо это решение подходит для высоконагруженных сайтов!
А кешировщики опкодов вообще тащатся от eval'a.
Молчу про base64_decode, gzip и str_replace по всему исходнику...
аффтары забыли это все обернуть в
ob_start();
echo gzuncompress(base64_decode($z));
$code = ob_get_clean();
eval($code);
А еще можно на каждую страничку вызывать SOAP-сервис с сайта производителя софтины, дабы проверить, что ее точно не сперли.
А кешировщики опкодов вообще тащатся от eval'a.
Молчу про base64_decode, gzip и str_replace по всему исходнику...
аффтары забыли это все обернуть в
ob_start();
echo gzuncompress(base64_decode($z));
$code = ob_get_clean();
eval($code);
А еще можно на каждую страничку вызывать SOAP-сервис с сайта производителя софтины, дабы проверить, что ее точно не сперли.
diwriter
(21.05.2010 в 06:58):
Спасибо, очень наглядно, но и, правда, грустно.
user
(20.05.2010 в 14:28):
Программинг профанируется(((
ManHunter
(20.05.2010 в 13:14):
Увы, ни к одному из трех определений эта поделка не относится.
user
(20.05.2010 в 13:12):
Цена внушает... кому- то, возможно, даже веру в то, что перед ним качественный продукт. Качественный, надёжный, неприступный.
Добавить комментарий
Заполните форму для добавления комментария