Fernflower
Fernflower 是 JetBrains 开发的分析型 Java 反编译器,内置于 IntelliJ IDEA。它将 .class 字节码还原为可读的 Java 源码,是目前还原质量最高的开源 Java 反编译器之一。
反编译流程
.class 字节码
│
▼ 字节码解析(结构分析)
指令序列 + 常量池
│
▼ 控制流重建(基于 CFG) ← 参见 [[cfg|CFG]]
结构化控制流(if/while/for/switch)
│
▼ 数据流分析
变量类型推断、表达式合并
│
▼ 去糖还原
还原 lambda、try-with-resources、增强 for 等
│
▼ 源码生成
.java 文件
Fernflower 属于结构化反编译器(Structuring Decompiler),核心难点在于从非结构化的字节码跳转重建出结构化的控制流(if/else/loop)。
命令行使用
Fernflower 以 JAR 形式发布,可独立运行:
# 从 IDEA 安装目录找到 fernflower.jar
# Linux/Mac: $IDEA_HOME/plugins/java-decompiler/lib/java-decompiler.jar
# Windows: %IDEA_HOME%\plugins\java-decompiler\lib\java-decompiler.jar
# 反编译单个 class 文件,输出到 out/ 目录
java -jar fernflower.jar Hello.class out/
# 反编译整个 jar 包(输出同样为 jar,内含 .java 源文件)
java -jar fernflower.jar app.jar out/
# 指定多个来源
java -jar fernflower.jar Foo.class Bar.class out/常用选项
选项以 -key=value 形式传入,放在源文件路径之前:
| 选项 | 默认 | 说明 |
|---|---|---|
-hes=1 | 1 | 隐藏空的 super 调用 |
-hdc=1 | 1 | 隐藏默认构造器 |
-dgs=0 | 0 | 去糖 String switch(转为等价 if-else) |
-nls=0 | 0 | 统一换行符(0=系统,1=\n) |
-den=1 | 1 | 去糖枚举 |
-rbr=1 | 1 | 移除空的 try-catch 块 |
-bsm=1 | 1 | 反编译 bootstrap 方法(lambda) |
-udv=1 | 1 | 还原调试变量名(需 .class 含调试信息) |
-rer=1 | 1 | 还原 record 类 |
-log=INFO | INFO | 日志级别(TRACE/INFO/WARN/ERROR) |
# 示例:禁止隐藏默认构造器,开启 String switch 去糖
java -jar fernflower.jar -hdc=0 -dgs=1 app.jar out/在 IntelliJ IDEA 中使用
IDEA 已内置 Fernflower,无需手动调用:
- 在项目/依赖中打开任意
.class文件 - IDEA 自动调用 Fernflower 并展示反编译结果
- 右键 → Decompile to source 可保存为
.java
若
.class编译时带有-g调试信息(参见 javac),还原的变量名会更接近原始代码。
局限性
| 场景 | 说明 |
|---|---|
| 混淆代码 | 变量/方法名已被替换为无意义字符,结构可还原但语义难懂 |
| 复杂控制流 | 深层嵌套或 goto 密集的字节码可能还原为 goto 语句 |
| 运行时生成类 | 动态生成的类(如 CGLIB 代理)结构混乱,可读性差 |
| 版本差异 | 高版本字节码特性(如 sealed class)在旧版 Fernflower 中支持有限 |
与其他反编译器对比
| 工具 | 优势 | 劣势 |
|---|---|---|
| Fernflower | 还原质量高、支持新语法 | 速度稍慢 |
| CFR | 速度快、命令行友好 | 部分语法还原不如 Fernflower |
| Procyon | 早期还原质量好 | 更新较少 |
| JAD | 老工具,速度快 | 不支持 Java 5+ 新特性 |