27.7 Decompiler und Obfuscatoren 

Ein Decompiler wandelt Java-Klassendateien in Java-Quellcodedateien zurück. Er verdreht also die Arbeitsweise eines Compilers, der aus der Quellcodedatei eine ausführbare Datei beziehungsweise Klassendatei erzeugt. Obwohl es für die verschiedensten Sprachen Decompiler gibt (unter anderem .NET, C und Smalltalk), ist für Java die Zurückübersetzung relativ einfach. Der Java-Compiler erstellt für einen virtuellen Prozessor Bytecode, und dieser Bytecode enthält viele wertvolle Informationen, die in einem herkömmlichen Maschinencode nicht auftauchen. Darunter sind etwa Typinformationen oder Hinweise, ob ein Methodenaufruf virtuell ist oder nicht. Sie sind für den Interpreter ebenfalls wichtig, um Programme als sicher oder unsicher zu erkennen. Dies macht es einfach, verlorenen Quellcode wiederzubeleben oder an fehlende Informationen aus Paketen von Fremdherstellern zu gelangen.
Ein weiteres Anwendungsgebiet sind Optimierungen am Quellcode. Über die Rückübersetzung lässt sich die Arbeitsweise eines Compilers gut verstehen, und wir können an einigen Stellen optimieren, wenn wir beispielsweise sehen, dass eine Multiplikation mit der Zahl 16 doch nicht zu einem Shift optimiert wurde. Das Übersetzen ist dabei verhältnismäßig einfach. Ein Decompiler benötigt lediglich die Klassendatei, wobei einige Decompiler auch direkt einen Verbund von Klassen aus einem Jar-Archiv unterstützen. Aus dem Java-Bytecode für eine Methode baut der Decompiler dann einen Kontrollfluss-Graphen auf und versucht, Ausdrücke zu erkennen, die bei der Übersetzung bestimmter Sprachkonstrukte entstanden sein müssten. Da Variablennamen durch einen Obfuscator eventuell ungültig gemacht worden sind, muss ein guter Decompiler diese illegalen Bezeichnernamen korrigieren. Somit sollte der Quelltext auch noch gut lesbar sein, obwohl er verunstaltet wurde. Diese Umbenennung ändert den Algorithmus nicht, und ein Decompiler hat es bei dieser Art von Verschleierung einfach. Es sind allerdings andere Techniken in der Entwicklung, die den Bytecode erst zur Laufzeit entschlüsseln, und dieser ist dann in der Klassendatei nicht mehr lesbar.
Da mittlerweile auch andere Compiler auf dem Markt sind, die Java-Bytecode erzeugen – etwa aus EIFFEL-Programmen oder aus diversen LISP-Dialekten –, ist über den Umweg Compiler/Klassendatei/Decompiler ein Crosscompiling denkbar. Hier sind jedoch einige Einschränkungen bezüglich der auf dem Markt befindlichen Decompiler erkennbar. Denn fremde Compiler, die Java-Bytecode erstellen, haben andere Techniken, die der Decompiler dann nicht immer passend übersetzen kann.
Ist das Decompilieren legal?
Lassen wir einen Decompiler auf den eigenen Programmcode los, weil etwa der Quellcode verschwunden ist, dann ist die Anwendung kein rechtliches Problem. Das Reverse Engineering von vollständigen Anwendungen, die unter Urheberschutz stehen, muss nicht unbedingt ein Problem darstellen. Vielmehr beginnt die Straftat, wenn dieser Quelltext verändert und als Eigenleistung verkauft wird.
27.7.1 Der Decompiler Jad 

Jad (von Java Decompiler) ist ein frei verfügbarer Decompiler von Pavel Kouznetsov und oft [Das Kalkül der Anbieter von freiem Webspace besteht darin, immer nur Seiten anzubieten, die niemand kennt. Immer dann, wenn eine Seite bekannt ist und oft aufgerufen wird, muss der Freespacer tiefer in die Tasche greifen. Dann macht er die Seite einfach mit einer netten Meldung dicht (»The Tripod page you are trying to reach has exceeded its hourly bandwidth limit. The site will be available again in 2 hours!« ). ] unter der folgenden Adresse zu beziehen: http://www.kpdus.com/jad.html. Jad ist in C++ geschrieben [Wollte der Autor verhindern, dass auch sein Tool entschlüsselt wird? ] und decompiliert die Dateien sehr schnell. Bedauerlicherweise hat der Autor die Entwicklung von Jad eingestellt und möchte auch den Quellcode nicht freigeben, um eine Weiterentwicklung zu ermöglichen.
Da Jad auf jeden Fall den Bytecode auseinandernehmen muss, lässt sich zum Disassemblieren der Java-Bytecode auch in den Quellcodezeilen einblenden; eine prima Möglichkeit, Bytecode zu lernen und zu sehen, wie der Compiler funktioniert. Einen weiteren Pluspunkt bekommt Jad im Umgang mit Klassendateien, die ein Obfuscator [Ein Obfuscator benennt Methoden- und Klassennamen in unsinnige Bezeichner um. Er verschlüsselt Zeichenketten und versucht, im Code solche Bytecode-Kombinationen einzubauen, die von einem normalen Decompiler nicht wieder umgewandelt werden können. ] (leicht) verunstaltete. Daraus wird wieder gültiger Java-Code erzeugt. Manchmal muss Jad aber auch aufgeben, und dann verschwinden beispielsweise Zuweisungen.
27.7.2 Das Obfuscator-Programm ProGuard 

ProGuard (http://proguard.sourceforge.net/) ist ein Open-Source-Projekt unter der GPL-Lizenz, [Obwohl ProGuard selbst unter GPL steht, darf die Software auch angewendet werden auf Software, die nicht unter der GPL stehen. ] das Java-Klassen und Jar-Archive verschleiert. Es bietet eine ganze Reihe von Versteck-Aktionen:
- Löscht Debug-Informationen.
- Benennt Bezeichner für alle Pakete um und gestaltet sie für neugierige Augen ermüdend. Klassen heißen dann zum Beispiel C1, C2, ... und Methoden m1, m2, ...
- Vereinfacht Bytecode-Sequenzen.
Neben der Verschleierung ist ein Nebeneffekt, dass die Klassendateien kleiner werden, was insbesondere für Applets und Midlets (mobile Anwendungen) interessant ist. ProGuard 3 bietet Unterstützung für das Bytecode-Format von Java 5 und Java ME – ProGuard 4 bietet Obfuscation auch für Java 6. Die Software lässt sich über eine Swing-Oberfläche oder über die Kommandozeile bedienen oder aber auch über ein Ant-Skript steuern. Die Webseite nennt ein Beispiel, das alle Typen bis auf Applets eines Java-Archivs berücksichtigt. Auf der Kommandozeile ist anzugeben:
$ java -jar proguard.jar –injars in.jar -outjars out.jar –libraryjars $JAVA_HOME/lib/rt.jar-keep public class * extends java.applet.Applet