逆コンパイラ

更新日: 2003年 8月30日(日)

逆コンパイラって?

ある日、仕事中に「オラクル」のことを調べていたらなぜか検索で引っかかったことが事の発端ですが、先に"逆コンパイラ"とは、何者か説明しましょう。

"逆コンパイラ"は書いて字のごとくコンパイラの逆、バイトコードのclassファイルをjavaソースファイルへ元に戻すことのことを言います。

しっかり者の方なら、アプリケーションをインストールする時に表示される使用許諾書の中に"逆アセンブラ","逆コンパイラ","リバースエンジニアリング"などの行為は禁止と書かれていることに気が付いた人もいるのではないかと思います。

開発したソフトウェアを解析し、それを自分で作り直し、自分が開発したものとしてソフトウェアを作る行為を"リバースエンジニアリング"といい、この行為はやってはいけないことになっています。

ですので、旨々使用方法にはお気を付けてください(^^ゞ

逆コンパイラの利点

これは

「class ファイルから元のソースコードを読むことができる」

事でしょう。

classファイルのライブラリ化されたパッケージはブラックボックス化してしまい、細かい仕様が把握しにくいことがあります。仕事をしている時にドキュメント不足のライブラリを渡された時もこの逆コンパイラである程度問題を解決できるツールとして利用できます。

逆コンパイルの問題

実際、逆コンパイラで発生する問題点を上げると

Java の逆コンパイラよりも前に C/C++ の逆コンパイラも存在していました。しかし、C/C++の逆コンパイラは、機械語から元のソースコードに戻すため、逆コンパイルしたソースコードを読んでも変数や関数の名前はすべて番号付けの名前で 、クラスや関数の名前が元に戻らないため"何をしているソースコード"なのかさえ、調べるのが困難でした。

これは、本来物理的に存在するCPUは、存続のプログラムを最適化して高速に実行したり、コンパイラは存続のCPUで可能な限り最適を図ろうとしたため、このようなCPUが最適に実行できるコードはそれだけで難読なものになってしまうからです。

今度は Java の実際に存在しないCPUは、本来のCPU, OSに依存しないで、バイトコードが実行できることが上げられます。この機能を実装するためには、物理的に存在するCPUに依存するコードを出力してしまうと、それとは異なるアーキテクチャをもつCPUが実行しにくくなると考えられるので、元のソースコード似のシンプルなバイトコードで実行する必要があります。

そのため Java のプログラムは、従来のC++に比べると解読が容易なため逆コンパイラの出来が良い者が多いようです。

逆コンパイラを使う

実際に以下のソースコードをコンパイルします。

//
// Filename: HelloJava.java
//
class HelloJava {
  public static void main(String args[])
  {
  if(true)
    System.out.println("Hello, Java World!");
  else
    System.out.println("No");

  switch(1){
    case 1: System.out.println("No"); break;
  }
} 

ここでは javac で普通にコンパイルします。

次に、肝心な逆コンパイラができるツールですが、今回は「jad」というツールを使いました。このjadは、Win用なので、他のOSの人は、この他にも逆コンパイラがあるようなので、調べてみると良いかもしれません。

次に

> jad -8 HelloJava.class

( * '>' は c:\> のプロンプトのつもり )

と、逆コンパイラのツールを使ってコマンドを打つと、"HelloJava.jad" ファイルが生成されます。(-8のオプションは日本語対応?らしいです)

// Decompiled by Jad v1.5.7a. Copyright 1997-99 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3) ansi 
// Source File Name: HelloJava.java

import java.io.PrintStream;

class HelloJava
{

  HelloJava()
  {
  }

  public static void main(String args[])
  {
    System.out.println("Hello, Java World!");
    switch(1)
    {
      case 1: // '\001'
      System.out.println("No");
      break;
    }
  }
}

逆コンパイラしたファイルと元のソースコードを見比べると、デフォルトコンストラクタが追加され、意味のない if(true) 分が消え、最適化されたことがわかります。

完全に元のコードには戻りませんが、元のコードが何をしていたのかは手に取るようにわかると思います。

ちなみに、ソースコードを書くのがダルいので、長いソースコードを書きませんでしたが、

のようになるため、逆コンパイラによって生成されたコードを読むのは難しくありません。

難読

Java だけではなく、同じような仮想OSで動作する C# (.net Framework ) も同じように解読が容易に行うことができます。

これは逆に、勝手にソースコードがいじくられる可能性やコードが盗まれる可能性も容易に行えるためセキュリティ的に安全ではありません。

そこで、解析を難しくする「難読ツール」というものが出てきました。Java はいろんなところから難読ツールが作られ、セキュリティを強化することが出来ます。ただし、これを使用すると実行速度やファイルサイズが多少変化するようですが・・・。(*C#はMSから難読ツール提供)

最後にもう一度念押しで、リバースエンジニアリングは不正行為であり、法的にも罰せられる可能性があるのでご使用の際は十分気を付けてご使用ください。