逆コンパイルが必要になる場面
実際の現場で「ソースコードが手に入らない Java バイナリ」に向き合う機会は思いのほか多い。 主なシナリオを整理すると次のとおりだ。
合法性と倫理 — 必ず最初に確認すること
逆コンパイル自体は技術的に可能だが、法的・倫理的に許容されるかは状況次第である。 作業を始める前に以下の 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++ のネイティブバイナリと異なり、元のソースに近い情報を多く残している。 クラス名・メソッド名・フィールド名・型情報はほぼそのまま埋め込まれているため、逆コンパイルツールが高精度な復元を行える。
Hello.java ──[javac]──▶ Hello.class(バイトコード)
│
┌─────────▼─────────┐
│ JVM(実行環境) │
│ Windows / Mac / Linux │
└───────────────────┘
逆コンパイラ(CFR / jadx 等)
Hello.class ──[decompile]──▶ Hello.java(復元ソース)
注意点として、コンパイラの最適化によってソースと完全に一致しないコードが生成される場合がある。
変数名はデバッグ情報(-g オプション)が含まれていれば復元されるが、リリースビルドでは短縮名になっていることも多い。
.class ファイルの構造(概要)
| セクション | 内容 |
|---|---|
| Magic Number | 0xCAFEBABE — Java クラスファイルの識別子 |
| バージョン情報 | コンパイルに使用した Java バージョン(major / minor version) |
| 定数プール | クラス名・メソッド名・文字列リテラルなどの定数テーブル |
| アクセスフラグ | public / abstract / interface など |
| フィールド情報 | 型・名前・アクセス修飾子 |
| メソッド情報 | シグネチャ・バイトコード命令列(Code 属性) |
| 属性 | デバッグ情報(LineNumberTable・LocalVariableTable)など |
前提知識 ②:JAR・WAR の内部構造
JAR(Java ARchive)も WAR(Web ARchive)も、実態は ZIP アーカイブである。
拡張子を .zip に変えて解凍ツールで開けばそのまま中身が確認できる。
JAR の構造
myapp.jar
├── META-INF/
│ ├── MANIFEST.MF ← メインクラス指定・バージョン情報
│ └── services/ ← ServiceLoader の設定(オプション)
├── com/
│ └── example/
│ ├── Main.class ← 逆コンパイル対象
│ ├── Util.class
│ └── Util$Inner.class ← 内部クラス($ で区切られる)
└── resources/
└── config.properties
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 単体の逆コンパイル | 初心者・基礎確認 |
| 04 | JAR から一括抽出 | ライブラリ解析 |
| 05 | WAR から抽出 | Web システム移行 |
| 06 | 難読化コードへの対処 | レガシー移行・バグ調査 |
| 07 | IDE 連携 | 日常的なデバッグ・読解 |
| 08 | まとめ・ツール選定フロー | 全員(最後に確認) |
✅ 次の PART では…
PART 02 では CFR・Fernflower・Procyon・jadx の 4 ツールを精度・速度・使いやすさで比較し、どの場面でどのツールを選ぶべきかを解説する。