Направо към съдържанието

Декомпилатор

от Уикипедия, свободната енциклопедия

Декомпилаторът е компютърна програма, която изпълнява обратната операция на тази на компилатора.

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

Декомпилация е действието от използването на декомпилатор, но може да се има предвид и самия резултат от декомпилатора. Успехът на декомпилацията зависи от количеството информация, предоставено от кода, който се декомпилира и начина, по който се анализира от декомпилатора. Биткод формат използван от много виртуални машини (като Java Virtual Machine и от .NET Framework Common Language Runtime) често съдържат метаданни и функции на високо ниво, които правят декомпилацията лесно осъществима. Присъствието на дебъг данни предоставя възможност да се възпроизвеждат оригиналните имена на променливите и на структурите, дори и номерацията на редовете. Код без такива метаданни и дебъг данни е много по-труден за декомпилиране.

Етапи на декомпилация

[редактиране | редактиране на кода]

Декомпилаторите могат да се разглеждат като поредица от етапи, всеки от които допринася специфични аспекти на цялостния процес на декомпилация.

Първата етап зарежда машинния код или междинния език на програмата. Би трябвало да открие основни факти за зададената програма като архитектурата (Pentium, PowerPC, и други) и входната точка.

Следващия етап е преобразуването на инструкциите от машинния код в машинно независимо междинно представяне(IR).

Идиоматични поредици от машинен код са поредици код, чиято комбинирана семантика не е непосредствено очевидна от инструкциите на индивидуалните семантики.

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

Анализ на програма

[редактиране | редактиране на кода]

Различни анализи на програма могат да се прилага на IR. По-специално изразно събиране комбинира семантиките на няколко инструкции в по-сложен израз. Резултатът е повече като език на високо ниво.

Анализ на потока данни

[редактиране | редактиране на кода]

Местата, където различните регистри се дефинират и използват, трябва да бъдат проследени с анализ на потокът данни. Същия анализ трябва да бъде приложен на места, които се използват за временни и локални данни. Различни имена могат да се формират за всеки свързан набор от стойностни дефиниции и употреби. Възможно е едно и също място в паметта да се използва за повече от една променлива в различни части от програмата. Анализът може да покаже дори ако определена променлива се използва за две различни цели, но тази логика да е имплементирана от компилатора, а не от разработчика.

Добър декомпилатор ще изпълнява такъв анализ. Чрез наблюдение на записването в паметта, декомпилаторът понякога може да разбере типът данни, който се записва.

Предпоследния етап включва структуриране на IR в конструкции от високо ниво като while цикли и if/then/else условни конструкции.

Последния етап е генерирането на код от високо ниво в back end-а на декомпилатора. Декомпилатора може да има опция да предостави този код в други езици от високо ниво.

Основни инструменти

[редактиране | редактиране на кода]

.NET Reflector е първата програма за разглеждане (браузване) на CLI(Common Language Infrastructure) компилиран код. Може да се използва за инспектиране, навигиране, търсене, анализиране или разглеждане на съдържанието на CLI компоненти, като например на изпълним файл под .NET Framework (познат още като асембли). Основната му функция е да превежда машинния код от ниско ниво до разбираем за хората код от високо ниво. Стандартно .NET Reflector позволява декомпилация на СLI асемблита до C#, Visual Basic .NET, Common Intermediate Language и F#. Друга полезна функционалност на Reflector е така нареченото „дърво на извикванията“ (Call Three), с помощта на което се проследяват методите на ниско ниво какви други методи извикват. Показва в детайли метаданни, ресурси и XML документация. .NET Reflector може да се използва от .NET програмистите за по-лесно разбиране на същината на начина, по които са имплементирани различни методи, класове, библиотеки и т.н., за показване на разликите в две версии на едно и също асембли, а също така и за лесно разбиране на взаимовръзката между две части на едно и също CLI приложение. Съществуват голям брой програми, който наследяват и допълнително разширяват и подобряват функционалността и възможностите на .NET Reflector.

Декомпилатор за Java

[редактиране | редактиране на кода]

Java Decompiler (JD) е декомпилатор, предназначен за работа с програмния език Java. Може да бъде намерен като приложение с графичен потребителски интерфейс както и под формата на плъгин за среда за разработка като Eclipse (JD-Eclipse) и IntelliJ IDEA (JD-IntelliJ).

