Print This Post Методика деобфускации PHP-скриптов для чайников. Полезные советы.

Вторник, 24. Январь 2012
Раздел: PHP, Для новичков, автор:

Очень часто непосвященные люди задают вопросы вроде "Как расшифровать обфусцированный PHP-скрипт?", "Хороша ли защита PHP-скрипта обфускатором?" и даже "Помогите деобфусцировать! Вам же не сложно?". Цель этой статьи - показать, что обфускаторы дают в 90% случаев никакущую защиту (которая способна защитить только от людей, увидевших язык программирования первый раз в жизни). Снять ее можно обычно минут за 10-20, получив исходный PHP-скрипт в первозданном виде. Остальные 10% случаев - это немного усложненная защита, которая, впрочем, снимается теми же путями. Если вы желаете самостоятельно научиться снимать обфускацию со скриптов, то эта статья специально для вас!

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

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

Для деобфускации нам потребуются руки, трезвая голова и Notepad++ (можно и другой редактор, желательно умеющий подсвечивать одинаковые подстроки в документе - это ускорит снятие обфускатора).

Для примера берем совершенно абстрактный, накрытый неизвестным мне, но в последнее время чрезвычайно популярным обфускатором, скрипт: original.php.
Сохраняем его в директорию нашего Web-сервера под именем original.php, а затем дублируем его же под другим именем, например, script.php. Позже я поясню, для чего это надо. Открываем скрипт и начинаем его изучение.

Видим, что сам скрипт по размеру небольшой, зато в конце файла, уже после скрипта, находится некий зашифрованный кусок текста. Видим также вызов инструкции PHP eval(), которая исполняет переданный ей PHP-код. Первым делом меняем eval на print, чтобы просмотреть, что же она выполняет. Дабы убедится, что скрипт не натворит на нашем компьютере ничего плохого, просматриваем то, что идет выше - а это безобидный вызов urldecode(), несколько конкатенаций строк и присвоение значений паре переменных. Кроме того, перед вызовом eval() выполняется функция, имя которой хранится в переменной $OOO0000O0. Проверим, что эта функция не делает чего-либо зловредного, для начала просто выведя ее имя и временно закомментировав строку с eval:

Обратите внимание, что редактирую я скрипт script.php, а оригинал original.php оставил без изменений. Обращаемся в браузере к скрипту script.php и видим вывод: base64_decode. Понятно, значит, перед вызовом eval() ничего плохого не происходит, и можно смело менять его на print():

Снова запускаем script.php через браузер и видим следующий вывод:

$O000O0O00=$OOO000O00($OOO0O0O00,'rb');$O0O00OO00($O000O0O00,0x49f);$OO00O00O0=$OOO0000O0($OOO00000O($O0O00OO00($O000O0O00,0x17c),'EnteryouwkhRHYKNWOUTAaBbCcDdFfGgIiJjLlMmPpQqSsVvXxZz0123456789+/=','ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'));eval($OO00O00O0);

Уже по этому неразборчивому коду можно догадаться, что он открывает какой-то файл на выполнение и что-то с ним делает (скорее всего, читает). Кроме того, тут появился очередной вызов eval(). Выведя значение переменной $OOO000O00 видим, что это не что иное, как имя функции fopen(). Какой же файл открывает данный код? Воспользуемся подсветкой Notepad++:

Видим, что это имя текущего файла, то есть script.php. Мы уже серьезно изменили этот скрипт, но можно же заставить код считывать оригинал, который мы заботливо припасли!

Далее, выводя содержимое переменной $O0O00OO00, убеждаемся, что это имя функции fread и файл действительно читается. Сначала считывается 0х49f байтов, которые никуда не сохраняются, а затем еще 0х17c, и вот с ними скрипт уже что-то делает. Чтобы определить, что именно он с ними творит, выводим как обычно содержимое переменных $OOO0000O0 (это base64_decode) и $OOO00000O (это strtr). Таким образом, считанное содержимое сначала прогоняется через strtr(), а затем через base64_decode(). Проще говоря, производится раскодирование. А раскодированное содержимое затем пропихивается в eval(). Теперь мы его снова можем безболезненно заменить на print():

Снова исполняем через браузер script.php и видим очередную порцию кода:

$OO00O00O0=str_replace('__FILE__',"'".$OOO0O0O00."'",$OOO0000O0($OOO00000O($O0O00OO00($O000O0O00,$OO00O0000),'EnteryouwkhRHYKNWOUTAaBbCcDdFfGgIiJjLlMmPpQqSsVvXxZz0123456789+/=','ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')));fclose($O000O0O00);eval($OO00O00O0);

Добавляем этот код в файл script.php и начинаем его разбирать:

С помощью подсветки Notepad++ (выделяя по очереди переменные с исковерканными именами) узнаем уже знакомую конструкцию base64_decode(strtr(fread())), только вот в fread теперь количество байтов для считывания указано неявно, но и это не проблема, ведь чуть выше оно пишется в переменную, которая и передается в fread:

$OO00O0000=0x2f24;

Здесь же явно вызывается str_replace, меняющая в считанной и декодированной строке все вхождения подстроки "__FILE__" на имя нашего файла. Значит, меняем замену на "original.php", как мы делали выше:

После всего этого мы видим вызов fclose - значит, с файлом делаться больше ничего не будет. Остается последний вызов eval(), который мы в очередной раз меняем на print():

И снова запускаем скрипт из браузера... Ура! Наконец-то мы получили исходный код скрипта! В нем немного исковерканы некоторые имена переменных, но это уже не проблема, так как мы видим исходный код!

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

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

Для конкретных обфускаторов можно написать автоматический скрипт-деобфускатор, чтобы свести работу к минимуму.
В свое время я уже писал скрипт, позволяющий снимать конкретно такую обфускацию, и с радостью делюсь им с вами. Этот скрипт также умеет и снимать привязку (так как такой обфускатор, который я рассмотрел в статье, умеет делать привязку скрипта к конкретному домену). Скачать деобфускатор!

Также рекомендую почитать

 Обсудить на форуме


Получать обновления на почту:     

Метки: , , , , , , .

Комментариев: 14 к “Методика деобфускации PHP-скриптов для чайников. Полезные советы.”


  1. flisk :

    Спасибо за полезную и интересную статью.

    [Ответить]


  2. cb^3 :

    Действительно полезно!)

    [Ответить]


  3. 3mph :

    Пускай Каими расскажет, как он дотнет обфусцировал во втором квесте :)

    [Ответить]


  4. true :

    DX, привет.
    Можешь посоветовать наиболее мощный обфускатор кода, на твой взгляд.
    Твой обфускатор снимается так же не сложно, как и описанный в статье.
    Спасибо!

    [Ответить]

    dx:

    Привет, не могу, потому что все обфускаторы примитивны, да и нельзя сделать обфускатор для PHP настолько сложным, чтобы его нельзя было снять в течение пары часов. Можно, конечно, использовать Zend Optimizer или ioncube, но и для их снятия есть готовые пути.

    [Ответить]

    komyak:

    По деобфускации ioncube не подскажешь? Не нашел решений.
    После снятия куба функции остаются зашифрованными.

    [Ответить]

    dx:

    Это другой уровень, на уровне самого интерпретатора PHP и Zend, а не просто скрипт. Не в курсе, как такое снимают.


  5. SHiNiGaMi :

    Извиняюсь, конечно, но статья бесолезная. Смысл показывать и так очевидные действия?

    [Ответить]

    Kaimi:

    Зато есть куда посылать просителей отсюда https://forum.antichat.net/thread144505.html

    [Ответить]

    flisk:

    Кому-то бесполезная, а кому-то и очень полезная. Я, например, не знал всего этого (и в свое время не прошел квест от Kaimi дальше этапа с обфускацией пхп).

    [Ответить]

    zloid:

    А мне было интересно почитать.

  6. [...] предыдущей статье dx рассказывал о ручной методике снятия типовой и [...]


Оставьте ваш комментарий