逆コンパイルが必要になる場面

実際の現場で「ソースコードが手に入らない Java バイナリ」に向き合う機会は思いのほか多い。 主なシナリオを整理すると次のとおりだ。

ライブラリ調査
公開 JAR のソースが Maven Central にない、またはソース JAR のバージョンが合わない場合に実装を直接確認する。
レガシー移行
ソースリポジトリが消滅したレガシーシステムを Java や別言語に移行する際の解析起点として使う。
バグ調査・パッチ
サードパーティ製 JAR にバグが発見されたがベンダー対応が遅い場合に、動作を確認してワークアラウンドを探す。
教育・学習
Java 標準ライブラリや有名 OSS の実装を手元で読んで理解を深める。

逆コンパイル自体は技術的に可能だが、法的・倫理的に許容されるかは状況次第である。 作業を始める前に以下の 3 点を必ず確認してほしい。

⚠️ ライセンス条項の確認

多くの商用ソフトウェアのライセンスには 「逆コンパイル・リバースエンジニアリング禁止」 の条項が含まれている。 違反すると契約違反・著作権侵害となる可能性がある。対象バイナリのライセンス(EULA / OSSライセンス)を必ず先に読むこと。

状況逆コンパイルの可否注意事項
自社で開発・所有するバイナリ ✅ 問題なし ソース管理が目的であれば当然許容
MIT / Apache / GPL などの OSS ✅ 基本的に許容 ライセンスに逆コンパイル禁止条項がないか確認
商用ライブラリ(EULA あり) ⚠️ 要確認 禁止条項が多い。デバッグ目的のみ許容するケースも
他社の業務システム ❌ 基本的に不可 著作権法・不正競争防止法に抵触する可能性が高い

💡 EU ソフトウェア指令 / 日本著作権法について

EU のソフトウェア指令(2009/24/EC)は 相互運用性確保を目的とした逆コンパイル を限定的に認めている。 日本の著作権法でも「プログラムの著作物に係る登録の特例」があり、一定条件下での複製・変換は許容される場合がある。 ただし法的判断は専門家に確認すること。

前提知識 ①:.class ファイルとバイトコード

Java のソースコード(.java)は javac でコンパイルされ、.class ファイル(バイトコード)になる。 .class は CPU 命令ではなく JVM(Java Virtual Machine)が実行できる中間コードであり、プラットフォーム非依存となっている。

バイトコードは C/C++ のネイティブバイナリと異なり、元のソースに近い情報を多く残している。 クラス名・メソッド名・フィールド名・型情報はほぼそのまま埋め込まれているため、逆コンパイルツールが高精度な復元を行える。

概念図 — Java コンパイルの流れ
Hello.java  ──[javac]──▶  Hello.class(バイトコード)
                                    │
                          ┌─────────▼─────────┐
                          │  JVM(実行環境)    │
                          │  Windows / Mac / Linux │
                          └───────────────────┘

逆コンパイラ(CFR / jadx 等)
Hello.class  ──[decompile]──▶  Hello.java(復元ソース)

注意点として、コンパイラの最適化によってソースと完全に一致しないコードが生成される場合がある。 変数名はデバッグ情報(-g オプション)が含まれていれば復元されるが、リリースビルドでは短縮名になっていることも多い。

.class ファイルの構造(概要)

セクション内容
Magic Number0xCAFEBABE — Java クラスファイルの識別子
バージョン情報コンパイルに使用した Java バージョン(major / minor version)
定数プールクラス名・メソッド名・文字列リテラルなどの定数テーブル
アクセスフラグpublic / abstract / interface など
フィールド情報型・名前・アクセス修飾子
メソッド情報シグネチャ・バイトコード命令列(Code 属性)
属性デバッグ情報(LineNumberTable・LocalVariableTable)など

前提知識 ②:JAR・WAR の内部構造

JAR(Java ARchive)も WAR(Web ARchive)も、実態は ZIP アーカイブである。 拡張子を .zip に変えて解凍ツールで開けばそのまま中身が確認できる。

JAR の構造

JAR 内部構造
myapp.jar
├── META-INF/
│   ├── MANIFEST.MF          ← メインクラス指定・バージョン情報
│   └── services/            ← ServiceLoader の設定(オプション)
├── com/
│   └── example/
│       ├── Main.class        ← 逆コンパイル対象
│       ├── Util.class
│       └── Util$Inner.class  ← 内部クラス($ で区切られる)
└── resources/
    └── config.properties

WAR の構造

WAR 内部構造
myapp.war
├── WEB-INF/
│   ├── web.xml               ← サーブレット設定
│   ├── classes/              ← ここに .class ファイルが格納される
│   │   └── com/example/
│   │       ├── HelloServlet.class
│   │       └── Service.class
│   └── lib/                  ← 依存ライブラリ JAR(ここも逆コンパイル可能)
│       ├── spring-core-6.0.jar
│       └── jackson-databind-2.15.jar
├── META-INF/
│   └── MANIFEST.MF
└── static/                   ← HTML / CSS / JS(そのまま読める)

WAR を解凍して確認する方法

WAR の中身を手軽に確認するには、ファイルを .zip にリネームして解凍するか、 jar tf myapp.war コマンドで一覧表示するだけでよい。 WEB-INF/classes/ 以下が自前コードで、WEB-INF/lib/ 以下が依存ライブラリだ。

逆コンパイルの限界を知る

逆コンパイルは万能ではない。事前に限界を把握しておくことでトラブルを防げる。

状況影響対処
コンパイラ最適化 元のロジックと異なる構造で復元される場合がある 複数ツールで比較・バイトコードを直接確認
デバッグ情報なし 変数名が var1 / param0 などになる コンテキストから意味を推測する
ProGuard 等で難読化 クラス名・メソッド名が a / b などに置換される PART 06 で詳説。完全復元は不可能なケースもある
ラムダ / invokedynamic ツールによって展開形式が異なり可読性が落ちる Procyon または jadx が比較的得意
コンパイル非互換バージョン 新しい Java バージョンのクラスを古いツールで読めない ツールを最新版にアップデートする

このシリーズの進め方

全 8 回の構成は以下のとおり。読者の目的に応じて途中から読み始めても問題ない。

PART内容目的別おすすめ
01(本記事)はじめに・前提知識全員
02ツール選定ガイド全員
03.class 単体の逆コンパイル初心者・基礎確認
04JAR から一括抽出ライブラリ解析
05WAR から抽出Web システム移行
06難読化コードへの対処レガシー移行・バグ調査
07IDE 連携日常的なデバッグ・読解
08まとめ・ツール選定フロー全員(最後に確認)

次の PART では…

PART 02 では CFR・Fernflower・Procyon・jadx の 4 ツールを精度・速度・使いやすさで比較し、どの場面でどのツールを選ぶべきかを解説する。

→ PART 02 — ツール選定ガイドへ