JD поддържа всички версии на Java от 1.1.8 до 1.7.0, а също така и JRockit 90_150, Jikes 1.2.2, Eclipse Java Compiler и Apache Harmony и поради тази причина бива често предпочитан заместник на популярния в миналото JAD (JAva Decompiler). JD-Eclipse има поддръжка за Eclipse до версия 3.7(Indigo).

Boomerang e декомпилатор с GPL лиценз, който позволява превод от двоичен код до език близък до С. Boomerang използва Static Single Assignment Form за репрезентация на кода.

Разлика между Декомпилатор и дисасемблер

[редактиране | редактиране на кода]
резултат след декомпилиране
Изходен код от декомпилатор

Декомпилаторът превръща изпълнимия бинарен файл в лесно четима форма. По точно той трансформира бинарния код в по-високо ниво програмен език (C, C++ или Java), който програмисти и разработчици могат да четат и променят. Много често цялата индустрията за софтуерна защита разчита на тази трансформация, за да анализира и одобри определени софтуерни продукти. Анализът се прави върху двоичния код, ползвайки декомпилатори, просто защото изходния програмен код традиционно не е достъпен, най-често поради търговска тайна.

Дисасемблерите от своя страна превръщат простите двоични инструкции на процесора едно към едно в мнемонични инструкции (код). Обикновено мнемоничният код представлява символно наименование на една изпълнима на машинен език инструкция (операционен код) и съществува поне по един операционен мнемоничен код, дефиниран за всяка инструкция на машинен език.

Декомпилаторите се различават от дисасемблерите по един много важен показател. Тъй като и двата създават лесен за четене от хората последователност от текстови команди, но декомпилаторите създават доста по високо ниво текстови инструкции, които са по-смислени и доста по лесни за четене. Сравнен с ниско ниво асемблерните езици, езикът от високо ниво като Java, има следните предимства:

  • Значително по-смислен е
  • Структуриран е
  • Не изисква от разработчиците да знаят асемблерен език
  • По-малко объркващ е следователно е по-лесен за разбиране
  • Разпознава и преобразува идиомите от ниско ниво в понятия от високо ниво
  • По-малко повторяем е и съответно не толкова разсейващ
  • Използва анализ на потока от данни

Обикновено изходния код от декомпилаторите е от пет до десет пъти по-къс от този на дисасемблерите. Например, най-често една програма съдържа от 400KB до 5MB бинарен (двоичен) код. Съответно изходния код, който дисасемблера ще генерира ще включва от 5-100MB текст, което би отнело от няколко седмици до няколко месеца за да се анализира напълно. Докато при декомпилаторите кода за същата програма би бил от 400KB до 10MB, като в този случай времето за анализ би било 10 пъти по-малко.

дисасемблерен код
Изходен код от дисасемблер

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

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

За да може да се ползва дисасемблер, анализаторите на код трябва добре да познават асемблерният език на дадения процесор. Разбира се основната част от програмистите не използват асемблер езикът всекидневно, а по скоро по-високо ниво езици като Java. По този начин декомпилатора прескача границата между обикновените програмни езици от високо ниво до изходния език.

Декомпилатора преобразува идиомите от асемблер в по високо ниво абстрактен програмен език. Някои идиоми могат да бъдат доста дълги и времеемки за анализ. Следната последователност от код:

x = y / 2;

може да бъде трансформирана от компилатора в серия от 20 – 30 процесорни инструкции. Това би отнело между 15 – 30 секунди на един опитен анализатор да разпознае модела и мислено да го замени с оригиналния ред. Ако кода включва много такива изрази, съответно анализатора трябва да си води бележки и да описва всеки модел с неговия къс израз. Всичко това би забавило анализатора значително. Декомпилаторът просто премахва това неудобство от анализатора на кода.

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

  Тази страница частично или изцяло представлява превод на страницата Decompiler в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​

  Тази страница частично или изцяло представлява превод на страницата Java Decompiler в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​

  Тази страница частично или изцяло представлява превод на страницата .NET Reflector в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​

  Тази страница частично или изцяло представлява превод на страницата Boomerang(decompiler) в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​