Java反编译工具
反编译工具
javap 反编译出来的并不是我们熟知的java代码,只有特殊需要的时候才用它
jad 很久不更新了,没办法反编译JDK8的lambda表达式
cfr 语法稍复杂点,但是可以用,今天来学习使用cfr
cfr(cfr-0.151.jar)
下载地址 http://www.benf.org/other/cfr/
使用命令 java -jar cfr-0.151.jar --help
获取帮助文档
使用命令java -jar cfr-0.151.jar --help sugarboxing
查看命令的详细信息
参数一览
java -jar cfr-0.151.jar --help
CFR 0.151
--aexagg (boolean)
--aexagg2 (boolean)
--aggressivedocopy (int >= 0) default: 0
--aggressivedoextension (boolean)
--aggressiveduff (boolean)
--aggressivesizethreshold (int >= 0) default: 15000
--allowcorrecting (boolean) default: true
--allowmalformedswitch (boolean)
--analyseas (One of [DETECT, JAR, WAR, CLASS])
--antiobf (boolean) default: false
--arrayiter (boolean) default: true if class file from version 49.0 (Java 5) or greater
--caseinsensitivefs (boolean) default: true
--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
--constobf (boolean) default: Value of option 'antiobf'
--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)
--forbidanonymousclasses (boolean) default: false
--forbidmethodscopedclasses (boolean) default: false
--forceclassfilever (string, specifying either java version as 'j6', 'j1.0', or classfile as '56', '56.65535')
--forcecondpropagate (boolean)
--forceexceptionprune (boolean)
--forcereturningifs (boolean)
--forcetopsort (boolean)
--forcetopsortaggress (boolean)
--forcetopsortnopull (boolean)
--forloopaggcapture (boolean)
--hidebridgemethods (boolean) default: Value of option 'obfattr'
--hidelangimports (boolean) default: true
--hidelongstrings (boolean) default: false
--hideutf (boolean) default: true
--ignoreexceptions (boolean) default: false
--ignoreexceptionsalways (boolean) default: false
--importfilter (string)
--innerclasses (boolean) default: true
--instanceofpattern (boolean) default: true if class file from version 58.0 (Java 14) or greater, or experimental in 58.0 (Java 14)
--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
--lomem (boolean) default: false
--methodname (string)
--obfattr (boolean) default: Value of option 'antiobf'
--obfcontrol (boolean) default: Value of option 'antiobf'
--obfuscationpath (string)
--outputdir (string)
--outputpath (string)
--override (boolean) default: true if class file from version 50.0 (Java 6) or greater
--previewfeatures (boolean) default: true
--pullcodecase (boolean) default: false
--recordtypes (boolean) default: true if class file from version 58.0 (Java 14) or greater, or experimental in 58.0 (Java 14)
--recover (boolean) default: true
--recovertypeclash (boolean)
--recovertypehints (boolean)
--reducecondscope (boolean)
--relinkconststring (boolean) default: true
--removebadgenerics (boolean) default: true
--removeboilerplate (boolean) default: true
--removedeadconditionals (boolean)
--removedeadmethods (boolean) default: true
--removeinnerclasssynthetics (boolean) default: true
--rename (boolean) default: false
--renamedupmembers (boolean) default: Value of option 'rename'
--renameenumidents (boolean) default: Value of option 'rename'
--renameillegalidents (boolean) default: Value of option 'rename'
--renamesmallmembers (int >= 0) default: 0
--showinferrable (boolean) default: false if class file from version 51.0 (Java 7) or greater
--showversion (boolean) default: true
--silent (boolean) default: false
--skipbatchinnerclasses (boolean) default: true
--staticinitreturn (boolean) default: true
--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
--stringconcat (boolean) default: true if class file from version 53.0 (Java 9) 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
--switchexpression (boolean) default: true if class file from version 57.0 (Java 13) or greater, or experimental in 56.0 (Java 12)
--tidymonitors (boolean) default: true
--trackbytecodeloc (boolean) default: false
--tryresources (boolean) default: true if class file from version 51.0 (Java 7) or greater
--usenametable (boolean) default: true
--usesignatures (boolean) default: true
--help (string)
Please specify '--help optionname' for specifics, eg
--help pullcodecase
常用的参数
–decodeenumswitch
(boolean) default: true if class file from version 49.0 (Java 5) or greater
public class Cfr {
public void testEnumSwitch(CfrEnum p) {
switch (p) {
case AAA:
System.out.println("print AAA");
break;
case BBB:
System.out.println("print BBB");
break;
case CCC:
System.out.println("print CCC");
break;
default:
System.out.println("print nothing");
break;
}
}
}
接下来,我们使用命令 java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class
进行反编译
E:\>java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class
/*
* Decompiled with CFR 0.151.
*/
public class Cfr {
public void testEnumSwitch(CfrEnum p) {
switch (p) {
case AAA: {
System.out.println("print AAA");
break;
}
case BBB: {
System.out.println("print BBB");
break;
}
case CCC: {
System.out.println("print CCC");
break;
}
default: {
System.out.println("print nothing");
}
}
}
}
我们使用命令 java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class --decodeenumswitch false
再试一下
E:\>java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class --decodeenumswitch false
/*
* Decompiled with CFR 0.151.
*/
public class Cfr {
public void testEnumSwitch(CfrEnum p) {
switch (1.$SwitchMap$CfrEnum[p.ordinal()]) {
case 1: {
System.out.println("print AAA");
break;
}
case 2: {
System.out.println("print BBB");
break;
}
case 3: {
System.out.println("print CCC");
break;
}
default: {
System.out.println("print nothing");
}
}
}
}
这时候会发现,switch中的枚举不见了,变成数字 1、2、3,这就是java中的语法糖
- 后续涉及到语法糖的参数将不再用代码举例,详细情况可以参考 《Java语法糖》
–decodelambdas
(boolean) default: true if class file from version 52.0 (Java 8) or greater
解 JDK8的lambda语法糖
–decodestringswitch
(boolean) default: true if class file from version 51.0 (Java 7) or greater
解 string-switch语法糖
–innerclasses
(boolean) default: true
示例代码
public class Cfr {
public void outMethod() {
}
class InnerCfr {
public void innerMethod() {
}
}
}
编译后我们将得到 Cfr.class 和 Cfr$InnerCfr.class两个.class文件
接下来,我们使用命令 java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class
进行反编译
java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class
/*
* Decompiled with CFR 0.151.
*/
public class Cfr {
public void outMethod() {
}
class InnerCfr {
InnerCfr() {
}
public void innerMethod() {
}
}
}
默认执行的–innerclasses的值为true,所以我能将得到内部类及内部方法,接下来将参数值改成false
E:\>java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class --innerclasses false
/*
* Decompiled with CFR 0.151.
*/
public class Cfr {
public void outMethod() {
}
}
E:\>java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr$InnerCfr.class --innerclasses false
/*
* Decompiled with CFR 0.151.
*/
class Cfr.InnerCfr {
Cfr.InnerCfr() {
}
public void innerMethod() {
}
}
不论是Cfr.clas还是Cfr$InnerCfr.class,我们都只得到当前反编译的类
–stringbuffer
(boolean) default: false if class file from version 49.0 (Java 5) or greater
java 1.5 之后被放弃了,用stringbuilder代替
–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
解枚举语法糖
常见用法
反编译单个文件
java -jar cfr的jar包路径 .class的路径
java -jar cfr-0.151.jar workspace/test/out/production/test/Cfr.class
反编译多个文件
java -jar cfr的jar包路径 第1个 .class的路径 第2个 .class的路径
java -jar cfr-0.151.jar workspace/test/out/production/test/Sugar.class workspace/test/out/production/test/SugarEnum.class
反编译jar包
java -jar cfr的jar包路径 java包的路径 --outputdir 反编译后的文件输出地址
java -jar cfr-0.151.jar E:/demo.jar --outputdir E:/cfrSource
参考资料
https://www.hollischuang.com/archives/58
http://www.benf.org/other/cfr/