あると便利だなぁ というソフトウェアやサービスの実現を目指します。

[JAVAアセンブリ][Modding]IndustrialCraft2のマターレシピの無効化

Forgeを用いて作られたMODをデコンパイルして改編後、再度リコンパイルしようとすると、うまくコンパイルができなかったりしますよね。(やり方が悪いだけかもしれませんが
そこで、今回は、逆アセンブルを用いた方法で、IC2のマターのレシピを無効化してみたいと思います。

用意するものは、JDKと、JD-GUIです。
また、テキストエディタや、バイナリエディダもあるとよいでしょう。
JDKは、MOD開発者なら当然持っていることでしょう。
JD-GUIも有名なJAVAデコンパイラですね。

今回は、JAVA等の環境パスは通ってる前提で進めます。

では早速始めたいと思います。

最初に、対象クラスを、取り出しましょう。

今回は、mod_IC2.class内の、レシピ情報を書き換えたいので、mod_IC2.classを取り出します。

そして、その取り出したmod_IC2.classをJD-GUIを用いて、改変箇所を確認します。

今回は、registerCraftingRecipes()内の、マターを用いたレシピ追加情報消去します。
なので、matterで検索を行います。
846行目あたりから、マターのレシピが大量に追加されていることが確認できます。
877行目のiridiumOreのレシピだけは残して、クァンタムの作成だけは許容するようにしてみます。

調査の結果、846行目~876行目 および、 878行目~890行目までを無効化すればいいと分かりましたね。

では今度は、これを逆アセンブルしましょう。

コマンドプロンプトを開いて、カレントディレクトリを mod_IC2.classを保存した場所に移動します。
その後、  javap -private -c -l mod_IC2 > mod_IC2.asm を実行し、逆アセンブルを行います。
 *note:オプション指定の -private -c -l の説明は、 javap -help を参照してください。
すると、カレントディレクトリに、逆アセンブルされたmod_IC2.asmが生成されます。
今度は、逆アセンブルされたクラスを見るために、mod_IC2.asmをTerapadやメモ帳などのお好きなテキストエディタで開いて確認します。

今回の編集対象のメソッド名であるregisterCraftingRecipesで検索をかけると、 4967行目に対象を発見しました。
ずらずらーーっとアセンブル情報が記述されています。 あまり長時間みていると、一部のマニアを除いて嫌気がさしてくるので、がっつり眺めてはいけません。
-lオプションをつけて、逆アセンブルしているため、メソッドの終了後に、デコンパイラとの行数の対応表が付与されています。


ずーーーーーっと下へスクロールし、15507行目あたりでやっと、オフセット対応表が出現しました。

対象は、846行目~876行目 および、 878行目~890行目までを無効化 と先程調査しましたので、それに対応するメソッド内オフセットを調査します。

対象開始となる846行目は、メソッド内オフセット4170番目から始まることがわかります。

対象終了である、876行目は、メソッド内オフセットの5991番目まで続いてることが分かります。
この際、5937番目ではないことに注意してください。5937番目は、876行目の開始オフセットであり、終了オフセットは、877行目のオフセット(5992番目)より1つ前の5991番目まで となります。

同様に、878行目~890行目も調査すると、
 846~876 ⇒ 4170~5991
 878~890 ⇒ 6046~6400
が今回のターゲット メソッド内オフセット値となります。
このオフセットはあくまで、メソッド内オフセットですので、このままでは実オフセットがわかりません。

ですので、メソッド内オフセット0が、実オフセットのいくつに対応するのか調査を行います。

幸い、registerCraftingRecipesの前のメソッド(takenFromCrafting)は、分かりやすい構成となっているので、それを目印として探してみましょう。前のメソッドは aload_1,aload_2,aload_3 invokestatic , return となっていますね。
各々の命令(aload_1など)の前の数字は、メソッド内オフセットを表しています。
invokestaticのオフセットが3なのにたいして、returnのオフセットが6なので、
invokestaticは、3バイト有していることが分かります。
それをもとに、ニーモニック変換を行います。ニーモニック変換は、wikiの表を参考にしながら頑張ります。

その結果、
aload_1は2b ,
aload_2は2c,
aload_3は2d
invokestaticは、B8 ?? ??
returnは、B1 だと分かりました。

では、Stirlingなどのバイナリエディダを用いて、mod_IC2.classの対象個所を探してみましょう。

大体、0xC6DA付近に対象がみつかりましたね。 2B 2C 2D B8 03 ?? ?? B1 の条件にぴったりマッチしていることが確認できますね。
メソッドが終わった後、すぐに次のメソッドのコードが書かれるわけではないので、registerCraftingRecipes側の先頭部分についても同様に探してみましょう。
getstatic , iconst_5,anewarry,dup 的な感じなので、
B2 ?? ??
08
BD ?? ??
59
03
であるので、0xC6DA直後に、B2 ?? ?? 08 BD ?? ?? 59 03 がくるところを探してみます。

0xC73Bに発見できました。よって、オフセットは0xC73Bであることがわかりました。

これを先程もとめた、

 846~876 ⇒ 4170~5991
 878~890 ⇒ 6046~6400
に足します。 10進表記と16進表記がまじっててわかりにくいので、16進数表記で統一します。
 4170~5991  : 104A ~1767
 6046~6400 : 179E~1900
これに、オフセットC73Bを加えると、
D785-DEA2
DED9-E03B
であることが分かりました。

これでほとんどの工程は完了です。あと一歩です。
最後に、 この範囲をNOPで埋めます。NOPは何もしないことを指します。
NOPコードは0なので、D785-DEA2とDED9-E03Bの範囲をそれぞれ指定して、0うめをします。

範囲をががーっと選択して、選択範囲を0で初期化します。同様に、DED9-E03Bも初期化します。

あとは保存して、jar内にclassを上書きして戻してやれば、作業は完了!

不安であれば、一応編集後のclassを再度、JD-GUI等でデコンパイルしてみて、正常に変更ができたか確認してにまにましてくださいませ。 また、実際にゲーム内で試してみることもお忘れなく。