いまさら聞けない「難読化」超入門 その1 〜難読化とは〜

 「難読化技術」について、広く浅く、できれば簡単に説明したいと思います。

難読化とは

 難読化(obfuscation)とは、プログラムやHTMLなどのコード(ソースコードアセンブリコードなど)を読みづらくする技術です。読みづらくとは、読んで字のごとく人間がコードを読んで理解しにくい状態を指します。難読化されたコードは、視認性が悪く全体を見通すことが複雑であったり、コードの簡単な表現が複雑な表現に置き換わっていたりします。また、難読化の対象はコードを読む人間だけでなく、逆コンパイラのようなソフトウェアが元のコードを復元するプロセスを妨害する場合もあります。
 難読化は主にコードを変更する技術ですが、動作の結果を変える技術ではありません。コードを難読化するとコードの姿形、つまり、見た目が大きく変わります。また、内面的には元のコードから大きくかけ離れた動作をすることがあります。それでも、難読化されたコードの実行/表示の結果は元のコードの動作から変わることはなく、元のコードと等価な動作をし、等価な結果を返すことを想定しています。

ここで例

 【追記】全然入門になってない&某氏に例をあげるといいとアドバイスをいただいたので、例をあげてみます。
 「難読化」「なんどくか」と呼ぶと難しいイメージがしますが、簡単に言えば難読化とは「コードをスパゲッティ化」することです。プログラマーであれば「スパゲッティコード」という言葉をご存じでしょう。例えば、次のふたつのCコードが同じ実行結果を示すと一瞬で判断することはできないでしょう。*1

#include <stdio.h>
int main(int argc, const char *argv[])
{
        while (0 < argc--) {
                printf("%d %s\n", argc, argv[argc]);
        }
        return 0;
}
main(int _,const char **__) {while(-(_--)<0)printf("\x25\x64\x20\x25\x73\n", _, __[_]);}

 難読化とはこのような変換だけに限りませんが、イメージしやすい形としてはスパゲティ化を想像いただけたらと思います。
 また、視覚的にわかりやすいものであれば、Wikipedia(en)のObfuscated codeというページや、The International Obfuscated C Code Contest(国際邪悪なCコードコンテスト)といったサイトを見るとよいでしょう。
 Obfuscated code - Wikipedia, the free encyclopedia
 http://en.wikipedia.org/wiki/Obfuscated_code
 The International Obfuscated C Code Contest
 http://www.ioccc.org/main.html

難読化と暗号化

 コードを暗号化するのが難読化じゃないの? という疑問もあるかもしれませんが、「暗号化すること=難読化」ではありません。コードを暗号化することで難読化を実現することはできます。しかしこれは「難読化とはすなわちコードを暗号化することである」という意味ではありません。数ある難読化の手段のひとつに「コードを暗号化」する方法もあるということです。
 難読化で利用する「暗号化」というのは普段用いる「暗号」とは意味合いが異なります。 プロテクト技術でプログラムを暗号化する、などといいますが、実際は復号する鍵をプログラム自身が持っていて実行時にプログラムが自身を復号して実行します *2。また、前述したように、難読化したコードは元のコードと等価な動作をして等価な結果を返すことが求められます。コードを暗号化したから元のコードが見られることがなく安全、というのはまったくの見当違いになります。暗号化したコードを実行するとなると、元のコードを復号する必要があるのですから。そして、暗号化によって保護できるのは暗号化しているときだけで、元のコードを復元してしまったら、元のコードを保護しているものは何もありません。
 暗号化は復号したコードを読みづらくすることに関しては無力です。それでは、暗号化は難読化の手段として無効なのか? ということはなく、使いどころによっては有効な手段です。少なくとも暗号化されている状態では、元のコードがどんなものか判別することはできません。そこで暗号化以外の「難読化」手法が有効となります。この件は後のエントリで説明します。

本日のまとめ

 難読化とはなんぞや、というくらいにはご理解いただけたでしょうか。これだけでは説明不足なので、次のエントリで難読化が使われる目的・背景、実際にどうやって実現するのか広く浅くをモットーに説明していきたいと思います。本当は一気に書きあげたかったのですが、意外に文字数がふくれあがってしまい疲れたので今日はここまで。難読化の概要を大きく示してから、より細かい説明に移った方がよかったかもしれません(汗)。何かツッコミがあればコメントで指摘いただければありがたいです。
 では、次回「目的・背景編」「実装技術編」といったエントリに続きます。

*1:一応gccコンパイルして実行結果を確かめましたが、例ということで多くの環境で動作することはテストしてないです。難読化やスパゲッティを示すよいコードとはいえませんが

*2:まれに外部、たとえばどこかにおいたファイルから鍵を求めるものが存在しますが、実行時に復号するというのは一緒です。