分かりやす〜い
コンピュータ技術情報

TOPに戻る
▼Processor
バッファオーバーフロー
┣ 異常な動作
┣ 本当に怖い事
┣ プログラムを作る
┣ バッファオーバーフロ
┃ ーを発生させる

┣ スタック領域の構成
┣ 何故強制終了されるの
┃ か?

┣ 強制終了されないよう
┃ に作り変える

┣ 任意のコードを実行す
┃ る

┣ of1.cとof2.cとの違い
┣ 例外
┣ 例外ハンドラの行う事
┣ of3.cを作る
┣ of1.cとof3.cとの違い
┣ of3.exeの例外ハンド
┃ ラ

┣ of3.exeを強制終了す
┃ るのは?

┣ 例外ハンドラの特徴
┣ Blue Screen
┣ BufferOverFlow応用
┃ プログラム

┗ 機械語の説明

Copyright(C) 2001-2002.ugpop. All rights reserved.




■デジタル用語辞典:
■ 何故強制終了されるのか? ■

前回は、バッファオーバーフローにより何の情報が壊されてし
まうのか説明しました。
前回見てもらったイメージをもう1度見てみましょう。


                  レジスタESP
 スタック領域├─────┤    ┌─────┐
       │  i  │←───┤     │●メイン関数で
       ├─────┤    └─────┘ 使用するスタ
       │     │            ック領域の1
       │     │            番上を示す。
       │バッファb│
       │     │
       │     │
       ├─────┤
       │バッファa│
       │     │    レジスタEBP
       ├─────┤    ┌─────┐
       │  ebp  │←───┤     │●メイン関数で
       ├─────┤    └─────┘ 使用するスタ
       │呼出し元 │            ック領域の1
       └─────┘            番底を示す。


これはメイン関数がスタック領域を初期化した直後のイメージ
です。
この時点ではまだバッファオーバーフローは発生していません。

それでは、コピー処理が完了した直後のイメージを見てみまし
ょう。


                  レジスタESP
 スタック領域├─────┤    ┌─────┐
       │  i  │←───┤     │●メイン関数で
       ├─────┤    └─────┘ 使用するスタ
       │     │            ック領域の1
       │     │            番上を示す。
       │バッファb├─┐
       │     │ │
       │     │ │コピー
       ├─────┤ │
       │     │←┘
       │     │    レジスタEBP
       │バッファb│    ┌─────┐
       │     │←───┤     │●メイン関数で
       │     │    └─────┘ 使用するスタ
       │     │            ック領域の1
       └─────┘            番底を示す。


バッファオーバーフローが発生し、「ebp」と「呼出し元」の
情報が上書きされています。

この時点ではまだプロセッサの保護機能は動作しません。

何故なら、バッファオーバーフローが発生した事にプロセッサ
は気付く事が出来ないからです。

それでは、このプログラムが強制終了させられる契機は何なの
でしょうか?


今度は具体的な値が設定されているイメージで見てみましょう。
まずはバッファオーバーフロー発生前です。


●バッファオーバーフロー発生前

        スタック領域
       ┌┌────┐
       ││ 10 │
       ││ 11 │
       ││ 12 │
  バッファb││ 13 │
       ││ 14 │
       ││ 15 │
       ││ 16 │
       ││ 17 │
       ││ 18 │
       ││ 19 │
       ││ 1A │
       ││ 1B │
       ││ 1C │
       ││ 1D │
       ││ 1E │
       ││ 1F │
       ││ FF │
       ││ FF │
       ││ FF │
       ││ FF │
       ├├────┤
       ││  0 │
       ││  1 │
       ││  2 │
       ││  3 │
  バッファa││  4 │
       ││  5 │
       ││  6 │
       ││  7 │
       └├────┤
        │    │
        │ebp │
        │    │
        │    │
        ├────┤
        │    │
        │呼出し元│
        │    │
        │    │
        └────┘


次にバッファオーバーフロー発生後のイメージを見てみましょ
う。


●バッファオーバーフロー発生後

        スタック領域
       ┌┌────┐┐
       ││ 10 ││
       ││ 11 ││
       ││ 12 ││バッファ「b」のサイズ分
  バッファb││ 13 │├─┐    ̄
       ││ 14 ││ │
       ││ 15 ││ │
       ││ 16 ││ │
       ││ 17 ││ │
       ││ 18 ││ │
       ││ 19 ││ │
       ││ 1A ││ │コピー
       ││ 1B ││ │
       ││ 1C ││ │
       ││ 1D ││ │
       ││ 1E ││ │
       ││ 1F ││ │
       ││ FF ││ │
       ││ FF ││ │
       ││ FF ││ │
       ││ FF ││ │
       ├├────┤┤ │
       ││ 10 ││ │
       ││ 11 ││ │
       ││ 12 ││ │
       ││ 13 ││ │
  バッファa││ 14 ││ │
       ││ 15 ││ │
       ││ 16 ││ │
       ││ 17 ││ │
       ├└────┘│ │
       │× 18 ×│ │
    ebp│× 19 ×│←┘
       │× 1A ×│
       │× 1B ×│
       ├××××××│
       │× 1C ×│
   呼出し元│× 1D ×│
       │× 1E ×│
       │× 1F ×│
       └××××××│
        × FF ×│
        × FF ×│
        × FF ×│
        × FF ×┘


