Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Кодирование и декодирование PHP кода

Anna | 31.05.2014 | нет комментариев

Я занимаюсь поправлением исходников PHP из закодированного вида.
В этой статье я расскажу о том, как обстоят дела с кодированием и декодированием PHP в реальное время.

Дюже короткий ликбез по внутреннему устройству интерпретатора PHP

При выполнении PHP-скрипта, он парсится и компилируется в опкоды внутренней виртуальной машины PHP.
Из всякого файла PHP получаются:
— массив классов: в всяком классе — информация о классе, свойства класса и массив способов класса
— массив функций
— «тело скрипта» — код вне классов и функций

// Классы
class A
{
	public $prop1 = NULL;

	public function method1() { }
}

// Функции
function FFF() { }

// Тело скрипта
echo "Hello, world!";

Для краткости, всю внутреннюю конструкцию скомпилированного файла, готового к выполнению, в этой статье я называю “опкодами“.

Сами опкоды (операции внутренней виртуальной машины PHP) внутри какой-нибудь функции выглядят так:

  
      [0000]ZEND_INIT_FCALL_BY_NAME               - , "defined" -> - 
      [0001]ZEND_SEND_VAL (61)                    "MVMMALL", -  -> - 
      [0002]ZEND_DO_FCALL_BY_NAME (1)             - , -  -> $_z_var_120
      [0003]ZEND_JMPZ                             $_z_var_120, #0008 -> - 
      [0004]ZEND_INIT_FCALL_BY_NAME               - , "defined" -> - 
      [0005]ZEND_SEND_VAL (61)                    "IN_ADMINCP", -  -> - 
      [0006]ZEND_DO_FCALL_BY_NAME (1)             - , -  -> $_z_var_120
      [0007]ZEND_JMPNZ                            $_z_var_120, #0009 -> - 
      [0008]ZEND_EXIT                             "Access Denied", -  -> -

Значимый момент: файлы в скомпилированном виде довольно крепко отличаются даже между подверсиями интерпретатора PHP. Оно и ясно: сам для себя скомпилировал — сам и исполнил.

Как работают энкодеры

Существуют два твердо различных типа энкодеров.

Первые — работают экстраординарно средствами самого языка. Они делают код нечитаемым с поддержкой base64-кодирования, zip-ования, различных манипуляций со строками, и все в конце концов применяют функцию eval(). Все это дюже схоже на обфускаторы в Javascript. Выглядит это как-то так:

eval(base64_decode("DQplcnJvcl9yZXBvcnRpbmcoMCk7DQokcWF6c --- [cut] --- KfQ0KfQ=="));

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

2-й тип энкодеров использует свои подключаемые модули для интерпретатора PHP, которые именуются загрузчиками (loader-ы). В этом случае, как правило, кодируется не сам начальный код, а итоги его компиляции, т.е. внутренние конструкции и опкоды. Это теснее значительно больше серьезная охрана — даже если раскодировать сами опкоды, по ним еще нужно восстановить начальный PHP-код. К тому же, с точки зрения продуктивности, добавочные затраты на раскодирование Зачастую компенсируются экономией на компилировании кода, т.е. скорость выполнения закодированных скриптов нередко даже выше, чем у начального кода.

Во время загрузки интерпретатора PHP, loader-ы энкодеров вешают свои обработчики на функции загрузки PHP-файлов, компиляции и выполнения, для того, Дабы работа с закодированными файлами была бы прозрачной для самого интерпретатора.

Основная трудность для энкодеров — это сделать так, Дабы опкоды, скомпилированные под одной версией PHP во время кодирования, трудились бы под иной версией PHP при декодировании. Фактически все loader-ы у всех энкодеров позже декодирования делают нужные правки, Дабы обеспечить такую совместимость. Основной игрок на этом рынке — IonCube — в свое время приложил громадные усилия для решения этой задачи, и его loader-ы могут на лету правильно исполнить опкоды от PHP 4.x на PHP 5.x, а по вероятности — даже напротив!

Обфускация

Также, для дополнительной охраны, множество энкодеров дает вероятность обфусцировать идентификаторы: имена переменных, наименования функций, классов. Данный процесс, как правило, односторонний — подобно хэширования, и к тому же в итоге Зачастую получаются имена с непечатными символами, которые отменно работают, но которые нельзя применять напрямую в декомпилированных текстах. Скажем, как записать функцию с именем… *диктую по байтам* 0x0D, 0×07, 0×03, 0x0B, 0×02, 0×04, 0×06?

