Кодиране и декодиране на PHP код, блог за разработчици на phpBB

Поправям изходните кодове на PHP от кодирания изглед. В тази статия ще говоря за това как PHP кодира и декодира в реално време.

Обстойна кратка образователна програма за вътрешната структура на PHP интерпретатора

Когато се изпълнява PHP скрипт, той се анализира и компилира в кодовете на операциите на вътрешната PHP виртуална машина. От всеки PHP файл получавате: —масив от класове: във всеки клас—информация за класа, свойства на класа и масив от методи на класа —масив от функции —„тяло на скрипта”—код извън класове и функции

За краткост наричам цялата вътрешна конструкция на компилиран файл, готов за изпълнение, като “opcodes” в тази статия.

Самите кодове за операции (операции на вътрешната PHP виртуална машина) в дадена функция изглеждат така:

Важен момент: файловете в компилираната форма са доста различни дори между подверсиите на PHP интерпретатора. Ясно е: той си го състави - сам го изпълни.

Как работят енкодерите

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

Първите работят необикновено чрез самия език. Те правят кода нечетлив с поддръжка за кодиране base64, zip-кодиране, различни манипулации на низове и всички в крайна сметка използват функцията eval(). Всичко това е много подобно на обфускаторите в Javascript. Изглежда нещо подобно:

Такава защита се отстранява много лесно, в най-трудните случаи - за няколко часа. Друг голям недостатък е, че ефективността е сериозно засегната. Следователно, за сериозна употреба, такава защита не се препоръчва.

Вторият тип енкодер използва своите добавки за PHP интерпретатора, които се наричат ​​зареждащи устройства (зареждащиs). В такъв случай,като правило се кодира не самият първоначален код, а резултатите от неговата компилация, т.е. вътрешни структури и кодове за операции. Това вече е много по-сериозна защита - дори и да декодирате самите опкодове, пак трябва да възстановите първоначалния PHP код от тях. Също така, от гледна точка на производителността, добавената цена на декодирането често се компенсира от спестявания при компилирането на кода, т.е. скоростта на изпълнение на кодираните скриптове често е дори по-висока от тази на първоначалния код.

По време на зареждането на PHP интерпретатора, зареждащите устройства на енкодерите окачват своите манипулатори на функциите за зареждане на PHP файлове, компилиране и изпълнение, за да може работата с кодираните файлове да бъде прозрачна за самия интерпретатор.

Основната трудност за енкодерите е да направят така, че операционните кодове, компилирани под една версия на PHP по време на кодиране, да работят под различна версия на PHP, когато се декодират. Всъщност всички зареждащи устройства за всички енкодери правят необходимите промени след декодиране, за да осигурят такава съвместимост. Основният играч на този пазар -IonCube- веднъж положи огромни усилия да разреши този проблем и неговите зареждащи програми могат правилно да изпълняват кодове за операции от PHP 4.x до PHP 5.x в движение и най-вероятно дори обратното!

Объркване

Също така, за допълнителна защита, много енкодери позволяват да се затъмняват идентификатори: имена на променливи, имена на функции, класове. Този процес обикновено е еднопосочен - като хеширане, а освен това резултатът често е имена с непечатаеми знаци, които работят перфектно, но не могат да се използват директно в декомпилирани текстове. Кажете, как се пише функция с име... *диктуваща по байтове* 0x0D, 0x07, 0x03, 0x0B, 0x02, 0x04, 0x06?

Специално внимание се обръща на факта, чеобърканите имена биха работили правилно. Да кажем, че функцията checkLicense е извикана в кода - loader замъглява името в движение, получава < 0x0D, 0x07, 0x03, 0x0B, 0x02, 0x04, 0x06 > и търси дадения ключ в хеш-таблицата с имена на функции.

Zend Guard дори предоставя функции по време на изпълнение zend_obfuscate_function_name и zend_obfuscate_class_name, които ви позволяват да изчислявате обфускатни имена за функции и класове, за да улесните свързването на кодирани файлове с некодирани.

Декодерите отвръщат на удара

За да създадете декодер, вие се нуждаете от две неща: да получавате декодирани операционни кодове и да можете да ги декомпилирате в първоначалния PHP код.

За да придобие кодове за операции, някой излезе с ясна идея - да направи своя собствена сборка на PHP интерпретатора, която вместо да изпълни декодирания скрипт, да го изпрати за декомпилация. Няма нужда да се занимавате с четене на формата на енкодера и неговите предпазители - товарачът на енкодера върши цялата необходима работа!

Това забави тези, които "кърпеха товарачите" за дълго време. Първо, трябваше да разбера дълго време защо, така да се каже, правилно удължените кодове на операции се декомпилират с грешки. Второ, тук вече не беше лесно да промените няколко байта в товарача.

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

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

Имало едно време ясни глави, които написаха няколко добри алгоритма за декомпилиране на PHP. Много от тези, които сега се занимават с PHP декодиране, не могат да напишат собствен декомпилатор, затова използват тези, които са, с минимални редакции.

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

