.NET Tools

.NET逆コンパイラと
コードを難読化するDotfuscator

(株)ピーデー 川俣 晶
2003/09/23
Page1 Page2 Page3 Page4

Reflector for .NETで逆コンパイルする

 アセンブリの内容を、ILではなく、C#やVB.NETのソース・コードにすることができるツール(Decompiler:逆コンパイラと呼ばれる)の1つとして「Reflector for .NET」というものがある。これは英語版のソフトだが、日本語を含むコードも問題なく扱える。利用するには、開発元のサイト(Lutz Roeder’s Programming.NET)よりReflector.zipファイルを入手後、これを展開する。中には、.NET Framework 1.0対応のファイルと、1.1対応のファイルが含まれているので利用中の環境に合わせて使い分ける。ここにあるReflector.exeを実行すれば、Reflector for .NETはすぐに使用可能である。

Reflector for .NETの実行画面
.NETのEXEファイルやDLLファイルから、C#やVisual Basic .NETのソース・コードを復元する(逆コンパイルする)ことができる。起動時には.NET Frameworkに含まれている主要なクラス・ライブラリが読み込まれる。

 ここで、[File]メニューの[Open]を使って、調べたいアセンブリを指定する。次に[Language]メニューで、対象とする言語をC#とするかVB.NETとするかを選ぶ。続いて、ツリーから目的のDistanceメソッドを探す。そのメソッドを選択してから、[Tool]メニューの[Decompile]を選ぶ。するとこうなる。

C#を使用したDistanceメソッドの逆コンパイル
 
VB.NETを使用したDistanceメソッドの逆コンパイル

 このとおり、ソースが提供されていないアセンブリのソース・コードを見ることができてしまった。しかし、これは魔法ではない。ここに表示されている内容は、Reflector for .NETがILの内容から推測して組み立てたもので、ソース・コードと完全に一致しているわけではない。この事例のソース・コードは実は以下のようなものであった。

public static int Distance( int x1, int y1, int x2, int y2 )
{
    return (int)Math.Sqrt( (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) );
}

 C#版の結果と見比べると分かるように、括弧の数が違うし、元のコードにはないdouble型へのキャストが含まれている。意味的には完全に同じだが、ソース・コード上の一字一句が再現されているわけではないのである。

 もう1つ、VB.NET版と見比べてみよう。プログラム言語が違うため、まったく違うソース・コードになってしまったといってもよい。しかし、機能的にはまったく同じものである。

 実は、逆コンパイラを使うと、異なるプログラム言語への変換も可能である。C#で書かれたソース・コードが理解できなくて困っているVisual Basicプログラマーは、一度アセンブリにしてからReflector for .NETでVB.NETのソース・コードとして表示してから理解する、という方法も可能かもしれない。とはいえ、この方法ではコメントなどが削除されてしまうため、元のコードにあったすべての情報にアクセスできない点には注意が必要である。

 さて、こうやって見ると、この例のメソッドで、計算結果の小数の扱いがどうなっているかは明白である。計算結果の実数値を戻り値の整数型に変換するために、整数型へのキャストが行われているので、実数から整数へのキャストの変換ルール「ゼロに向かって最も近い整数値に丸められる」が適用されることがはっきりした。

 なお、このような行為は、リバース・エンジニアリングを禁止しているライセンスのクラス・ライブラリに適用してはならない。その点は注意していただきたい。

 Reflector for .NETは、このほかに以下のような機能も備えている。

  • 型やメンバの検索
  • 型の参照の検索
  • IL逆アセンブラ
  • C# XMLドキュメント・ビューア
  • MSDN helpビューア
  • 依存ツリー表示
  • スーパータイプ、サブタイプ・ヒエラルキー・ビューア
  • リソース・ビューア

 以上に加えて、Reflector for .NETを拡張するためのSDK(開発キット)も提供されている。これには「Delphi .NET」のコードに逆アセンブルするプラグインなども含まれている。

