mcpField
R
re-java

re-java

github.com/dslsdzcセキュリティ20652 回インストール2 週間前に更新
リポジトリ

re-java について

JAR、WAR、classファイルを調べるためのJavaリバースエンジニアリング向けスキルです。CFR、JD-GUI、javapによるバイトコード調査と逆コンパイルに加え、難読化の確認や任意の動的検証を扱います。

主な機能

  1. 01JARとWARの展開
  2. 02javapによるクラス構造とバイトコードの確認
  3. 03CFRとJD-GUIによる逆コンパイル
  4. 04一般的な難読化と文字列暗号化の識別
  5. 05JDBによる任意の動的検証

活用シーン

  1. 01Javaサンプルのロジック復元
  2. 02登録コード、鍵、ネットワーク処理の特定
  3. 03ProGuardやAllatoriで処理されたプログラムの分析
  4. 04Javaマルウェアの静的調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dslsdzc/rev-skills --skill re-java

インストール後、Claude Code で/re-javaを入力して読み込まれたか確認します。

詳細

Java 字节码逆向(CFR / JD-GUI / javap)

何时使用 / 何时不用

  • 用: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-gui release 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]])。

  1. 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 看对应层,别只看顶层
  2. 类结构识别:

    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 等)——字符串字面量、类名、签名全在常量池,混淆样本的明文串先在这里找
  3. 逻辑还原(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 对老代码更顺)
  4. 混淆识别与字符串解密:

    • 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,沙箱内)——先静态还原,静态卡住再动态
  5. 动态(可选;沙箱内执行 [[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

跨域联合

  • [[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 による名前変更で意味情報が失われます。対策——文字列を手がかりにします。平文の URL/メッセージを grep → 逆コンパイル結果からその文字列を参照しているクラスを探す(grep -rn "提示语" cfr_out/)→ 呼び出しチェーンをたどって意味を復元します。
  • Allatori/文字列暗号化は先に復号する必要があります:症状——逆コンパイル結果に StringEncryptor.decrypt("...") の呼び出ししかなく、平文を確認できません。原因——文字列が実行時に初めて復号されます。対策——復号アルゴリズムと key を静的に特定 → python3 で再現して一括復元します。または復号呼び出しの直後に平文を取得します(JDB の eval/Frida)。サンドボックス内で実行してください。
  • 逆コンパイル結果が完全に正確とは限りません:症状——CFR/JD-GUI の出力に構文エラーがある、goto/label の構造が混乱している、try-catch の構造が不自然、lambda の復元に失敗するといった問題が発生します。原因——バイトコードから Java への変換は、完全に元どおりに復元できるものではありません。対策——javap -c -p のバイトコードと照合して手動で修正し、複数の逆コンパイラーで相互検証します。
  • Virbox などの Java 保護は、シェルと同様に先に解除する必要があります:症状——JD-GUI で開くとエラー/空白になり、javap の出力が破損している、またはファイルヘッダーが標準形式ではありません。原因——保護ツールが class バイトコードを暗号化し、実行時に初めて復号します(本質的にはシェルです)。対策——先に保護を解除します。実行時に class を dump します(主に 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 または新しい 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 本体は、合成された private メソッドと invokedynamic のブートストラップとしてコンパイルされます。対策——javap -v -p の BootstrapMethods テーブルで lambda 本体のメソッドを特定します(キャプチャされた変数は合成メソッドの引数に含まれます)。あとは通常のメソッドと同様に分析できます。

コメント