Frage:
Warum gibt es (manchmal große) Unterschiede zwischen dem Java-Quellcode und seinem dekompilierten Ergebnis?
JMcAfreak
2013-07-23 02:20:59 UTC
view on stackexchange narkive permalink

Ich habe einen [relativ komplexen] Java-Code in eine .class-Datei kompiliert und ihn dann mit jad wieder in Java dekompiliert. Natürlich war der Code verschleiert, was zu erwarten war. Da ich jedoch den Originalcode hatte, dachte ich, ich könnte den dekompilierten Code ziemlich einfach durchsehen. Ich habe jedoch Unterschiede im Code festgestellt, z. B. wo bestimmte Variablen definiert wurden (einschließlich Unterschiede im Umfang).

Gibt es einen Hauptgrund dafür? Ich stelle mir vor, dass dies eines der Dinge ist, die nur beim Dekompilieren von Code passieren, aber ich bin neugieriger, welche Faktoren die Änderung verursachen (z. B. Komplexität des Codes, ob er sich auf andere Dateien bezieht usw.).

Könnte mir jemand eine gute Erklärung geben, welche Faktoren die Unterschiede im Code vorher und nachher verursachen?

Bearbeiten

Technisch gesehen wird die .class-Datei aus einem Glas gezogen. Ich habe den Inhalt extrahiert und dort die .class-Datei verwendet.

Was den von mir verwendeten Obfuscator betrifft, habe ich den Retroguard-Obfuscator mit den folgenden Optionen verwendet (ich untersuche derzeit nur die Verschleierung und finde heraus, welche jeweils vorhanden sind Dies führt zum Endergebnis.):

  .option Application.option Applet.option Repackage.option Annotations.option MapClassString.attribute LineNumberTable.attribute EnclosingMethod.attribute Veraltet  

Die Dokumentation für das Skript finden Sie auf ihrer Website. Es ist ein wenig unorganisiert, aber Sie sollten in der Lage sein, angemessene Erklärungen zu finden. Es ist auch bemerkenswert, dass ich die Generika und die lokale Variablentabelle entfernt habe.

Ich habe jetzt auch eine Möglichkeit eingerichtet (inspiriert von den Entwicklern des Minecraft Coder Pack), die Quellen mithilfe von Daten aus einer Datei umzubenennen ( oder Dateien), die an ein Wörterbuch mit Listen für Pakete, Klassen, Methoden und Felder übergeben werden.

  # Snippet aus der MCP-Version (meine ist etwas anders) (alle in Python): srg_types = {'PK:': ['obf_name', 'deobf_name'], 'CL:': ['obf_name', 'deobf_name'],
'FD:': ['obf_name', 'deobf_name'], 'MD:': ['obf_name', 'obf_desc', 'deobf_name', 'deobf_desc']} parsed_dict = {'PK': [], 'CL ': [],' FD ': [],' MD ': []}  

Eine Zeile wird dann aus der Datei analysiert und an das parsed_dict und dann verwendet, um alles umzubenennen (hin und her). Implementiert nach dem Kompilieren als beim ersten Dekompilieren (nachdem ich Unterschiede festgestellt habe).

Welchen Obfuscator haben Sie übrigens benutzt? Klingt nicht nach einem sehr guten Verschleierer. Außerdem ist Jad ziemlich alt. Ich würde empfehlen, stattdessen Procyon für unverhüllten Code zu verwenden.
@Antimony Die Frage mit der Antwort darauf wurde bearbeitet. Als Randnotiz versuche ich momentan nicht, alles vollständig zu verschleiern. Ich werfe Dinge an die Wand und sehe, was klebt (ja, sehr unorganisiert, aber auch lustig).
Wenn Sie versuchen, verschleierte Klassen zu dekompilieren, sollten Sie Krakatau verwenden. Es wurde speziell für verschleierte Klassen entwickelt und kann häufig mit Dingen umgehen, die kein anderer Dekompiler kann. https://github.com/Storyyeller/Krakatau
@Antimony Süß. Danke für den Vorschlag. Ich werde das untersuchen.
Drei antworten:
Ditmar Wendt
2013-07-23 05:16:43 UTC
view on stackexchange narkive permalink