バッファオーバーフローが発生しました。
ここでちょっと「呼出し元」の情報に注目してみましょう。

この情報は何かというと、メイン関数の処理が「終了した後に」
どこに制御を移行させるか、という情報を表しています。

以下に、バッファオーバーフローが「発生しない」場合のプロ
グラムの動作イメージを示します。
「呼出し元」の情報がどのように使用されているかに気を付け
ながらご覧ください。

┌──────────────────────────┐
│           プログラム          │
│                          │
└───┬──────────────────────┘
    │                       スタック領域
    │call命令               格納 ┌──────┐
    ├─────────────────────→│ 呼出し元 │
    │    制御を移行┌────────┐   └──────┘
    ├────────→│ main関数 │
    │←──┐     │        │
    │   │     └───┬────┘
    │   │         │
  続きの処理 │      ┌──┴──┐
    ・   │      │コピー処理│
    ・   │      └──┬──┘
    ・   │         │処理終了     スタック領域
    ・   │         │どこへ戻るか参照┌──────┐
        │ 呼出し元に戻る │←───────┤ 呼出し元 │
        └─────────┘        └──────┘


「call命令」により、スタック領域に「呼出し元」の情報が格
納され、メイン関数に制御が移行されます。

そしてメイン関数の処理が終了した後に、スタック領域にある
「呼出し元」の情報を参照しています。
プロセッサはこれによりどこへ戻れば良いかを認識し、「呼出
し元」で示されている場所へ制御を移行させます。

「呼出し元」の情報がどのように使用されるか分かりましたね?

それでは今度はバッファオーバーフローが「発生する」場合の
プログラムの動作イメージを見てみましょう。
先ほどのイメージとは、コピー処理が完了した後の動作が異な
ります。

┌──────────────────────────┐
│         OF1.EXE          │
│                          │
└───┬──────────────────────┘
    │                       スタック領域
    │call命令               格納 ┌──────┐
    ├─────────────────────→│ 呼出し元 │
    │    制御を移行┌────────┐   └──────┘
    ├────────→│ main関数 │
    │         │        │
    │         └───┬────┘
    │             │
               ┌──┴──┐
               │コピー処理│
               └──┬──┘
                  │×バッファオーバーフロー発生
                  │         スタック領域
                  │        ┌──────┐
                  ├───────→│1F 1E 1D 1C │
                  │        └──────┘
                  │処理終了     スタック領域
                  │どこへ戻るか参照┌──────┐
                  │←───────┤1F 1E 1D 1C │
                  │        └──────┘
               ×××××××
               ×そんな所に×
               ×実行可能な×
               ×プログラム×
               ×ありません×
               ×××××××


「call命令」により、スタック領域に「呼出し元」の情報が格
納され、メイン関数に制御が移行されます。
ここまでは先ほどのイメージと同じです。

ところが、メイン関数のコピー処理においてバッファオーバー
フローが発生してしまいます。
これにより「呼出し元」の情報がおかしな値に書き換えられて
しまいました。

「呼出し元」の情報がどういう値に書き換わってしまったのか
を覚えておいてください。

覚えたら、ちょっと実験してみましょう。

もう1度、以前作成したプログラム"OF1.EXE"を実行してみて
ください。

ただし、今度は「不正な処理を行ったので強制終了します。」
と表示されたら、「閉じる」を選択せずに、「詳細情報」のボ
タンを押してみてください。(WindowsXPの方は、「エラー報
告に含まれるデータの参照」の項目をクリックし「エラー報告
に関する技術情報」の項目をクリックしてみてください。)


この詳細情報の中には、不正な処理を行ったアドレス情報が表
示されるようになっています。

以下に"OF1.EXE"をWindows98にて実行した場合の詳細情報を示
します。


─↓ここから──────────────────────

OF1 のページ違反です。
モジュール : <不明>、アドレス : 0084:1f1e1d1c
Registers:
EAX=00000015 CS=017f EIP=1f1e1d1c EFLGS=00010212
EBX=00530000 SS=0187 ESP=0063fe00 EBP=1b1a1918
ECX=0063fe00 DS=0187 ESI=816d9158 FS=66ef
EDX=0063fdff ES=0187 EDI=00000000 GS=6e1e
Bytes at CS:EIP:

─↑ここまで──────────────────────

アドレス情報の所が「1f1e1d1c」となっています。

先ほど覚えてもらった、「呼出し元」の情報と同じ値ですね。

この事は、メイン関数の処理が完了して、「呼出し元」に戻ろ
うとしたという事を表しています。

つまり「1f1e1d1c」という場所にある命令を実行しようとした
けれども「実行可能なコードが存在しない」ので、インテルプ
ロセッサが怒ってしまった、という事です。

ここで気を付けて頂きたい事は、インテルプロセッサは「バッ
ファオーバーフローが発生した」から怒っているのではなく、
「呼出し元のコードを実行しようとしたけど出来ませんでした
よ。」と言って怒っているという事です。

それでは、「呼出し元のコードを実行しようとしたけど出来ま
せんでしたよ。」とプロセッサに言わせないようにした場合、
どうなるでしょうか?

次回はインテルプロセッサが怒ってしまわないようにプログラ
ムを改造してみる予定です。



▲このページの上へ

▲このページの上へ

▲このページの上へ

▲このページの上へ

←前に戻る    ▲このページの上へ    続きを読む→