Отдельно внимание уделяется тому, Дабы обфусцированные имена трудились бы правильно. Скажем, в коде вызывается функция checkLicense — loader обфусцирует наименование на лету, получает { 0x0D, 0×07, 0×03, 0x0B, 0×02, 0×04, 0×06 } и ищет теснее данный ключ в хэш-таблице с наименованиями функций.

Zend Guard даже предоставляет run-time функции zend_obfuscate_function_name и zend_obfuscate_class_name, которые разрешают вычислить обфусцированные имена для функций и классов, Дабы облегчить связывание закодированных файлов с незакодированными.

Декодеры наносят ответный удар

Для создания декодера необходимы две вещи: получать расшифрованные опкоды и уметь декомпилировать их в начальный код PHP.

Для приобретения опкодов кому-то пришла в голову ясная идея — сделать свою сборку интерпретатора PHP, которая бы взамен выполнения раскодированного скрипта — отправляла бы его на декомпилирование. Не необходимо возиться с чтением формата энкодера и его охранами — loader энкодера сам делает всю надобную работу!

Какое-то время это работало недурно, потом авторы некоторых энкодеров додумались заменять раскодированные функции заглушками, а настоящий код прятать и доставать всякую вызываемую функцию только в момент ее непосредственного выполнения.
В результат, авторы декодеров стали модифицировать loader-ы от энкодеров, Дабы те не использовали такие заглушки.
Достаточно огромный минус оказался в том, что для всякой версии PHP у всякого энкодера были свои loader-ы, которые к тому же частенько обновлялись. Доводилось много и Зачастую патчить, правда и нетрудно — легко отключить вызов функции-иной.

И вот наконец авторы одного знаменитого энкодера сделали дальнейший шаг: они стали добавочно кодировать отдельные операнды в некоторых инструкциях и вешать свои обработчики для соответствующих команд виртуальной машины PHP. Скажем, код $a = 0; превращался в $a = 5;, а в момент исполнения кастомный обработчик правил 5 обратно в 0.

Это надолго затормозило тех, кто «патчил loader-ы». Во-первых, пришлось длинно разбираться, отчего как бы бы верно вытянутые опкоды декомпилируются с ошибками. Во-вторых, здесь теснее не получалось легко поменять пару байт в loader-е.

На сцену вышли те немногие, кто прикладывал огромнее усилий — реверсил и разбирался в формате закодированных файлов.

Вторая часть в работе декодера — декомпилирование. Это — трудная, но увлекательная, чисто алгоритмическая задача.

Когда-то ясные головы написали пару недурных алгорифмов декомпилирования для PHP. Множество тех, кто занимается декодированием PHP теперь, написать свой декомпилятор не могут, следственно применяют те, что есть, с минимальными правками.

Все декомпиляторы в открытом доступе верно восстанавливают только 90-95%% кода. Остальное доводится исправлять вручную, и здесь дюже огромную роль играют навык программирования на PHP и навык декомпилирования, т.к. ошибки появляются обыкновенно типовые.

Подводя вывод: никакого всецело механического декодирования для основных торговых энкодеров пока нет.

Как защититься от декодирования

Ясно, что рано либо поздно всякий закодированный код будет вскрыт, если это будет необходимо. Но зная, как устроена работа декодеров, дозволено серьезно осложнить данный процесс:

  • по вероятности, используйте новые версии PHP и сам язык по-полной: namespaces, traits, lambdas
  • непременно используйте обфускацию имен, причем усердствуйте не применять короткие и типовые имена: $ch, $ci, $arr, ‘license’, ‘valid’ …
  • декодеры «обожают» конструкции вида
    connect(...) or die(...);
    и их вариации вида:
    defined('MYCONST') or define('MYCONST', true);
    либо
    ($_alias = $object_name) OR $_alias = $class;
  • исключительно «отлично» декодеры понимают редчайшие конструкции вида:$valid ? $a : exit('Error!');

    $valid ? $valid : print('Error!'); // вопрос знатокам PHP: знаете ли вы, отчего здесь именно print ? ;)

  • используйте «любимый» элемент языка: list( , , $c, $d) и конструкции вида while(list($k, $v) = each($arr))
  • испробуйте «десерт для декомпилятора»:
    switch($eatThis)
    	{
    	   default:
    	      $doNothing = 0;
        }
    

    (юмор в том, что декомпиляторы обыкновенно ждут увидеть хоть один CASE, без этого они и не понимают, что тут была конструкция switch)

  • часть публично доступных декодеров сбоит на трудных именах способов либо свойств: $obj->{'alpha' . $beta}
  • иная часть сбоит с magic-способами, включая даже __construct

