逆コンパイル

バージョン: industrialcraft-2-2.2.828-experimental

概要

逆コンパイルとは、ソースコードから実行可能コード・中間コード・別のプログラミング言語のソースコードなどを生成するコンパイルの逆の処理で、そのような生成されたコードから元となるソースコードを生成する処理である。

プログラミング言語は、基本的に機械が実際に実行するまでの間のどこかで、人間が読むための形式(通常はテキスト形式)を分析する構文解析の過程を経なければならない。構文解析後のデータをどのように扱うかは言語によって異なるが、そのまま実行したり(インタプリタ型言語)、再び構文解析を行うコストを省略するために中間コードや直接OSが実行できる実行可能コードの形で一旦保存しておいたり(コンパイル型言語)する。構文解析には付属して意味解析などのより高等な解析を行う場合もある。

現在(2017年11月)のJavaは、ソースコードをJavaバイトコードと呼ばれる中間コードにコンパイル(javacでのコンパイル)したのち、実行直前に実行可能コードにコンパイル(JITコンパイラでのコンパイル)して、それを実行させるという二度手間(機械語の解析を含めると三度手間)のコンパイル形態を持っている。このうち、JITコンパイラは当初は存在しなかった(バイトコードを解析しながら実行するインタプリタ型だった)らしいが、実行速度の面で新たに加えられた。MinecraftのMODの配布形式であるJARは、バイトコードであるclassファイルといくつかのその他のメタなファイルをZIP圧縮して拡張子を変えた奴である。どうせランタイムが必要ならソースコードの状態で配れよとか言わない。

ソースコード ――[javac]―→ バイトコード(中間コード) ――[JITコンパイラ]―→ 実行可能コード ――[CPU]―→ 実行

 .java             .class≒.jar
[人間が読める]
[============ファイルの状態で存在する============]

                                      [========機械が実行できる========]
                                      [==========OSに依存する=========]

Javaにおける逆コンパイル

Javaにおける逆コンパイルは専らJavaバイトコード(.class≒.jar)からJavaソースコード(.java)への変換であり、Javaにおける通常のコンパイル(javacおよびjar)の逆の変換を行うものである。この段階の処理は特定のOSに依存した実行ファイル(Windowsの場合は.exeファイルなど)は関与せず、そのためJavaのコンパイルおよび逆コンパイルではプログラマーはOSごとの違いを無視して作業を行うことができる。

この逆コンパイルという処理はJavaにおいては意外なほど簡単であり、Pleiades Eclipseに標準でくっついてきていたりする。そのため、Javaをコンパイルする際には基本的にソースコードが筒抜けになると考えておいた方が良い。

Minecraft(Forge)における逆コンパイル

Minecraft界隈での逆コンパイルもJavaにおける逆コンパイルと同様で、バイトコードをソースコードに変換するものである。ただし、Minecraftでは難読化というプログラムを逆コンパイルから守る処理によって、単に逆コンパイルしただけではソースコードをまともに編集できない。

プログラミングではデータを格納する変数や動作を表す関数といったものに名前を付けて利便性を高めている。このような物の名前はJavaではバイトコードの段階でも維持され、プログラマー同士が互いのプログラムを理解するのに一役買っているが、難読化はこの名前を破壊しプログラマーのやる気を削ぐことで配布物を改造や解析などから守っている。

Minecraft Forgeでは、Moddingの際に難読化済みの名前に再び意味のある名前を付けることで難読化対策をしている。そして、ユーザーの実行環境のMinecraftは難読化されているため、意味のある名前のMODのバイトコードを難読化して配布している(Modding界隈では無印(難読化あり)とdev版(難読化なし)であり、IC2Expにも存在する)。

本サイトでは、ソースコードが見当たらないJavaプログラムについてソースコードと言ったら、実際に開発者の手元にあるソースコードではなく逆コンパイルして得られたJavaソースコード(略して逆コンパイルコード)を指すものとする

Jarの逆コンパイル環境を整える

特に逆コンパイル対策がされていないJarファイルは、EclipseやJD-GUIといった様々なツールからソースコードが見れる(JD-GUIならインストールしてD&D(ドラッグアンドドロップ)で済むので初心者でも割と簡単に見れる読解できるかは謎)が、ここではfernflowerを使う。これはどうやらMinecraft Forgeでも使われているようだ。