Java kompiliert zu Bytecode, der in der JVM ausgeführt und in den .class-Dateien gespeichert wird. Dieser Bytecode ist keine 1: 1-Darstellung des ursprünglichen Codes und enthält mehrere vom Compiler implementierte Optimierungen. Informationen gehen verloren, wenn diese Optimierungen durchgeführt werden, und aufgrund dieser verlorenen Informationen können Dekompilierer den Code nicht wieder genau so rekonstruieren, wie er war.

Antimony
2013-07-23 07:56:29 UTC
view on stackexchange narkive permalink

Um das zu ergänzen, was Ditmar gesagt hat, ist das große Problem wahrscheinlich Ihre Verschleierung. Normaler Java-Bytecode kommt der ursprünglichen Quelle tatsächlich überraschend nahe, zumindest aus der Sicht von C oder C ++ (oder sogar Scala). Sie werden immer einige Informationen verlieren, aber nicht verschleiertes Java kann zu etwas dekompiliert werden, das dem Original nahe kommt, insbesondere wenn Sie mit Debug-Informationen kompilieren.

Alles, was mit Verschleierung aus dem Fenster geht, wird jedoch absichtlich von Verschleiern versucht um die Struktur des Codes zu manipulieren. Wenn Sie verschleierten Code dekompilieren, sollten Sie mehr erstaunt sein, wenn Sie überhaupt Ähnlichkeiten finden.

Ja, laut der Bearbeitung des Posters ist dies sicherlich eine Frage, die durch Verschleierung ausgelöst wurde. Guter Aufruf, das vorherzusagen. Leser sollten beachten, dass diese Antworten für .NET MSIL-Sprachen (wie C #) in Bezug auf die Verschleierung / ihren nahezu 1: 1-Bytecode auf sehr ähnliche Weise gelten.
@Ditmar Java ist dem Bytecode etwas näher als CIL, da der Bytecode nur für eine einzelne Sprache entwickelt wurde. Aber Sie haben Recht, dass sie sich sehr ähnlich sind.
Nessie
2013-08-29 12:16:04 UTC
view on stackexchange narkive permalink

Ihre Wahl des Dekompilierers kann das Ergebnis stark beeinflussen. Sie sollten entweder JODE oder Fernflower probieren (was meiner Meinung nach von Androchef stammt).

Vor dem Dekompilieren ist es möglicherweise eine gute Idee, selbst eine einfache Deobfuscation durchzuführen. Sie können beispielsweise versuchen,

  • Java-Schlüsselwörter, die als Klassen- / Methoden- / Variablennamen für legale Java-Bezeichner verwendet wurden, neu zuzuordnen. Diese Aufgabe ist mit den Remapping-Adaptern der ASM-Bibliothek http://asm.ow2.org/asm40/javadoc/user/org/objectweb/asm/commons/RemappingClassAdapter.html sehr einfach zu erledigen. a>

  • Einige einfache Reorganisation von Blöcken. Viele Verschleierer stecken Gotos an unangenehme Stellen, die sich "innerhalb eines einzelnen Ausdrucks" im Java-Quellcode befinden, z. Etwas auf den Stapel zu schieben, dann zu springen und es dann in einer lokalen Variablen im Ziel zu speichern, ist im Bytecode durchaus realisierbar, aber zu verstehen, dass der Bytecode einfach var = value ausführt, kann einigen Dekompilierern Schwierigkeiten bereiten.

Fernflower ist nicht sehr gut und ich glaube nicht, dass es überhaupt noch öffentlich verfügbar ist. Außerdem behandelt Krakatau automatisch die zweite von Ihnen erwähnte Deobfuscation sowie viele andere, obwohl die Ergebnisse nicht so gut sind, wenn der Code bereits nicht verschleiert ist.


Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...