【コラム】

ITセキュリティのアライ出し

20 Windowsにおけるバッファオーバーフロー(5)

    新井悠  [2007/02/14]

    スタックの役割は、第18回に書いたとおり「一時データ置き場」である。一方で、このデータの種類によって、スタックも分類することができる。以下にその分類を記述する。

    1. データスタック…変数やポインタなどを保存するスタック
    2. コールスタック(ウィキペディア)…サブルーチンコールにおける戻りアドレス(リターンアドレス)を保存するスタック。「リターンスタック」「実行スタック」「関数スタック」などと呼ばれることもある

    スタックベースのバッファオーバーフローを理解するうえで、重要なポイントのひとつになるのはリターンアドレスについての概念になる。よって、ここでは後者について説明していきたい。

    ここで、あるプログラムがあったとする。そのプログラムでは、図1のように特定の処理Aと処理Bが重複して実行されるとする。このままのプログラムでもよいのだが、重複した処理を単一の処理として整理したほうが、メモリ利用効率が向上することになる。また、重複した処理を何度もコーディングするというのは、プログラマにとって大変煩わしい。

    図1

    そこで、重複する処理はプログラム本体(メインルーチン)とは別の場所に個別に作成しておき、必要に応じてそれを呼び出す、という方法が考案された。このようなプログラム本体とは別の場所に作成され、呼び出される特定の処理を「サブルーチン」と呼ぶ。図2にその概念を示す。

    図2

    プログラマにとって、あるプログラムの一連の処理をサブルーチンに分割するメリットについて以下に述べる。

    1. 重複したコードを減らすことで作業を低減できる
    2. コードの再利用を促せる
    3. 複雑な処理を、複数の単純な処理に分割することで、保守・拡張が容易なプログラムにできる
    4. プログラムの可読性を改善できる
    5. 特定のコードへの依存を低減すること
    上記のメリットの出典: Wikipedia

    ところで、本稿で扱うバッファオーバーフローは、CおよびC++言語でコーディングされたプログラムにおいて発生しやすいとされている。そして、これらのプログラミング言語も、関数という形でサブルーチンを実現している。具体的には、これらの言語のコンパイラによって生成されるコードは、[コール]と[リターン]というCPUへの命令を利用することで、サブルーチンを実現しているのだ。

    サブルーチンに関して理解をすすめるために、さらに図3を用意してみた。細かい点は理解促進のために省いてあるのでご容赦いただきたい。

    図3

    あるプログラム中で、サブルーチンの呼び出しがコール命令の実行によって(1の部分)行われたとする。すると、コール命令の次の命令が格納されているアドレスをスタックに保存する(2の部分)。このように、サブルーチンの呼び出しのあった次の命令のアドレスを保存するスタックは「コールスタック」と呼ばれる。加えて、コールスタックに保存されたアドレスの値は「リターンアドレス」と呼ばれる。

    次に、サブルーチンの処理が開始された(3の部分)のちに終了したとする。ここでメインルーチンに処理を戻すためにリターン命令が実行される(4の部分)。すると、先ほどのコールスタックからリターンアドレスが取り出され、それを指標にCPUは処理を移す(5の部分)ことでメインルーチンへの復帰を図る。いささか単純化しているきらいもあるが、以上がCおよびC++言語でコーディングされたプログラムにおけるサブルーチンの取り扱いになる。

    重要なことは、コールスタックに含まれるリターンアドレスは、プログラムが正確に処理を進めるための指標であるということになる。この値にズレや間違いがあれば、プログラムはコーディングした通りには動いてくれなくなるのだ。そこで、ひとつ想像力を働かせてみよう。プログラムをコーディングした当人以外が、この値を自在に操ることができたなら、いったい何が起こるというのだろうか?

    プログラムの動作不全が起こる、と答えられればほぼ正解である。ソフトウエアにつきもののバグと同じように、動作不全が起こる個所を避けて使用するなどして、その利用者は使い勝手に支障を起こさないように心がけるだろう。問題は、リターンアドレスの値を自在に操れるようにバグを使いこなす者である。

    バグを巧みに利用することで、ソフトウエアの本来の動作とはかけ離れた処理を引き起こさせる手口がある。スタックベースのバッファオーバーフローは、まさにその手口のひとつである。多量のデータをスタックに複製させることで、リターンアドレスを上書きし、メインルーチンでない別の場所から命令を読み出させることで、攻撃を成功させるのだ。

    関連記事

    関連サイト

    新着記事

    特設サイトの情報

      人気記事

      一覧

        イチオシ記事

        新着記事

        特別企画

        マイナビニュースマガジン