Java 字节码逆向(CFR / JD-GUI / javap)
SkillDev toolsJava 字节码逆向:CFR/JD-GUI、jar 解包、Java 加固。触发词:Java、jar、字节码、JD-GUI、CFR、class文件
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Java 字节码逆向(CFR / JD-GUI / javap) skill
What this skill tells your AI
The instructions your AI receives, as published by dslsdzc/rev-skills in .claude/skills/re-java/SKILL.md and read by ahel’s review.
何时使用 / 何时不用
- 用:jar/war/class 样本还原 Java 逻辑;定位注册码/密钥/网络逻辑;处理 ProGuard/Allatori 混淆与 Java 加固
- 用:恶意 Java 样本([[re-malware]] → [[re-managed]] 路径)静态还原
- 不用:Android DEX 直接分析([[re-apk]];转成 jar 后可回本技能)
- 不用:非 Java(.NET 走 [[re-dotnet]]、脚本走 [[re-script-deob]]、native 走 [[re-binary-core]])
- 注意:动态步骤默认沙箱([[re-analyze/platform-tips]] 最高原则);解包产物先备份
工具准备
参考 [[re-analyze/platform-tips]]——反编译/解包为静态步骤,免沙箱;动态验证按最高原则进沙箱。
JDK(javap / jar / java 运行时)
- Debian/Ubuntu:
apt install openjdk-17-jdk - Fedora:
dnf install java-17-openjdk;Arch:pacman -S jdk17-openjdk - macOS:
brew install openjdk(或brew install --cask temurin) - Windows:
choco install temurin或官方安装器 - 验证:
java -version && javap -version
unzip(jar = zip 容器)
- Linux:
apt install unzip/dnf install unzip/pacman -S unzip;macOS:brew install unzip - 验证:
unzip -v
CFR(jar CLI 反编译器,零依赖)
- 下载(无依赖,只需 JRE):
curl -L -o cfr.jar https://www.benf.org/other/cfr/cfr-0.152.jar - 验证:
java -jar cfr.jar --help
JD-GUI(GUI 反编译器)
- GitHub
java-decompiler/jd-guirelease zip → 解压,Linux/macOS:java -jar jd-gui-1.6.6.jar(zip 内含各平台可执行) - 验证: GUI 启动并能
File > Open打开 jar
procyon(备选反编译器)
- Maven Central:
curl -L -o procyon-decompiler.jar https://repo1.maven.org/maven2/org/bitbucket/mstrobel/procyon-decompiler/0.6.0/procyon-decompiler-0.6.0.jar - 验证:
java -jar procyon-decompiler.jar --help
操作步骤
按顺序执行,每步记录证据(路径 + sha256,见 [[re-triage]])。
-
jar/war 解包:
jar tf app.jar # 先看清单(JDK 自带 jar 工具) unzip -o app.jar -d unpacked/ unzip -p app.jar META-INF/MANIFEST.MF # Main-Class / 加固标记- war: 类在
WEB-INF/classes/,依赖在WEB-INF/lib/ - fat jar(Spring Boot): 类在
BOOT-INF/classes/,嵌套依赖BOOT-INF/lib/*.jar需逐个解 - aar(Android): 内含
classes.jar,解出后再按本技能处理 - Multi-Release jar: 同路径多版本类在
META-INF/versions/N/(N=9/11/17…)下覆盖——运行时按 JDK 选版加载,逆向按目标 JDK 看对应层,别只看顶层
- war: 类在
-
类结构识别:
javap -c -p unpacked/com/example/Main.class # 字节码(-c)+ 私有成员(-p) javap -v unpacked/com/example/Main.class # 常量池/元数据- 找入口:MANIFEST.MF 的
Main-Class→javap -c -p <入口类>看 main 逻辑 - 混淆程序集先看类名是否可读(a/b/c → 步骤 4)
- class 文件头速查:
xxd -l 8 <类>.class→CA FE BA BE+ minor(2) + major(2);Java 版本 = major − 44(52=Java 8、55=11、61=17、65=21,实测 JDK 21 产物 major=65);javap -v首行直接打印 minor/major - 常量池:计数在 major 之后(u16,索引 0 占位),
javap -v列条目类型(String/Class/NameAndType/Methodref/Utf8 等)——字符串字面量、类名、签名全在常量池,混淆样本的明文串先在这里找
- 找入口:MANIFEST.MF 的
-
逻辑还原(CFR / JD-GUI):
java -jar cfr.jar app.jar --outputdir cfr_out/ # 整包还原为 Java 源码 java -jar cfr.jar unpacked/com/example/Main.class # 单类还原 java -jar procyon-decompiler.jar -jar app.jar -o procyon_out/ # 备选- JD-GUI:
File > Open→ 左侧树浏览 →File > Save All Sources导出 - 关键类/方法用两个反编译器交叉验证(CFR 对 lambda/现代字节码还原更好,JD-GUI 对老代码更顺)
- JD-GUI:
-
混淆识别与字符串解密:
- ProGuard: 类/方法名全变
a/b/c、javap -l无 LineNumberTable/LocalVariableTable(调试信息被剥) - Allatori: 反编译产物出现
com.allatori.*水印类、StringEncryptor调用(字符串加密) - ZKM(Zelix KlassMaster):
com.zelix.*类特征 - 检测:
grep -rn 'StringEncryptor\|decrypt(' cfr_out/ | head - 字符串加密处理:定位解密类与算法(key/变换方式)→ python3 复刻批量还原;或动态取明文(步骤 5,沙箱内)——先静态还原,静态卡住再动态
- ProGuard: 类/方法名全变
-
动态(可选;沙箱内执行 [[re-sandbox]]):
- JDB(桌面 JVM):
jdb -classpath app.jar com.example.Main > stop in com.example.Main.checkKey # 下断点 > print key # 取变量 > eval new com.example.Util().decrypt("密文") # 直接调用解密方法取明文 - Frida(Android Java 应用,转 [[re-mobile]]/[[re-apk]] 域):
Java.perform(function () { var c = Java.use("com.example.Main"); c.checkKey.implementation = function (k) { console.log("key = " + k); return this.checkKey(k); }; }); - 桌面 JVM 无 Frida Java API → 用 JDB / 自写 Java agent
- JDB(桌面 JVM):
跨域联合
- [[re-managed]]:网关工作流步骤②(反编译)③(去混淆)固定调用本技能
- [[re-malware]]:Java 恶意样本路径(re-malware → re-managed → 本技能静态还原)
- Android 侧:[[re-apk]] / [[re-mobile]](DEX 转 jar 后可回本技能);动态 [[re-frida]](Android)
- 底座 [[re-binary-core]]:初勘([[re-triage]]);native/JNI 部分
常见坑与陷阱
- ProGuard 改名后靠字符串交叉引用:现象——反编译全是
a/b/c类、a(...)方法,无法定位目标逻辑;原因——ProGuard shrink+obfuscate 重命名抹掉语义;对策——从字符串入手:grep 明文 URL/提示语 → 在反编译产物里找引用它的类(grep -rn "提示语" cfr_out/)→ 沿调用链恢复语义 - Allatori/字符串加密需先解密:现象——反编译只见
StringEncryptor.decrypt("...")调用,看不到任何明文;原因——字符串运行时才解密;对策——静态定位解密算法与 key → python3 复刻批量还原;或动态在解密调用后取明文(JDBeval/ Frida),沙箱内执行 - 反编译不完全正确:现象——CFR/JD-GUI 输出语法错误、goto/label 混乱、try-catch 结构诡异、lambda 还原失败;原因——字节码到 Java 不存在无损还原;对策——对照
javap -c -p字节码手工修正,多反编译器交叉验证 - Java 加固(如 Virbox)类似壳需先脱:现象——JD-GUI 打开报错/空白、
javap输出损坏、文件头非标准;原因——加固器加密 class 字节码、运行时才解密(本质是壳);对策——先脱加固:运行时 dump class(attach agent / 专用脱壳工具为主;-Xbootclasspath仅 JDK 8 可用,JDK 9+ 已移除该选项)→ 对脱出的标准 class 再反编译;思路同 [[re-anti-analysis]] 的"先脱壳后分析" - javap 报 unsupported class file version:现象——
javap报major version 65之类不支持;原因——class 文件版本高于本机 JDK 工具版本;对策——按 major−44 换算目标 Java 版本,装对应或更新的 JDK;只读版本与常量池可先用xxd手工看头字段,不必等工具 - Multi-Release jar 分析错层:现象——
unzip -o解出顶层类后反编译,逻辑与运行时行为不符(版本分支消失);原因——多版本类在META-INF/versions/N/,不同 JDK 加载不同层;对策——解包后检查META-INF/versions/,按目标 JDK 选层分析;顶层与 versions 层的差异就是版本条件逻辑 - lambda 反编译出现合成方法:现象——CFR/JD-GUI 输出
lambda$xxx$n方法或invokedynamic调用;原因——lambda 体编译为合成私有方法 + invokedynamic 引导;对策——javap -v -p的 BootstrapMethods 表定位 lambda 体方法(捕获变量在合成方法参数里),按普通方法分析即可
Signals
- GitHub stars
- 57
- Forks
- 8
- Last commit
- Sep 2026
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
re-java- Source
- github.com/dslsdzc/rev-skills