Юридические аспекты

Вообще говоря, декодирование PHP-файлов позже торговых энкодеров — незаконно. Технически это связано с тем, что для полновесного декодирования необходимо декомпилировать и исследовать сами энкодеры, а закон и пользовательские соглашения это прямо воспрещают.

На территории Евросоюза есть такая уловка: разрешается «обеспечивать совместимость экземпляров ПО, которыми вы обладаете, и для этого, при необходимости, обходить встроенные системы охраны». При этом прямой закроет на reverse engineering у всякого энкодера все-таки имеет приоритет.

Получается, что «я скачал программу из Интернета, которая достала мне незашифрованные опкоды» либо «я применял особую сборку интерпретатора PHP, которая сберегает расшифрованные опкоды» — это условно-легальные методы декодирования. «Условно» — потому что если дело все-таки дойдет до суда, еще непостижимо, кто окажется прав.

Внятное дело, что создатели энкодеров выбрали бы, Дабы закодированные файлы никто и никогда не мог бы раскодировать. Но у тех, кто остался с закодированные кодом позже наплевательских фрилансеров, либо позже исчезновения компании-разработчика (что бывает дюже Зачастую), суждение про декодирование — диаметрально противоположное.

Увлекательные факты и байки

Огромная часть энкодеров последние пару лет каждого лишь чуть-чуть меняет формат файлов «под капотом», и выпускается под видом новой версии.

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

Фрилансеры настоль Зачастую применяют куски кода из документации PHP и со StackOverflow, что словарь, составленный из идентификаторов, взятых оттуда из примеров, разрешает обыкновенно деобфусцировать под 90% всех имен в среднем плане.

За все время работы я встретил каждого лишь пять разных декомпиляторов PHP. Три из них были написаны русскоязычными программистами, еще один — китайцем и еще один — божились, что французом. Мелочь, а отрадно — горд за «наших» :)

При этом множество русскоязычных заказчиков умоляет по-свойски сделать работу даром :)

И напоследок – пара историй

Один араб позже долгого обсуждения его плана, известил, что «мой бюджет — $15, но мы все понимаем… работы здесь много, так что ты легко вышли все свои программы, а мы здесь сами как-то все раскодируем».

Несколько раз получалось так, что декодировать определенный формат файлов мог только я. И одни и те же файлы приходили на декодирование через нескольких различных посредников единовременно.
Исключительно меня повеселила такая история: негр с африканским именем и со швейцарским гражданством, разругался с фрилансером-программистом из Австралии, не уплатил ему за работу и остался с парочкой закодированных недоделанных файлов на своем сайте. Длинно искал на фрилансерских биржах того, кто их раскодирует, пока наконец один индус не впарил ему свои службы.
Три недели данный индус кормил клиента завтраками, а сам усиленно искал реального исполнителя. Параллельно клиент (жук еще тот) под иным именем и сам продолжал искать других декодировщиков на все тех же фрилансерских биржах. Обнаружил меня, отдал мне проект… и здесь же, дословно через 30 мин, ко мне постучался индус и с чувством очевидного упрощения стал уговоривать сделать и его план тоже. Я сравнил файлы, и…
Безусловно, стоило бы в воспитательных целях взять у обоих 100% предоплаты… но я легко принудил их пообщаться и разобраться между собой.
По выводам, индус до сих пор не забывает поздравить меня с днем рождения.
Клиент даже дал мне бонус, а теперь переехал в Эстонию (!) потому что там дешевле жить, и периодически уговаривает меня поучаствовать в каких-то его подозрительных прожектах.

UPD. Пришлось вырезать часть примера с eval-закодированым кодом, потому что Kaspersky выдавал на него предупреждение. Спасибо nokimaro!

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB