Декодиране на PHP код обфускиран с NET-TEC PHP-ENCODER V1.0

Темата на тази статия е декодиране на PHP код обфускиран, с NET-TEC PHP-ENCODER V1.0. Причината да се занимавам с това е тема за WordPress на блога ми за фентъзи. Исках да добавя нещо в долният колонтитул на страницата (т.е. footer). И така отворих си съответният файл и какво да видя:

А ето и съкратена версия на горното (по-голяма част от низа е премахната за четимост):

<?php
/*
Encoder : NET-TEC PHP-ENCODER V 1.0
WEB : http://www.net-tec.biz/
WARNING: This file is protected by copyright law. To reverse engineer or decode this file is strictly prohibited.
*/
$Q16118B8947480F50A0A2FEDC99864231="DQovKg....Zm9vdGVyKCk7ID8+DQoNCjwvYm9keT4NCg0KPC9odG1sPg==";
eval(base64_decode($Q16118B8947480F50A0A2FEDC99864231));?>

И така видимо е че кодът не е четим с просто око. И така започваме с малко анализ. Няколко части са видими в кода:

  1. Отварящ PHP таг
  2. Коментар – който удобно посочва името, версията и сайта на производителят на инструмента използван за обфускиране
  3. PHP променлива – $Q16118B8947480F50A0A2FEDC99864231
  4. Стойност за тази променлива – ето отрязък от края на тази стойност – Zm9vdGVyKCk7ID8+DQoNCjwvYm9keT4NCg0KPC9odG1sPg==
  5. PHP eval() функция
  6. Затварящ PHP таг

Моля PHP и HTML гурутата да ме извинят ако има неточности в термините, които използвам.

Очевидно нито затварящият нито отварящият таг не ни носят никаква информация, която вече да не знаем, за сметка на това коментарът е пре-любопитен. Той съдържа името и версията на софтуера използван за обфускирането, сайта на софтуера а също така предупреждение, че декодирането на текста е забранено от законите за авторското право. Не съм специалист по Закона за авторското и сродните мъ права, но член 70 и член 71 ми изглеждат приложими с този случай. Разбира се първата ми работа беше да питам Google, но първите резултати бяха някакви форуми и тъй като ме мързеше да чета реших, че ще е по бързо да декодирам текста сам.

И така изправяме се пред декодирането на кода. В началото виждаме, че името на променливата не носи никаква полезна информация. След което забелязваме, че стойността на променливата подозрително прилича на base64 кодиран низ, особено с тия два знака за равно накрая. После няма как да пропуснем, че функцията eval() приема като аргумент върната стойност от функцията base64_decode(), на която, като параметър, е подадена дефинираната по-горе променлива. Решавайки, че низа „най-вероятно“ е base64 кодирана версия на (X)HTML кода, който ни интересува се насочваме към http://home2.paulschou.net/tools/xlate/, на който имам онлайн кодер/декодер за base64. Резултатът е следният:

А и компактната версия (отново с изрязан низ):

/*
Encoder : NET-TEC PHP-ENCODER V 1.0
WEB : http://www.net-tec.biz/
WARNING: This file is protected by copyright law. To reverse engineer or decode this file is strictly prohibited.
*/
?>
		<div class="clear"></div>
	</div>
	<!-- /Main -->
	<!-- Footer -->
	<div id="footer">
		Designed by <a href="http://bloggingzone.info">Custom WordPress Themes</a><br />
		Made free by <a href="http://www.wilsonfield.co.uk/corporate/cva-liquid-admin.htm">Insolvency</a> | <a href="http://www.ffxi-gil.info">FFXI Gil</a> | <?php /* v5 - WARNING: This file is protected by copyright law. To reverse engineer or decode this file is strictly prohibited. */
$o="QAAAOz...kNnMk1Da3VJajhpT3c9PSIpKTtldmFsKCRsbGxsbGxsbGwpOw=="));?>
	</div>
	<!-- Footer -->
</div>
<!-- /Page -->
<?php wp_footer(); ?>
</body>
</html>

И така ето какво откриваме:

  1. Коментар – същият като този по-горе
  2. Самотен затварящ таг – ?>
  3. Малко (X)HTML код – който изглежда като част от този който търсим
  4. Известно количество PHP код, който прилича изключително много на този с който започнахме
  5. Още (X)HTML – който явно случи за затваряне на страницата

С току що намереният (X)HTML можем да направим малък експеримент. Вземаме първата част, добавяме след нея втората и заменяме първоначалният код с така полученият. Подменяме файла на сървъра и voila, работи. ОК, бихме могли да спрем до дук, но аз лично се дразня много когато нещо, което се предполага да е колонтитул прави и други работи. Особено когато това не е документирано и е скрито в камара обфускиран код.

Но първо нека коментираме самотният затварящ се таг – ?>. За мен лично той няма смисъл, освен ако не е сложен там да затрудни инструменти занимаващи се с автоматичен анализ и декодиране на обфускиран код. Разбира се той може и да има друга функционалност, но след като получихме пълната функционалност на (X)HTML кода, не виждам за какво може да е.

И така, PHP кода започва с интересен коментар – v5, последван от нова предупреждение да не се декодира файла. За повече информация, по въпроса с декодирането, прочетете по-горе, където се говори за авторското право. Относно v5, според мен тук е използван друг инструмент или поне друга версия на същият инструмент. Версията най-вероятно има номер 5. Следва променлива $o. На пръв поглед изглежда, че тя не се използва. При опита ми да я декодирам, получих данни, които изглеждат случайна двоична информация. Всъщност тя се използва две нива на кодиране по-долу. При декодирането на низа подаден на eval() получих следното:

Поиграх си малко с форматирането и поличух следният код:

$lll=0;
eval(base64_decode("JGxsbGxsbGxsbGxsPSdiYXNlNjRfZGVjb2RlJzs="));
$ll=0;
eval($lllllllllll("JGxsbGxsbGxsbGw9J29yZCc7"));
$llll=0;
$lllll=3;
eval($lllllllllll("JGw9JGxsbGxsbGxsbGxsKCRvKTs="));
$lllllll=0;
$llllll=($llllllllll($l[1])<<8)+$llllllllll($l[2]);
eval($lllllllllll("JGxsbGxsbGxsbGxsbGw9J3N0cmxlbic7"));
$lllllllll=16;
$llllllll="";
for(;$lllll<$lllllllllllll($l);){
    if($lllllllll==0){
        $llllll=($llllllllll($l[$lllll++])<<8);
        $llllll+=$llllllllll($l[$lllll++]);
        $lllllllll=16;
    }
    if($llllll&0x8000){
        $lll=($llllllllll($l[$lllll++])<<4);
        $lll+=($llllllllll($l[$lllll])>>4);
        if($lll){
            $ll=($llllllllll($l[$lllll++])&0x0f)+3;
                for($llll=0;$llll<$ll;$llll++)
                    $llllllll[$lllllll+$llll]=$llllllll[$lllllll-$lll+$llll];
                $lllllll+=$ll;
        } else{
        $ll=($llllllllll($l[$lllll++])<<8);
        $ll+=$llllllllll($l[$lllll++])+16;
        for($llll=0;$llll<$ll;$llllllll[$lllllll+$llll++]=$llllllllll($l[$lllll]));
        $lllll++;
        $lllllll+=$ll;
        }
    }else
        $llllllll[$lllllll++]=$llllllllll($l[$lllll++]);
    $llllll<<=1;$lllllllll--;
}
eval($lllllllllll("JGxsbGxsbGxsbGxsbD0nY2hyJzs="));
$lllll=0;
eval($lllllllllll("JGxsbGxsbGxsbD0iPyIuJGxsbGxsbGxsbGxsbCg2Mik7"));
$llllllllll="";
for(;$lllll<$lllllll;){
    $llllllllll.=$llllllllllll($llllllll[$lllll++]^0x07);
}
eval($lllllllllll("JGxsbGxsbGxsbC49JGxsbGxsbGxsbGwuJGxsbGxsbGxsbGxsbCg2MCkuIj8iOw=="));
eval($lllllllll);

Разглеждайки внимателно кода, виждаме, че има няколко base64 низа, но по интересно, виждаме използването на променливи и функции, които не се дефинират в кода (например масива $l и функцията $llllllllllll). За това се насочваме към разкодирането на останалите низове:

$lll=0;
// eval(base64_decode("JGxsbGxsbGxsbGxsPSdiYXNlNjRfZGVjb2RlJzs="));
$lllllllllll='base64_decode'; // decoded
$ll=0;
//eval($lllllllllll("JGxsbGxsbGxsbGw9J29yZCc7"));
$llllllllll='ord'; // decoded
$llll=0;
$lllll=3;
//eval($lllllllllll("JGw9JGxsbGxsbGxsbGxsKCRvKTs="));
$l=$lllllllllll($o); // decoded
$lllllll=0;
$llllll=($llllllllll($l[1])<<8)+$llllllllll($l[2]);
//eval($lllllllllll("JGxsbGxsbGxsbGxsbGw9J3N0cmxlbic7"));
$lllllllllllll='strlen'; // decoded
$lllllllll=16;
$llllllll="";
for(;$lllll<$lllllllllllll($l);){
    if($lllllllll==0){
        $llllll=($llllllllll($l[$lllll++])<<8);
        $llllll+=$llllllllll($l[$lllll++]);
        $lllllllll=16;
    }
    if($llllll&0x8000){
        $lll=($llllllllll($l[$lllll++])<<4);
        $lll+=($llllllllll($l[$lllll])>>4);
        if($lll){
            $ll=($llllllllll($l[$lllll++])&0x0f)+3;
                for($llll=0;$llll<$ll;$llll++)
                    $llllllll[$lllllll+$llll]=$llllllll[$lllllll-$lll+$llll];
                $lllllll+=$ll;
        } else{
        $ll=($llllllllll($l[$lllll++])<<8);
        $ll+=$llllllllll($l[$lllll++])+16;
        for($llll=0;$llll<$ll;$llllllll[$lllllll+$llll++]=$llllllllll($l[$lllll]));
        $lllll++;
        $lllllll+=$ll;
        }
    }else
        $llllllll[$lllllll++]=$llllllllll($l[$lllll++]);
    $llllll<<=1;$lllllllll--;
}
//eval($lllllllllll("JGxsbGxsbGxsbGxsbD0nY2hyJzs="));
$llllllllllll='chr'; // decoded
$lllll=0;
//eval($lllllllllll("JGxsbGxsbGxsbD0iPyIuJGxsbGxsbGxsbGxsbCg2Mik7"));
$lllllllll="?".$llllllllllll(62); // decoded
$llllllllll="";
for(;$lllll<$lllllll;){
    $llllllllll.=$llllllllllll($llllllll[$lllll++]^0x07);
}
//eval($lllllllllll("JGxsbGxsbGxsbC49JGxsbGxsbGxsbGwuJGxsbGxsbGxsbGxsbCg2MCkuIj8iOw=="));
$lllllllll.=$llllllllll.$llllllllllll(60)."?"; // decoded
eval($lllllllll);

От горният код виждаме някой интересни декларации:

  • $llllllllll=’ord’;
  • $lllllllllll=’base64_decode’;
  • $llllllllllll=’chr’;
  • $lllllllllllll=’strlen’;

Всеки от стринговете отговаря на функция в PHP. Ето и какво правят те според документацията на езика:

  • int ord (string $string) – връща ASCII стойността на първият символ от даден низ
  • string base64_decode (string $data) – декодира base64 кодиран низ
  • string chr (int $ascii) – връща низ от еднин символ, чиято ASCII стойност е подадеna като параметър
  • int strlen (string $string) – връща дължината на даден низ

И така заместваме не четимите променливи със съответните им функции и получаваме:

$lll=0;
$ll=0;
$llll=0;
$lllll=3;
//eval(base64_decode("JGw9JGxsbGxsbGxsbGxsKCRvKTs="));
$l=base64_decode($o); // decoded
$lllllll=0;
$llllll=(ord($l[1])<<8)+ord($l[2]);
$lllllllll=16;
$llllllll="";
for(;$lllll<strlen($l);){
    if($lllllllll==0){
        $llllll=(ord($l[$lllll++])<<8);
        $llllll+=ord($l[$lllll++]);
        $lllllllll=16;
    }
    if($llllll&0x8000){
        $lll=(ord($l[$lllll++])<<4);
        $lll+=(ord($l[$lllll])>>4);
        if($lll){
            $ll=(ord($l[$lllll++])&0x0f)+3;
                for($llll=0;$llll<$ll;$llll++)
                    $llllllll[$lllllll+$llll]=$llllllll[$lllllll-$lll+$llll];
                $lllllll+=$ll;
        } else{
        $ll=(ord($l[$lllll++])<<8);
        $ll+=ord($l[$lllll++])+16;
        for($llll=0;$llll<$ll;$llllllll[$lllllll+$llll++]=ord($l[$lllll]));
        $lllll++;
        $lllllll+=$ll;
        }
    }else
        $llllllll[$lllllll++]=ord($l[$lllll++]);
    $llllll<<=1;$lllllllll--;
}
$lllll=0;
//eval(base64_decode("JGxsbGxsbGxsbD0iPyIuJGxsbGxsbGxsbGxsbCg2Mik7"));
$lllllllll="?".chr(62); // decoded
for(;$lllll<$lllllll;){
    "".=chr($llllllll[$lllll++]^0x07);
}
//eval(base64_decode("JGxsbGxsbGxsbC49JGxsbGxsbGxsbGwuJGxsbGxsbGxsbGxsbCg2MCkuIj8iOw=="));
$lllllllll.="".chr(60)."?"; // decoded
eval($lllllllll);

И така получаваме крайната версия на кода. Имената на променливите са доста подобни и бихме могли да продължим с тяхното преименуване за по-голяма четимост. Само че като разгледаме кода малко по внимателно можем да видим, че има поне един безсмислен цикъл. Последният for цикъл всъщност не прави нищо освен да конкатенира към празен низ. Първият цикъл от своя страна прави някакви обработки върху променливата , която беше намерена по-горе, която всъщност е масив. Обработките изглеждат доста безсмислени, тъй като променливите в които се съхраняват данните не се използват извън цикъла.

Ако инцидентно успеете да изпълните PHP кода (както ми се случи няколко пъти по време на писането на тази статия) ще забележите, че обработката на данните е изключително дълга и браузърът ви забива. След известно време Firefox ми даваше възможност да спра изпълнението на скрипта, тъй като не изглежда забил. Явно целта на този код е да направи така, че „хакерите“, които се опитат да го разкодират да си направят страницата не работеща. От моя гледна точка това е леко смешно, не е много трудно да се разбере кой е причинителя и да се премахне.

Аз лично се чудя какво прави първият от двата цикъла. Въпреки че той очевидно няма никакъв ефект върху страницата, може би има някой готин скрит ефект. Например възможно е в някоя от променливите буква по буква да се образува някакъв текст. Но усилието, което би ми коствало да разбера е прекалено голямо за да си струва. Така че вие сте на ход, ако сте по-любопитни от мен :).

P.S. Един доста полезен сайт: http://writecodeonline.com/php/ – с него можете да изпълнявате PHP код онлайн, без да е необходимо да имате сървър. Е има си някой ограничения, но няма как.

This entry was posted in Програмиране and tagged , , , , . Bookmark the permalink.

Comments are closed.