1. Jadx
jadx是个反编译神器,集apktool、jd功能于一身,能直接查看apk,dex,jar文件。目前还不支持查看aar文件。
如果要查看aar文件的话,可以先重命名为zip文件,再解压查看。
下面介绍下如何使用jadx将编译后的class文件转换为java源码文件:
-
把class文件所属的jar包通过jadx方式打开
-
点击菜单中的File –>Save all(或者使用快捷键Ctrl+S)
-
输入保存路径,点击Select
4.查看生成的java文件
附:jadx下载地址
2. Fernflower
fernflowser也是一个开源的反编译工具项目,Android Studio内置的反编译工具就是它。
fernflower没有图形界面,主要是通过命令行的方式进行操作。
下面介绍下如何使用fernflower将编译后的class文件转换为java源码文件:
-
下载fernflower的jar包文件
http://files.minecraftforge.net/maven/net/minecraftforge/fernflower/ -
将需要反编译的jar包文件用压缩工具解压
-
通过命令行输出反编译输出java文件
java -jar fernflower.jar -dgs=1 svg2vector-applet-1.0.0 .
fernflower其他具体使用方式可参考: https://github.com/fesh0r/fernflower
3、jad工具
命令:jad -o -r -s java -d src classes/**/*.class
就能在根目录下发现是src的文件夹,里面都是反编译后的java源文件。
jad命令的参数含义如下:
-o:覆盖旧文件,而且不用提示确认。
-r:重新加载生成包结构。
-s (java):定义输出文件的扩展名。jad为默认扩展名,我们反编译后当然是要.java源文件了。
-d:输出文件的目录。src表示反编译后的所有文件都放在src目录下。
classes/**/*.class:classes是需要反编译的文件夹的名字,整个表示classes目录下的所有class文件。你也可以写成这样**/*.class,这表示当前目录及其子目录下所有的class文件(包含所有的子目录)。
.jad -o -8 -r -dXXXXX -sjava XXXXX
-o: 覆盖写,如果文件已经存在,则覆盖
-r: 建立和java包一致的文件夹路径
-dXXXX: 反编译后保存路径,如 D:/output/src
-sjava: 反编译后的文件后缀名,我们希望是.java文件
-8: 避免反编译时将中文编译为unicode,必不可少。
注意:路径中不要有中文,否则会出现错误,JavaClassFileReadException: can’t open input file on `D:\XXXXXX’
注意:会丢失注解 ,比如@XmlAttribute,@Autowired等等,全部缺失。表示很无赖
补充:
使用方法:
[1] 反编译一个class文件:jad example.class,会生成example.jad,用文本编辑器打开就是java源代码
[2] 指定生成源代码的后缀名:jad -sjava example.class,生成example.java
[3] 改变生成的源代码的名称,可以先使用-p将反编译后的源代码输出到控制台窗口,然后使用重定向,输出到文件:jad -p example.class > myexample.java
[4] 把源代码文件输出到指定的目录:jad -dnewdir -sjava example.class,在newdir目录下生成example.java
[5] 把packages目录下的class文件全部反编译:jad -sjava packages/*.class
[6] 把packages目录以及子目录下的文件全部反编译:jad -sjava packages/**/*.class,不过你仍然会发现所有的源代码文件被放到了同一个文件中,没有按照class文件的包路径建立起路径
[7] 把packages目录以及子目录下的文件全部反编译并建立和java包一致的文件夹路径,可以使用-r命令:jad -r -sjava packages/**/*.class
[8] 当重复使用命令反编译时,Jad会提示“whether you want to overwrite it or not”,使用-o可以强制覆盖旧文件
最权威的还是help:
bin>jad
Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov (jad@kpdus.com).
Usage: jad [option(s)] <filename(s)>
Options: -a – generate JVM instructions as comments (annotate)
-af – output fully qualified names when annotating
-b – generate redundant braces (braces)
-clear – clear all prefixes, including the default ones
-d <dir> – directory for output files
-dead – try to decompile dead parts of code (if there are any)
-dis – disassembler only (disassembler)
-f – generate fully qualified names (fullnames)
-ff – output fields before methods (fieldsfirst)
-i – print default initializers for fields (definits)
-l<num> – split strings into pieces of max <num> chars (splitstr)
-lnc – output original line numbers as comments (lnc)
-lradix<num>- display long integers using the specified radix
-nl – split strings on newline characters (splitstr)
-noconv – don’t convert Java identifiers into valid ones (noconv)
-nocast – don’t generate auxiliary casts
-noclass – don’t convert .class operators
-nocode – don’t generate the source code for methods
-noctor – suppress the empty constructors
-nodos – turn off check for class files written in DOS mode
-nofd – don’t disambiguate fields with the same names (nofldis)
-noinner – turn off the support of inner classes
-nolvt – ignore Local Variable Table entries (nolvt)
-nonlb – don’t insert a newline before opening brace (nonlb)
-o – overwrite output files without confirmation
-p – send all output to STDOUT (for piping)
-pa <pfx>- prefix for all packages in generated source files
-pc <pfx>- prefix for classes with numerical names (default: _cls)
-pe <pfx>- prefix for unused exception names (default: _ex)
-pf <pfx>- prefix for fields with numerical names (default: _fld)
-pi<num> – pack imports into one line using .* (packimports)
-pl <pfx>- prefix for locals with numerical names (default: _lcl)
-pm <pfx>- prefix for methods with numerical names (default: _mth)
-pp <pfx>- prefix for method parms with numerical names (default:_prm)
-pv<num> – pack fields with the same types into one line (packfields)
-r – restore package directory structure
-radix<num>- display integers using the specified radix (8, 10, or 16)
-s <ext> – output file extension (default: .jad)
-safe – generate additional casts to disambiguate methods/fields
-space – output space between keyword (if, while, etc) and expression
-stat – show the total number of processed classes/methods/fields
-t<num> – use <num> spaces for indentation (default: 4)
-t – use tabs instead of spaces for indentation
-v – show method names while decompiling
-8 – convert Unicode strings into ANSI strings (ansi)
-& – redirect STDERR to STDOUT
4、在线反编译网 http://javare.cn/
5、JDK自带的反编译工具 javap
javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。
语法:
-help --help -? 输出此用法消息
-version 版本信息,其实是当前javap所在jdk的版本信息,不是class在哪个jdk下生成的。
-v -verbose 输出附加信息(包括行号、本地变量表,反汇编等详细信息)
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类 和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示静态最终常量
-classpath <path> 指定查找用户类文件的位置
-bootclasspath <path> 覆盖引导类文件的位置
下面举一个小例子,java源代码如下:
public class JavapTest2 {
private String username;
public void say(String username) {
System.out.println("hi,"+username);
}
}
将其编译后,使用 javap来查询 JavapTest2的字节码
javac JavapTest2.java
javap -p -v JavapTest2
生成的字节码如下:
Classfile ../JavapTest2.class
Last modified 2018-8-31; size 608 bytes
MD5 checksum 25f04ad8674616cb2f0e7fe9d35e6ab1
Compiled from "JavapTest2.java"
public class com.pjmike.JVM.JavapTest2
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #10.#21 // java/lang/Object."<init>":()V
#2 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Class #24 // java/lang/StringBuilder
#4 = Methodref #3.#21 // java/lang/StringBuilder."<init>":()V
#5 = String #25 // hi,
#6 = Methodref #3.#26 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/String
Builder;
#7 = Methodref #3.#27 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#8 = Methodref #28.#29 // java/io/PrintStream.println:(Ljava/lang/String;)V
#9 = Class #30 // com/pjmike/JVM/JavapTest2
#10 = Class #31 // java/lang/Object
#11 = Utf8 username
#12 = Utf8 Ljava/lang/String;
#13 = Utf8 <init>
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 say
#18 = Utf8 (Ljava/lang/String;)V
#19 = Utf8 SourceFile
#20 = Utf8 JavapTest2.java
#21 = NameAndType #13:#14 // "<init>":()V
#22 = Class #32 // java/lang/System
#23 = NameAndType #33:#34 // out:Ljava/io/PrintStream;
#24 = Utf8 java/lang/StringBuilder
#25 = Utf8 hi,
#26 = NameAndType #35:#36 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#27 = NameAndType #37:#38 // toString:()Ljava/lang/String;
#28 = Class #39 // java/io/PrintStream
#29 = NameAndType #40:#18 // println:(Ljava/lang/String;)V
#30 = Utf8 com/pjmike/JVM/JavapTest2
#31 = Utf8 java/lang/Object
#32 = Utf8 java/lang/System
#33 = Utf8 out
#34 = Utf8 Ljava/io/PrintStream;
#35 = Utf8 append
#36 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#37 = Utf8 toString
#38 = Utf8 ()Ljava/lang/String;
#39 = Utf8 java/io/PrintStream
#40 = Utf8 println
{
private java.lang.String username;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE
public com.pjmike.JVM.JavapTest2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 7: 0
public void say(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String hi,
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/
lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/
lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 11: 0
line 12: 25
}
SourceFile: "JavapTest2.java"
默认情况下 javap 会打印所有非私有的字段和方法,如下:
javap JavapTest2
Compiled from "JavapTest2.java"
public class com.pjmike.JVM.JavapTest2 {
public com.pjmike.JVM.JavapTest2();
public void say(java.lang.String);
}
javap -v -p JavapTest2
。
加了 -p 选项后,还会打印私有的字段和方法,加上 -v 选项后,它会尽可能地打印出所有信息,如果只需要查询相关方法对应的字节码,可以使用 -c 代替 -v,代码如下:
Compiled from "JavapTest2.java"
public class com.pjmike.JVM.JavapTest2 {
private java.lang.String username;
public com.pjmike.JVM.JavapTest2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void say(java.lang.String);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String hi,
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/la
ng/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/la
ng/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
}
6、借助idea、eclipse工具
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13990.html