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

от Уикипедия, свободната енциклопедия
Направо към навигацията Направо към търсенето

Java декомпилаторът е вид декомпилатор – програмен инструмент, който превръща изпълними файлове на компютърни програми в изходен код, разбираем от хора[1][2]. Операцията е обратна на тази на компилатора, който превежда изходния код на машинен език. Качеството на декомпилацията варира значително в зависимост от сложността на програмата и наличие на метаданни. Начина по който декомпилаторът анализира изпълнението на програмата също има ключова роля.

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

Java компилаторът компилира в двоичен код, който се изпълнява в JVM (Java виртуална машина) и се съхранява в .class файлове. Този двоичен код не представя едно към едно оригиналния Java код написан от програмиста и включва няколко оптимизации приложени от компилатора. Определена част от информацията се губи, когато се изпълни тази оптимизация. Поради тази причина декомпилаторите не могат да възстановят точно първоначалния вид на кода.

Как работи Декомпилатора[редактиране | редактиране на кода]

Декомпилацията може да се разбие на няколко поредни етапа:

Зареждане на машинния код[редактиране | редактиране на кода]

При зареждането трябва да се открият основни точки за зададената програма като архитектура и входната точка. В повечето случаи трябва да намери еквивалентни функции с основните функциите в Java.

Преобразуване[редактиране | редактиране на кода]

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

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

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

Анализ на програмата[редактиране | редактиране на кода]

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

Анализиране на потока от данни[редактиране | редактиране на кода]

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

Анализ на типовете данни[редактиране | редактиране на кода]

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

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

В този етап машинно междинно независимо представане(IR) структурира в конструкция от по високо ниво, като цикли while и условни конструкции (if, else, then).

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

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

Разлика между Декомпилатор и Дисасемблър[редактиране | редактиране на кода]

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

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

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

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

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

Да разгледаме тези точки по-детайлно. 

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

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

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

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

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

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

x = y / 2;

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

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

Различни Java Декомпилатори[редактиране | редактиране на кода]

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

Декомпилаторът Procyon е съвместим с всички версии на езика за компилиране Java по-нови от Java версия 5 (включително Java версия). Написан на Java версия 6, този декомпилатор е особено надежден в ситуации включващи:

  • Enum и String базирани switch изрази
  • Локални класове (анонимни и именувани)
  • Анотации
  • Java версия 8 ламбда изрази и референции към методи (например: :: оператор).

Често срещан проблем, е че класовете компилирани чрез средата Eclipse, може да не даде напълно правилни резултати. Това се забелязва най-често при String базирани switch изрази.

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

Безплатен, няма сорс код на разположение.[4]

Обновен последно през 2015 година и написан изцяло на езика за програмиране Java 6, декомпилаторът CFR поддържа Java версия 6,7 и 8 и е способен да декомпилира модерни Java функции като:

  • Ламбда изрази от Java версия 8
  • String базирани switch изрази от Java версия 7

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

Декомпилаторът AndroChef е собственост на компанията Microsoft и е способен да декомпилира клас файлове с разширение:

  • .apk
  • .dex
  • .jar
  • .java

Поддържа всички версии на езика за програмиране Java до Java версия 6 включително. Съвместим е със следните операционните системи:

Декомпилаторът AndroChef е способен да декомпилира бинарни кодове и сложни приложения написани на програмния език Java версия 6. Често се наблюдават проблеми при съвместна работа с Java JRE 64-bit пакет.

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

JAD е бил един от най-разпространените декомпилатори на програмния език Java. Написан изцяло на програмния език C++, JAD не е обновяван от 2011 година и отдавна е изгубил функционалността си сред съвременните езици като Java версия 5 и нагоре.

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

Отворен код. Създател: Egor Ushakov.

Oбновен последно през 2015 година, този бързо развиващ се аналитичен декомпилатор скоро ще е интегрирана част от средата за програмиране Intellij версия 14. Fernflower e съвместим и съпортва всички версии на програмния език Java до Java версия 6 включително.

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

Безплатен софтуер за некомерсиално използване. Създател: Emmanuel Dupuy.

Обновен последно през 2014 година, този декомпилатор притежава собствен визуален интерфейс и приставки към средите за разработка Eclipse и Intellij. JD е написан изцяло на езика за програмиране C++ и поддържа само версия 5 на езика за програмиране Java.

Източници[редактиране | редактиране на кода]