しかし、簡単にソース・コードが見られるのも困りもの

 このような話は、クラス・ライブラリの利用者には朗報だが、クラス・ライブラリの開発者にとっては大問題である。さまざまな企業秘密のテクニックを駆使したクラス・ライブラリのソースが簡単に見られては困ったことになる。さらに付け加えるなら、Reflector for .NETで逆コンパイルできるのは、クラス・ライブラリに限らない。実行ファイルも、やはり簡単に逆コンパイルできるとあっては、アプリケーション・ソフトの開発者も安心はできないだろう。アセンブリに含まれるコードは、ネイティブ・コードを除き、基本的には逆コンパイル可能であると考えてよいだろう。

 では、どうして、こんなにも容易に逆コンパイルができるのだろうか。確かに昔から、逆コンパイラというソフトがなかったわけではない。しかし、これほど精度よく分かりやすいソース・コードを生成できるものは存在しなかった。いったい、.NETで何が変わったというのだろうか。

 それを理解するには、リフレクションと呼ばれる技術について知る必要がある。リフレクションとは、プログラムが実行中に、プログラム自身についての情報を扱う機能である。リフレクションを使えば、プログラム自身に含まれているクラスやメソッドを調べ、それを呼び出すことができる。また、未知のアセンブリを読み込んで、内部を調べ、どんなクラスやメソッドがあるかを知ることもできる。

 このような機能を活用するためには、ソース・コードの多くの情報をアセンブリに埋め込んでおく必要がある。例えば、メソッドの名前は、古い世代の言語処理系では、デバッグ用の実行ファイルを生成する場合にのみ埋め込むべきものであった。リリース用の実行ファイルには、メソッドの名前の情報は不要であり、ファイルを小さくするためにも取り除かれるべきものだったのである。そのため、このようなファイルを逆コンパイルしても、あまり分かりやすいソース・コードは得られなかった。しかし、リフレクションという機能があるとなると、話は別である。リフレクションで実行時に必要な情報を抜き出すには、クラスやメソッドの名前はアセンブリに書き込まれている必要がある。そうでなければ、名前を指定して特定のメソッドの情報を得る、という機能が実現できない。

 だがこれは裏を返すと、コンパイル済みのアセンブリからでも、非常に多くのソース・コードに関する情報を引き出せることを意味する。その結果、Reflector for .NETのような逆コンパイル・ツールによって、読んで意味の分かるソース・コードをかなり再現することが可能となっているわけである。

 このような状況を放置しておくことが問題となる場合もあるだろう。例えば、顧客のID文字列をチェックする以下のようなメソッドがあるとしよう。本来ならもっと複雑な条件で判定すべきものだが、ここでは簡略化し、文字列の長さが6で、2文字目が“X”、5文字目が“Y”であるものが正しい顧客IDという判定を行っているとしよう。そして、この判定条件は極めてレベルの高い機密事項だったとしよう。

public static void Check( string id )
{
  if( id.Length != 6 || id[1] != 'X' || id[4] != 'Y' )
  {
    throw new BadCustomerIDException(id +"は誤ったIDです。");
  }
}
顧客のID文字列をチェックするメソッド例
ここでは、この判定条件が極めてレベルの高い機密事項だとしよう。

 これをコンパイルして、Reflector for .NETで調べると、いともあっさりと以下のような結果を得ることができる。

C#を使用したCheckメソッドの逆コンパイル
 
VB.NETを使用したCheckメソッドの逆コンパイル

 “X”や“Y”がその文字コードを示す整数値の88や89に変わってしまった点を除けば、実に分かりやすいソースが再現されているといえる。整数値から、それが示す文字が何かを調べるのは簡単である。また、このメソッドが顧客IDをチェックしていることを突き止めることも容易である。画面左側のツリーを見れば、さまざまな手掛かりになる名前が並んでいる。これらを見ながら、corporatesecurity.dllというアセンブリの中のCorporateSecurity名前空間の中のCustomerIDクラスの中のCheckメソッド、とたどっていけば、目的のメソッドにたどり着くことは容易である。

 こういったツールに対抗するには、どうすればよいのだろうか。何か対策はあり得るのだろうか。


 INDEX
  [.NET Tools]
  .NET逆コンパイラとコードを難読化するDotfuscator
     1.クラス・ライブラリが何をしているか知りたいとき
   2.Reflector for .NETで逆コンパイルする
     3.コードの難読化を行うDotfuscator
     4.製品版Dotfuscatorによる文字列の暗号化
 
インデックス・ページヘ  「.NET Tools」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間