概述:
CFR(Class File Reader) 可以支持 Java 9、Java 12、Java 14 以及其他的最新版 Java 代码的反编译工作。而且 CFR 本身的代码是由 Java 6 编写,所以基本可以使用 CFR 在任何版本的 Java 程序中。值得一提的是,使用 CFR 甚至可以将使用其他语言编写的的 JVM 类文件反编译回 Java 文件。
demo :
Main.main(new String[] {
clazzPath,
"--outputdir",
SystemInfo.WORK_SPACE
});
反编译Class文件
详情请看:CrfUtils
反编译lamdba 一
public class ExeLamdab {
public void run(LamdbaInterface<String, String> lamdbaInterface) throws UnmodifiableClassException {
String world = lamdbaInterface.invote("world");
final Class[] allLoadedClasses = InstrumentationUtil.INSTANCE().getAllLoadedClasses();
//输出字节码文件
ClassFileTransformer extractor = new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> cls, ProtectionDomain pd, byte[] classBytes) {
if (null != classBytes) {
try {
File tmpFile = new File(SystemInfo.WORK_SPACE + File.separator + className.replace('.', '/') + ".class");
if (!tmpFile.exists()) {
String parent = tmpFile.getParent();
File file = new File(parent);
if (!file.exists()) {
file.mkdirs();
}
tmpFile.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
fileOutputStream.write(classBytes);
fileOutputStream.flush();
String clazzName = className.replaceAll("/", ".");
System.out.println(String.format("[FRIDAY] dump class: %s -> %s", clazzName, tmpFile.getAbsolutePath()));
} catch (Throwable e) {
System.out.println(String.format("[FRIDAY] dump class: %s error %s", className, e.getMessage()));
}
}
return classBytes;
}
};
//添加transformer
InstrumentationUtil.INSTANCE().addTransformer(extractor, true);
for (Class clazz : allLoadedClasses) {
if(clazz.getName().equals(lamdbaInterface.getClass().getName())){
InstrumentationUtil.INSTANCE().retransformClasses(clazz);
}
}
}
}
java -jar cfr.jar --help
org.benf.cfr.reader.util.getopt.OptionsImpl
选项 | 描述 | (类型)默认值 |
---|---|---|
--aexagg | (boolean) | |
--aexagg2 | (boolean) | |
--aggressivedocopy | (int >= 0) default: 0 | |
--aggressivedoextension | (boolean) | |
--aggressiveduff | (boolean) | |
--aggressivesizethreshold | 通过积极应用语义安全但有破坏性的转换例如删除忽略的存储 来简化静态分配分析,从而更好地处理巨大的代码块 | (int >= 0) default: 13000 |
--allowcorrecting | (boolean) default: true | |
--allowmalformedswitch | (boolean) | |
--analyseas | (One of [DETECT, JAR, WAR, CLASS]) | |
--antiobf | 处理基本整数例如 /0 控制流混淆 | (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 | 不反编译出增强 for 循环的语法糖实现 | (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 | 不反编译出switch-on-enum的语法糖实现 | (boolean) default: true if class file from version 49.0 (Java 5) or greater |
--decodefinally | 不反编译出finally的语法糖实现 | (boolean) default: true |
--decodelambdas | 不反编译出lambda的语法糖实现 | (boolean) default: true if class file from version 52.0 (Java 8) or greater |
--decodestringswitch | 不反编译出switch-on-string的语法糖实现 | (boolean) default: true if class file from version 51.0 (Java 7) or greater |
--dumpclasspath | Dump class path for debugging purposes | (boolean) default: false |
--eclipse | 允许禁用规范化 eclipse 输出的转换 | (boolean) default: true |
--elidescala | 通过删除 serialVersionUID 和 ScalaSignature 可能对其他语言有帮助 使阅读反编译的 scala 更容易 | (boolean) default: false |
--extraclasspath | 允许搜索 helper jar 进行分析 | (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 | 当代码看起来不正确时添加了一种激进的拓扑排序,改进了 dex2jar 输出 | (boolean) |
--forcetopsortaggress | (boolean) | |
--forcetopsortnopull | (boolean) | |
--forloopaggcapture | 允许循环捕获多个更新 | (boolean) |
--hidebridgemethods | (boolean) default: Value of option ‘obfattr’ | |
--hidelangimports | 隐藏 java.lang 导入 | (boolean) default: true |
--hidelongstrings | (boolean) default: false | |
--hideutf | 解码 unicode 文字 Hide UTF8 characters - quote them instead of showing the raw characters | (boolean) default: true |
--ignoreexceptions | 忽略异常当异常表非常混乱以至于无法检索到任何有意义的内容时,这很有用 | (boolean) default: false |
--ignoreexceptionsalways | (boolean) default: false | |
--importfilter | (string) | |
--innerclasses | 反编译内部类 | (boolean) default: true |
--instanceofpattern | 反编译instanceof 模板 | (boolean) default: true if class file from version 60.0 (Java 16) or greater, or experimental in 58.0 (Java 14), 59.0 (Java 15) |
--j14classobj | 不反编译出类常量的初始化 | (boolean) default: false if class file from version 49.0 (Java 5) or greater |
--jarfilter | 允许 jar 处理采用正则表达式提取哪些类 | (string) |
--labelledblocks | (boolean) default: true | |
--lenient | 允许对奇怪排序的异常处理程序进行排序 | (boolean) default: false |
--liftconstructorinit | 不反编译出类变量的初始化 | (boolean) default: true |
--lomem | (boolean) default: false | |
--methodname | Name of method to analyse | (string) |
--obfattr | (boolean) default: Value of option ‘antiobf’ | |
--obfcontrol | (boolean) default: Value of option ‘antiobf’ | |
--obfuscationpath | 支持反混淆映射文件 | (string) |
--outputdir | Decompile to files in [directory] (= options 'outputpath' + 'clobber') (historic compatibility) | (string) |
--outputencoding | (string) | |
--outputpath | (string) | |
--override | 生成 @Override 注释 | (boolean) default: true if class file from version 50.0 (Java 6) or greater |
--previewfeatures | (boolean) default: true | |
--pullcodecase | (boolean) default: false | |
--recordtypes | 不反编译出record的语法糖实现 | (boolean) default: true if class file from version 60.0 (Java 16) or greater, or experimental in 58.0 (Java 14), 59.0 (Java 15) |
--recover | 在反编译失败的情况下停止任何使用额外选项覆盖的尝试 | (boolean) default: true |
--recovertypeclash | (boolean) | |
--recovertypehints | (boolean) | |
--reducecondscope | (boolean) | |
--relinkconst | (boolean) default: true | |
--relinkconststring | 用猜测的源静态最终替换字符串常量 | (boolean) default: Value of option ‘relinkconst’ |
--removebadgenerics | 不反编译出泛型的语法糖实现 | (boolean) default: true |
--removeboilerplate | 不反编译出序列化时 lambda的语法糖实现 | (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 | |
--sealed | 支持密封类 | (boolean) default: true if class file from version 62.0 (Java 18) or greater, or experimental in 60.0 (Java 16), 61.0 (Java 17) |
--showinferrable | (boolean) default: false if class file from version 51.0 (Java 7) or greater | |
--showversion | (boolean) default: true | |
--silent | (boolean) default: false | |
--skipbatchinnerclasses | When processing many files, skip inner classes, as they will be processed as part of outer classes anyway. If false, you will see inner classes as separate entities also. | (boolean) default: true |
--staticinitreturn | (boolean) default: true | |
--stringbuffer | 反编译出【JDK 5-】 + 的语法糖实现 | (boolean) default: false if class file from version 49.0 (Java 5) or greater |
--stringbuilder | 不反编译出【JDK 8-】 + 的语法糖实现 | (boolean) default: true if class file from version 49.0 (Java 5) or greater |
--stringconcat | 不反编译出【JDK 9+】 + 的语法糖实现 | (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 |
--sugarretrolambda | (boolean) default: false | |
--switchexpression | 反编译switch 表达式 | (boolean) default: true if class file from version 58.0 (Java 14) or greater, or experimental in 56.0 (Java 12), 57.0 (Java 13) |
--tidymonitors | (boolean) default: true | |
--trackbytecodeloc | Propagate bytecode location info. | (boolean) default: false |
--tryresources | 不反编译出try-with-resources的语法糖实现 | (boolean) default: true if class file from version 51.0 (Java 7) or greater |
--usenametable | (boolean) default: true | |
--usesignatures | (boolean) default: true | |
--version | CFR 的版本号 | (boolean) default: true |
--help | 帮助 | (string) |
参考:
github地址:github.com/leibnitz27/…
官网地址:www.benf.org/other/cfr/j…
反编译方案对比:www.wdbyte.com/2021/05/jav…