Javaのコンパイルと逆コンパイル
13401 ワード
Javaのコンパイルと逆コンパイル
コンパイルとは
コンパイルはC、C++、Javaなどの高級言語をアセンブリ言語、機械言語などの低級言語に変換する過程であり、低級言語はコンピュータの識別に有利であり、高級言語はプログラマーの編纂と読書に有利であり、この過程を実行するツールはコンパイラである.
Java言語にも独自のコンパイラ
実はclassファイルもマシンが認識できる言語ではなく、JVMはさらにclassバイトコードファイルをマシンが認識できるマシン言語に変換します.
逆コンパイルとは
コンパイルプロセスとは逆に、classファイルをjavaファイルに変換するプロセスであり、javaの逆コンパイルを通じて、東西java文法の背後にある原理を得ることがある.
Javaでよく使われる逆コンパイルツール
javap
以下はHelloWorld.javaのソースファイルです.switchで文字列をマッチングします.ソースコードは次のとおりです.
このコードは簡単で、文字列を初期化することで常に明るくなり、switchで対応する文字列をマッチングして出力することができます.ソースコードから具体的な比較方法を分析するのは難しいです.このとき、コンパイル---逆コンパイルの方法を使うことができます.
まず、HelloWorld.classのバイトコードファイルを
その後、classファイルを
JAvap共通パラメータ:
JAvapはバイトコードをjavaファイルに逆コンパイルするのではなく、バイトコードを理解できるように生成しました.実はjavapが生成したファイルは依然としてバイトコードで、プログラマーが少し理解できるだけです.バイトコードをマスターすれば、以上のコードが読めます.実はStringをhashcodeに変えて比較します.
一般的には、バイトコードを見る必要がある場合にのみ
jad
JADは比較的良い逆コンパイルツールで、実行ツールをダウンロードすればclassファイルの逆コンパイルを実現できます.それとも上のソースコードなのか、jadを使用して逆コンパイルすると次のようになります.
JAdの逆コンパイル後にHelloWorld.jadファイルが生成されます.内容は以下の通りです.
その逆コンパイルされたコードはソースコードに近く、読みやすくなっています.switch操作は実際にはcaceのhashCodeから
JAd共通パラメータ:
しかし、JADは長い間更新されていないため、Java 7で生成されたバイトコードを逆コンパイルする際に、サポートされていないという問題がたまに発生し、Java 8のlambda式を逆コンパイルする際には徹底的に失敗する
cfr
JADはとても使いやすくて、しかし仕方がないのはとても长い间更新していないので、1种の新しいツールで彼に代わることしかできなくて、CFRは1つの悪くない选択で、JADに比べて、彼の文法は少し复雑かもしれませんが、しかし彼は使うことができます.
CFRは、現代Javaの特性であるJava 8 lambdas(Javaおよびそれ以前のバージョンのJava beta 103)を逆コンパイルし、Java 7 Stringを逆コンパイルするが、CFRは完全にJava 6で記述する.
cfrのjarパッケージはhttp://www.benf.org/other/cfr/cfr_0_129.jarダウンロード
逆コンパイル処理の実行
出力は次のとおりです.
jad実行の結果と同様にパラメータが に類似しているのは、
JD-GUI
JD-GUIはC++で開発されたJava逆コンパイルツールで、Pavel Kouznetsovが開発し、Windows、Linux、アップルMac Osの3つのプラットフォームをサポートしています.また、Eclipseプラットフォームの下にあるプラグインJD-Eclipseも提供されています.JD-GUIはGPLv 3オープンソースプロトコルに基づいて、個人用には完全に無料です.JD-GUIは主に可視化操作を提供し、直接ファイルをウィンドウにドラッグすることができ、効果図は以下の通りである.
興味があればhttp://jd.benow.ca/GUIおよびidea、eclipseの逆コンパイルプラグインをダウンロードします.
JD-GUIの使用も非常に便利で、jarパッケージやclassファイルをJD-GUIインタフェースにドラッグしたり開いたりすれば逆コンパイルが完了するので、ここでは説明を思い出しません.
参考感謝:
https://blog.csdn.net/u011479200/article/details/80019827
https://blog.csdn.net/dongnan591172113/article/details/51832628
http://jd.benow.ca/
コンパイルとは
コンパイルはC、C++、Javaなどの高級言語をアセンブリ言語、機械言語などの低級言語に変換する過程であり、低級言語はコンピュータの識別に有利であり、高級言語はプログラマーの編纂と読書に有利であり、この過程を実行するツールはコンパイラである.
Java言語にも独自のコンパイラ
javac
コマンドがあり、HelloWorld.java
のファイルを作成すると、javac HelloWorld.java
のファイルをコマンドHelloWorld.class
でコンパイルすることができます.このclassファイルはJVMが認識できるファイルです.このプロセスはコンパイルのプロセスです.実はclassファイルもマシンが認識できる言語ではなく、JVMはさらにclassバイトコードファイルをマシンが認識できるマシン言語に変換します.
逆コンパイルとは
コンパイルプロセスとは逆に、classファイルをjavaファイルに変換するプロセスであり、javaの逆コンパイルを通じて、東西java文法の背後にある原理を得ることがある.
Javaでよく使われる逆コンパイルツール
javap
javap
はjdkが持参したツールで、コードを逆コンパイルしたりjavaコンパイラが生成したバイトコードを表示したりすることができます.一例で理解できます.以下はHelloWorld.javaのソースファイルです.switchで文字列をマッチングします.ソースコードは次のとおりです.
public class HelloWorld {
public static void main(String[] args) {
String str = "world";
switch (str) {
case "hello":
System.out.println("hello");
break;
case "world":
System.out.println("world");
break;
default:
break;
}
}
}
このコードは簡単で、文字列を初期化することで常に明るくなり、switchで対応する文字列をマッチングして出力することができます.ソースコードから具体的な比較方法を分析するのは難しいです.このとき、コンパイル---逆コンパイルの方法を使うことができます.
まず、HelloWorld.classのバイトコードファイルを
javac HelloWorld.java
で生成することができます.このときidea、eclipseでプラグインを借りない場合、HelloWorld.classファイルの内容が読めません.その後、classファイルを
javap -c HelloWorld.class
で逆コンパイルし、次のように出力します.Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String world
2: astore_1
3: aload_1
4: astore_2
5: iconst_m1
6: istore_3
7: aload_2
8: invokevirtual #3 // Method java/lang/String.hashCode:()I
11: lookupswitch { // 2
99162322: 36
113318802: 50
default: 61
}
36: aload_2
37: ldc #4 // String hello
39: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_3
47: goto 61
50: aload_2
51: ldc #2 // String world
53: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_3
61: iload_3
62: lookupswitch { // 2
0: 88
1: 99
default: 110
}
88: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #4 // String hello
93: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 110
99: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #2 // String world
104: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 110
110: return
}
JAvap共通パラメータ:
-help
-l
-public public
-protected public protected
-package ,public protected ,
-p -private
-s
-c , , , java ,
-verbose ,
-constants final
JAvapはバイトコードをjavaファイルに逆コンパイルするのではなく、バイトコードを理解できるように生成しました.実はjavapが生成したファイルは依然としてバイトコードで、プログラマーが少し理解できるだけです.バイトコードをマスターすれば、以上のコードが読めます.実はStringをhashcodeに変えて比較します.
一般的には、バイトコードを見る必要がある場合にのみ
javap
コマンドが必要であり、バイトコードから漏れた情報が最も完全であり、逆コンパイルで読みやすいclassファイルを生成したい場合には、以下の2つの神器を使用することができます.jad
JADは比較的良い逆コンパイルツールで、実行ツールをダウンロードすればclassファイルの逆コンパイルを実現できます.それとも上のソースコードなのか、jadを使用して逆コンパイルすると次のようになります.
jad HelloWorld.class
Parsing HelloWorld.class... Generating HelloWorld.jad
JAdの逆コンパイル後にHelloWorld.jadファイルが生成されます.内容は以下の通りです.
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: HelloWorld.java
import java.io.PrintStream;
public class HelloWorld
{
public HelloWorld()
{
}
public static void main(String args[])
{
String s = "world";
String s1 = s;
byte byte0 = -1;
switch(s1.hashCode())
{
case 99162322:
if(s1.equals("hello"))
byte0 = 0;
break;
case 113318802:
if(s1.equals("world"))
byte0 = 1;
break;
}
switch(byte0)
{
case 0: // '\0'
System.out.println("hello");
break;
case 1: // '\001'
System.out.println("world");
break;
}
}
}
その逆コンパイルされたコードはソースコードに近く、読みやすくなっています.switch操作は実際にはcaceのhashCodeから
equals
の方法で2つの文字列を比較していることがわかります.JAd共通パラメータ:
-a - JVM
-af - -a,
-clear -
-b - (e.g., if(a) { b(); }, default: no)
-d -
-dead - dead (default: no)
-disass - (no JAVA source generated)
-f - ,
-ff - (default: after methods)
-i -
-l - strings (default: no)
-lnc - (default: no)
-nl - strings newline character (default: no)
-nodos - class dos (CR before NL, default: check)
-nocast -
-nocode -
-noconv - java (default: do)
-noctor -
-noinner - (default: turn on)
-nolvt -
-nonlb - (default: do)
-o - (default: no)
-p - STDOUT (e.g., for piping)
.
jad -o -r -sjava -dsrc test.class
tree *.class
jad -o -r -sjava -dsrc tree/**/*.class
unix :jad -o -r -sjava -dsrc 'tree/**/*.class'
,
jad -p example1.class > myexm1.java
しかし、JADは長い間更新されていないため、Java 7で生成されたバイトコードを逆コンパイルする際に、サポートされていないという問題がたまに発生し、Java 8のlambda式を逆コンパイルする際には徹底的に失敗する
cfr
JADはとても使いやすくて、しかし仕方がないのはとても长い间更新していないので、1种の新しいツールで彼に代わることしかできなくて、CFRは1つの悪くない选択で、JADに比べて、彼の文法は少し复雑かもしれませんが、しかし彼は使うことができます.
CFRは、現代Javaの特性であるJava 8 lambdas(Javaおよびそれ以前のバージョンのJava beta 103)を逆コンパイルし、Java 7 Stringを逆コンパイルするが、CFRは完全にJava 6で記述する.
cfrのjarパッケージはhttp://www.benf.org/other/cfr/cfr_0_129.jarダウンロード
逆コンパイル処理の実行
java -jar /Users/home/Desktop/cfr_0_129.jar HelloWorld.class --decodestringswitch false
出力は次のとおりです.
src $ java -jar /Users/tongkun/Desktop/cfr_0_129.jar HelloWorld.class --decodestringswitch false
/*
* Decompiled with CFR 0_129.
*/
import java.io.PrintStream;
public class HelloWorld {
public static void main(String[] arrstring) {
String string;
String string2 = string = "world";
int n = -1;
switch (string2.hashCode()) {
case 99162322: {
if (!string2.equals("hello")) break;
n = 0;
break;
}
case 113318802: {
if (!string2.equals("world")) break;
n = 1;
}
}
switch (n) {
case 0: {
System.out.println("hello");
break;
}
case 1: {
System.out.println("world");
break;
}
}
}
}
jad実行の結果と同様にパラメータが
--decodestringswitch
は、switchがstringをサポートする詳細を復号することを示す.--decodeenumswitch
、--decodefinally
、--decodelambdas
などである.--decodelambdas
は、lambda式を逆コンパイルすることができる.java -jar cfr_0_125.jar --help
では、どのcfr
パラメータがあるかを知ることができますが、ここでは説明しません.CFR 0_129
--aexagg (boolean)
--aggressivesizethreshold (int >= 0) default: 15000
--allowcorrecting (boolean) default: true
--analyseas (One of [JAR, WAR, CLASS])
--arrayiter (boolean) default: true if class file from version 49.0 (Java 5) or greater
--caseinsensitivefs (boolean) default: false
--clobber (boolean)
--collectioniter (boolean) default: true if class file from version 49.0 (Java 5) or greater
--commentmonitors (boolean) default: false
--comments (boolean) default: true
--decodeenumswitch (boolean) default: true if class file from version 49.0 (Java 5) or greater
--decodefinally (boolean) default: true
--decodelambdas (boolean) default: true if class file from version 52.0 (Java 8) or greater
--decodestringswitch (boolean) default: true if class file from version 51.0 (Java 7) or greater
--dumpclasspath (boolean) default: false
--eclipse (boolean) default: true
--elidescala (boolean) default: false
--extraclasspath (string)
--forcecondpropagate (boolean)
--forceexceptionprune (boolean)
--forcereturningifs (boolean)
--forcetopsort (boolean)
--forcetopsortaggress (boolean)
--forloopaggcapture (boolean)
--hidebridgemethods (boolean) default: true
--hidelangimports (boolean) default: true
--hidelongstrings (boolean) default: false
--hideutf (boolean) default: true
--ignoreexceptions (boolean) default: false
--innerclasses (boolean) default: true
--j14classobj (boolean) default: false if class file from version 49.0 (Java 5) or greater
--jarfilter (string)
--labelledblocks (boolean) default: true
--lenient (boolean) default: false
--liftconstructorinit (boolean) default: true
--outputdir (string)
--outputpath (string)
--override (boolean) default: true if class file from version 50.0 (Java 6) or greater
--pullcodecase (boolean) default: false
--recover (boolean) default: true
--recovertypeclash (boolean)
--recovertypehints (boolean)
--relinkconststring (boolean) default: true
--removebadgenerics (boolean) default: true
--removeboilerplate (boolean) default: true
--removedeadmethods (boolean) default: true
--removeinnerclasssynthetics (boolean) default: true
--rename (boolean) default: false
--renamedupmembers
--renameenumidents
--renameillegalidents
--renamesmallmembers (int >= 0) default: 0
--showinferrable (boolean) default: false if class file from version 51.0 (Java 7) or greater
--showops (int >= 0) default: 0
--showversion (boolean) default: true
--silent (boolean) default: false
--stringbuffer (boolean) default: false if class file from version 49.0 (Java 5) or greater
--stringbuilder (boolean) default: true if class file from version 49.0 (Java 5) or greater
--sugarasserts (boolean) default: true
--sugarboxing (boolean) default: true
--sugarenums (boolean) default: true if class file from version 49.0 (Java 5) or greater
--tidymonitors (boolean) default: true
--tryresources (boolean) default: true if class file from version 51.0 (Java 7) or greater
--usenametable (boolean) default: true
--help (string)
JD-GUI
JD-GUIはC++で開発されたJava逆コンパイルツールで、Pavel Kouznetsovが開発し、Windows、Linux、アップルMac Osの3つのプラットフォームをサポートしています.また、Eclipseプラットフォームの下にあるプラグインJD-Eclipseも提供されています.JD-GUIはGPLv 3オープンソースプロトコルに基づいて、個人用には完全に無料です.JD-GUIは主に可視化操作を提供し、直接ファイルをウィンドウにドラッグすることができ、効果図は以下の通りである.
興味があればhttp://jd.benow.ca/GUIおよびidea、eclipseの逆コンパイルプラグインをダウンロードします.
JD-GUIの使用も非常に便利で、jarパッケージやclassファイルをJD-GUIインタフェースにドラッグしたり開いたりすれば逆コンパイルが完了するので、ここでは説明を思い出しません.
参考感謝:
https://blog.csdn.net/u011479200/article/details/80019827
https://blog.csdn.net/dongnan591172113/article/details/51832628
http://jd.benow.ca/