За да обобщим: все още няма напълно механично декодиране за основните търговски енкодери.

Как да се предпазите от декодиране

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

  • вероятно използват нови версии на PHP и самия език изцяло: пространства от имена, черти, ламбда
  • по всякакъв начин използвайте обфускация на имена и внимавайте да не използвате кратки и общи имена: $ch, $ci, $arr, 'license', 'valid' ...
  • декодерите обичат конструкции като connect(. ) или die(. ); и техните варианти на формата: defined('MYCONST') или define('MYCONST', true); или ($_alias = $object_name) ИЛИ $_alias = $class;
  • само "отлични" декодери разбират най-редките конструкции на формата: $valid ? $a : изход ('Грешка!');

$валиден? $valid : print('Грешка!'); // въпрос към PHP експертите: знаете ли защо print е тук?

  • използвайте вашия „любим“ елемент на езика: list( , , $c, $d) и конструкции като while(list($k, $v) = each($arr))
  • опитайте "десерт за декомпилатор":
  • (хуморът е, че декомпилаторите обикновено чакат да видят поне един CASE, в противен случай те не разбират, че тук е имало конструкция за превключване)

  • някои публично достъпни декодери се провалят при трудни имена на методи или свойства: $obj->
  • другата част се проваля с магически начини, включително дори __construct
  • Правни аспекти

    Най-общо казано, PHP декодирането ефайлове по-късно от търговски енкодери е незаконно. Технически това се дължи на факта, че за пълно декодиране е необходимо да се декомпилират и изследват самите енкодери, а законът и потребителските споразумения директно забраняват това.

    На територията на Европейския съюз има такъв трик: позволено е да "осигурите съвместимостта на копията на софтуера, който притежавате, и за да направите това, ако е необходимо, заобиколете вградените системи за сигурност". В същото време директната линия ще се затвори при обратно инженерство, за всеки енкодер тя все още има приоритет.

    Оказва се, че „Изтеглих програма от интернет, която ми даде некриптирани кодове за операции“ или „Използвах специална сборка на PHP интерпретатора, която записва декриптирани кодове за операции“ - това са условно законни методи за декодиране. „Условно“ – защото, ако делото все пак стигне до съд, пак не е ясно кой ще е прав.

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

    Увлекателни факти и истории

    Голяма част от енкодерите през последните няколко години само леко променят файловия формат „под капака“ и се пускат под прикритието на нова версия.

    Когато кратките имена са объркани, често възникват сблъсъци. Очевидно в такива случаи техническата помощ на енкодерите лесно съветва да не се използва обфускация.

    Фрилансерите често използват части от код от PHP документацията и от StackOverflow, че речник, съставен от идентификатори, взети от там от примери, обикновено позволява деобфускация под 90% от всички имена в средния план.

    За всичкидокато работех, срещнах само пет различни PHP декомпилатора. Три от тях са написани от българоговорящи програмисти, още един от китаец, а за още един се кълняха, че са французи. Дребно, но радващо - гордеем се с "нашите"

    В същото време много българоговорящи клиенти молят по свой начин да свършат работата на безценица

    И накрая, няколко истории

    Един арабин, след дълго обсъждане на плана си, информира, че „бюджетът ми е 15 долара, но всички разбираме ... тук има много работа, така че можете лесно да пуснете всичките си програми и ние сами по някакъв начин ще декодираме всичко.“

    Няколко пъти се оказа, че само аз мога да декодирам определен файлов формат. И същите файлове идваха за декодиране през няколко различни посредника едновременно. Бях много забавен от тази история: черен мъж с африканско име и швейцарско гражданство се скарал с програмист на свободна практика от Австралия, не му платил за работата му и останал с няколко кодирани недовършени файла на сайта си. Дълго търсих в борсите за свободна практика някой, който да ги декодира, докато накрая един индиец му продаде услугите си. В продължение на три седмици този индиец хранеше клиента със закуска, докато самият той интензивно търсеше истински изпълнител. В същото време самият клиент (бръмбарът е същият) под различно име продължи да търси други декодери на същите борси на свободна практика. Намери ме, даде ми проекта… и точно там, буквално 30 минути по-късно, един индиец почука на вратата ми и с усещане за очевидно опростяване започна да ме убеждава да направя и неговия план. Сравних файловете и... Разбира се, би си струвало да взема 100% от авансовото плащане и от двамата за образователни цели... но лесно ги принудих да говорят и да оправят нещата помежду си. Според изводите, индиецът все още не забравя да ми честити рождения ден. Клиентът дори ми дадебонус, а сега се премести в Естония (!), защото там е по-евтино да се живее, и периодично ме убеждава да участвам в някои негови съмнителни проекти.

    UPD. Трябваше да изрежа част от примера с кодиран с eval код, защото Kaspersky издаде предупреждение за него. Благодаря ти nokimaro!