以下ではWindows 10/PowerShell/日本語環境でのインストールについて解説する。

Fernflowerの入手

  1. OSにJava(JRE)をインストールしてPathが通っていることを確認する
    • 自前のJREを使いたい場合はそれでもいい
    • それこそMinecraftのランチャーが引っ張ってくる奴でも行ける
  2. exlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifexlink.gifhttps://github.com/JetBrains/intellij-community/tree/master/plugins/java-decompiler/engineからソースコードをZIPでダウンロードする
  3. 解凍したフォルダに入り、build.gradleのあるフォルダでコマンドラインを起動
    • フォルダをShift+右クリックからでも起動できる
  4. > .\gradlew jarと実行
    • ここについて詳しくはGradleで調べてほしい
      • ただしプログラミング初心者の状態から挑むとかなり修羅の道
    • >はプロンプトという既に画面に表示されている記号を表すで、キーボードから打ち込むものではない
  5. build/libsにfernflower.jarが出来上がる

Fernflowerの実行

fernflower.jarとIC2Expのdev版のjarを同一フォルダに置いてPowerShellから以下を実行。

> java -jar .\fernflower.jar .\industrialcraft-2-2.2.828-experimental-dev.jar src

結果、srcフォルダにソースコードが出力される。

バッチファイルの作成(Windows前提)

このまま常にコマンドからfernflower.jarを呼び出してもいいが、できれば最低でもD&Dで実行したいのでバッチファイルを作る。

どこかしらに次のようなフォルダを作る

  • decompile
  • fernflower.jar
  • fernflower.bat (以下の内容)
java -jar "%~dp0fernflower.jar" %1 "%~dp0decompile"
mkdir "%~dpn1-src"
cd /d "%~dpn1-src"
jar xf "%~dp0decompile\%~nx1"
del "%~dp0decompile\%~nx1"
pause

これで、fernflower.batに対してjarファイルをドロップするとjarファイルと同じフォルダに逆コンパイルされたコードが入ったフォルダが生成されるようになった。

レジストリの設定(Windows前提)

このまま常にバッチファイルにドロップしてもいいが、できれば右クリックしたらこの場所にソースを生成するコマンドが欲しい。そこで、一連の動作を行うバッチファイルを作りレジストリを操作してJarファイルに関連付ける。

  1. レジストリエディタを起動する
    • Windowsキー+Rrededitで呼べる
  2. HKEY_CLASSES_ROOT\jarfile\shellに飛ぶ
    • Javaをインストールしていないと無いと思う、もしかしたら作ってもいいかも
  3. キーHKEY_CLASSES_ROOT\jarfile\shell\open\commandを作る
  4. (既定)のデータを"さきほどのfernflower.batのフルパス名" "%1"にする

適当なJarファイルを右クリックしてdecompileという項目が増えていれば成功。

逆コンパイルコードの読み方

ここまでで様々なJarを逆コンパイルして.javaファイルの入ったフォルダが入手できるようになっているので、実際にdev版のIC2Expをダウンロードしてソースコードを得る。ここではソースコードを読みやすくするためのいくつかの点について触れる。

IDEによる支援

結局のところとりあえず読むならIDEを入れた方が早い。exlink.gifexlink.gifEclipseのJava版かUltimate版をダウンロードし、新規プロジェクトないしexlink.gifexlink.gifForgeプロジェクトを使って、srcフォルダに逆コンパイルコードをぶち込んでしまおう。

JarをJD-GUIに読み込ませてもコードハイライトや定義へのジャンプ機能など様々なことができるが、ソースのフォーマット(成形)やより高度な検索はIDEを使うのが良い。一応実行もできる。

ファイル差分

別Verとの差分をとる場合、公式の更新履歴が信用できない場合は独自にコード差分をとることもできる。exlink.gifexlink.gifMercurial(バージョン管理システム)のGUI(exlink.gifexlink.gifTurtoiseHG)上でコミットしてしまうのが分かりやすくて高機能か。

外部リンク

GregTech6 exlink.gifhttp://gregtech.overminddl1.com/com/gregoriust/gregtech/gregtech_1.7.10/index.html#Downloads

IC2Exp exlink.gifhttp://ic2api.player.to:8080/job/IC2_experimental/

最終更新:2017年11月03日 23:06