Kali LinuxのJD-GUIでJava逆コンパイルしてみる

Kali Linuxをいじってみる続き。

Kali Linux 1.0.4からいくつかのパッケージが加わったので、そこにスポットを当ててみる。今回はJD-GUIという、Javaの逆コンパイラを取り上げよう。

JD-GUIとは何か

Javaの逆コンパイラは、.classファイルから.javaファイル(ソースコード)を生成するツールである。一昔前はJavaの逆コンパイラと言えばJADJava Decompilerか、と言われていた。今回紹介するJD-GUIは、このJava Decompilerプロジェクトのツールのひとつで、スタンドアロンで動作するGUIアプリである。

ちなみにJava Decompilerプロジェクトにはこのほかに、Eclipseプラグインとして動作するJD-Eclipseなどがある。公式Webサイトは以下。

インストール

Kali Linuxでは1.0.4からデフォルトパッケージに加わったが、1.0.3からアップデートしたところ自動的には入っていなかった。そのため、以下のようにapt-getで手動でインストールすればよい。

root@kali:~# apt-get install jd-gui

JD-GUIを使ってみる

起動方法

コマンドラインからjd-guiと叩くだけでよい。

上のように起動直後は空っぽのウィンドウが開くので、メニューからjarファイルをopenすればよい。

サンプル

なんでもよいのだが、ここでは私が分かりやすいということでTomcatを対象にしてみよう。Tomcat 7 Downloadsのページから、[Core - tar.gz]をダウンロードして適当なところに展開しておく。そしてJD-GUIのメニューで apache-tomcat-7.0.42/lib/catalina-tribes.jar を開いてみよう。

ちなみに本稿で最初にclassファイルを逆コンパイルする……というように書いたが、jarファイルは単なるzipファイルで、中身にはclassファイルなどが詰まっている形式である。JD-GUIはjarに対応しているので、jarファイルをそのまま開けば良い。


これは org.apache.catalina.tribes.transport.ReceiverBase を開いたものだが、ちょっとびっくりするくらい元のソースと同じものが再現されている。classファイルには元の変数名なども格納されているので、こうも忠実に逆コンパイルできるようだ。


これはReceiverBaseクラスのbind()関数で、利用したいポートが他アプリなどで使われているときは1ずつポート番号を増やしてリトライしていくautoBind機構で使われる部分である。たとえば、Tomcatクラスタリングする際、セッションレプリケーションで利用するポートなどはこれを利用する。

見て分かる通り、変数名まで含めて再現されているので内部的な動きもよく分かるし、元のソースともほとんど同じである。びっくりした。(ちなみにTomcatソースコードは先ほどのDownloadページの下の方、[Source Code Distributions]から落とせるので比べてみよう)

Androidアプリの逆コンパイル

さて、Javaアプリと言えば一昔前はサーバサイドで動くつまらない(失礼)業務アプリが主流だったので、逆コンパイラはあまり注目されてこなかった。わざわざ、職場で使われるような在庫管理ツールとか勤怠管理システムとかを、自分で逆コンパイルしてもつまらないよね(?)。

一方、もう若い人は知らないだろうけどかつてはJavaアプレットというものが一瞬だけ流行ったので、その逆コンパイルも一瞬トレンドになったことがあった。アプレットの場合はユーザ側にclassファイルが渡るので、それをなんとかしちゃおうという人たちと、ソースコードの漏洩を気にしていた企業側の人たちとの水面下の戦い(のようなもの)があったようだ。しかしその後はJavaアプレット自体が下火になったので、このトレンドも自然消滅。

しかし昨今のスマホブームで状況は一変した。AndroidアプリはJavaで書かれているので、それを逆コンパイルしたい……という需要が一気に高まったのだ。

Androidアプリは、周知の通り.apkというファイル形式になっている。apkはjarと同じように単なるzipファイルなのでそのまま展開すれば良いのだが、通常のJavaアプリと違うのは、Dalvik VMという特殊な仮想マシン上で動作することだ。

Android PCなど 備考
パッケージ形式 .apk .jar 実はどちらもただのzip
実行ファイル Dalvik Executable(.dex) Javaバイトコード(.class) dexはclassから生成可能
実行VM Dalvik VM Java VM Dalvik VMJava仮想マシンではない
アーキテクチャ レジスタベース スタックベース
ソースコード Javaソース Javaソース どちらも同じJava

細かい説明は省くが、AndroidアプリはまずJavaソースをコンパイルしてclassファイルを作成し、そこからさらにDalvik Executable(DEX)ファイルを作成し、それをDalvik VM上で実行することで動作させる。

具体的な手順

よって、AndroidアプリをJD-GUIで逆コンパイルするには、以下の手順を踏めば良い。

  • apkファイルをzipファイルとして展開する。
  • 中に含まれるclasses.dexファイルを、dex2jarを使ってjarファイルに変換する。
$ ./d2j-dex2jar.sh classes.dex
dex2jar classes.dex -> classes-dex2jar.jar
  • 作成されたjarファイル(classes-dex2jar.jar)を、JD-GUIで開く。

上記の手順で、apkファイルを逆コンパイルしてJavaソースコードまで持って行けることを確認した(もちろんライセンス的に問題ないものをやりましたよ)。

難読化とリバースエンジニアリング

さて逆コンパイルリバースエンジニアリングの話が出てくると、一緒に出てくるのが難読化ツール。ソースコードを人にとって読みにくくするためのツールだ。この類のものは世に色々とあって、特にJavaScriptのようにそのまま見えてしまうものは、ソースが見えることを嫌って難読化ツールを使う人が結構いるようだ。

しかしどうも私は、この手の製品を感覚として「気持ち悪い」と思ってしまう。せっかく美しいソースコード(リーダブルコード)を書いたとして、それを出荷前に「汚す」のはエンジニアとして大変によろしくないと感じてしまうのだ。それに、「もう誰が書いたかも分からない、仕様書も何も残っていないシステム」を運用させられることをイヤほど繰り返した経験からも(^^; 、難読化はまさに誰得技術としか思えない。

また、昨今のプログラミング環境ならば、何か面白い動きをするアプリを見たときに、「どういうコードを書いてるんだろう? なんとか逆コンパイルして解析してみよう」というアプローチよりも、「よーし、これをパクって同じ感じの動きをするプログラムを書いてみよう」というアプローチの方が、楽チンな気がするんだよね(そもそもパクること自体がアレだけど)。そうなると、もはや難読化って自己満足以外の何物でもないんじゃないかなぁ……と思ってしまうのだ。

あ、あとは、マルウェアを書いてる悪い人たちが動作を読ませにくくするために使う……という用途があるか。何か他に有効な使い道ってあるのかなぁ。

参考情報

書籍

まだ未読で申し訳ないけど、以下の書籍「デコンパイリングJava」が参考になるようです

URL

ちょっと古いけど、IBMdeveloperWorksに以下記事がありました