(57)【特許請求の範囲】
【請求項１】
電子計算機の記憶媒体に格納されているプログラムが、デバッグレジスタを有する構造を持つ中央演算処理装置によって実行されるとき、
メモリのスタックメモリ領域に格納されているリターンアドレスが不正コードの実行によってオーバーライトされる前記メモリのバッファオーバーフローを検知し、前記バッファオーバーフローの発生を防止させるように前記電子計算機を機能させる不正コード実行の防止用プログラムにおいて、
前記不正コード実行の防止用プログラムは、前記電子計算機に、
前記プログラムが前記記憶媒体から呼び出されるとき、前記プログラムの中の分岐命令を取得して前記プログラムを解析するための解析機能と、
前記プログラムの中で一番最初に実行される命令の番地を、デバッグ機能に利用される前記デバッグレジスタに登録し、前記命令が実行されたとき、前記デバッグ機能によって、トレースコールバック関数が呼び出されるようにする登録機能と、
前記プログラムが実行され、前記中央演算処理装置によって前記分岐命令がトレースされ、前記分岐命令が前記解析機能で検知されたとき、前記デバッグ機能のトレースフラグをクリアにするトレース無効機能と、
前記中央演算処理装置によって最後に実行された前記分岐命令の情報を、汎用レジスタに読み取りする機能と、
前記汎用レジスタの内容から、前記分岐命令の種類を判別する判別機能と、
前記判別機能で前記分岐命令が前記プログラムのサブルーチンの呼び出し命令（CALL）である場合、前記呼び出し命令の前記リターンアドレスが格納されている、前記スタックメモリ領域のメモリ番地から、前記リターンアドレスを取得する機能と、
前記リターンアドレスを前記メモリに保存するリターンアドレス保存機能と、
前記クリアされた前記トレースフラグを設定し、前記分岐命令の前記トレースを再開する機能と、
前記判別機能で前記分岐命令が復帰命令(RET、RETxx)である場合、前記復帰命令で指定された前記リターンアドレスを前記スタックメモリ領域から読み取る読み取り機能と、
前記読み取り機能で読み取った値を、前記リターンアドレス保存機能で保存された値と比較するリターンアドレス比較機能と、
前記リターンアドレス比較機能で、前記読み取り機能で読み取った値と、前記リターンアドレス保存機能で保存された値が同じである場合、前記クリアされた前記トレースフラグを設定し、前記分岐命令の前記トレースを再開する機能と、
前記リターンアドレス比較機能で、前記読み取り機能で読み取った値と、前記リターンアドレス保存機能で保存された値が一致しない場合、前記呼び出し命令（CALL）の前記リターンアドレスが改ざんされたものと判定し、前記プログラムの流れを停止、前記プログラムの流れを一時停止、及びエラールーチンを実行する処理の内の１処理を行って、前記プログラムの流れを制御するための制御機能と
を実現させるためのプログラムであり、
更に、
前記制御機能は、前記読み取り機能で読み取った前記リターンアドレスを、前記リターンアドレス保存機能によって前記メモリに保存された前記リターンアドレスで、書き換えする機能と、
前記制御機能は、前記読み取り機能で読み取ったもので、書き換えられた後の値を保存し、前記値を用いて攻撃の種類、及び前記攻撃のパターンを解析する機能と
を前記電子計算機に実現させることを特徴とする不正コード実行の防止用プログラム。
【請求項２】
請求項１において、
前記プログラムは、アプリケーションソフトウェア、オペレーティングシステムのソフトウェアモジュール、カーネルモードソフトウェア、これらの中で使用する関数、サブルーチンから選択される内１以上である
ことを特徴とする不正コード実行の防止用プログラム。
【請求項３】
請求項１又は２に記載された、不正コード実行の防止用プログラムを記録した不正コード実行の防止用プログラムの記録媒体。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、電子計算機で動作するプログラムが不正コードによる動作不備又は外部からの攻撃から保護する不正コード実行の防止方法、不正コード実行の防止用プログラム、及び不正コード実行の防止用プログラムの記録媒体に関する。詳しくは、バッファオーバーフローを検出し、プログラムの動作不備を改善する不正コード実行の防止方法、不正コード実行の防止用プログラム、及び不正コード実行の防止用プログラムの記録媒体に関する。
【背景技術】
【０００２】
電子計算機のオペレーティングシステムは複雑に設計されている。このため、オペレーティングシステムには、セキュリティホールと呼ばれる弱点がある。セキュリティホールとは、ソフトウェアの設計の欠陥やバグにより生じる脆弱性の構造である。悪意のあるユーザは、オペレーティングシステムのこのセキュリティホールを利用して、オペレーティングシステムへ不正に侵入し、ハッキング、クラッキング等の悪意の行為を行うことがある。その手段としては、メモリのバッファオーバーフロー（Buffer over flow）を利用する方法がある。
【０００３】
ここで、バッファオーバーフローについて説明する。電子計算機で動作するプログラムは、プログラムコードとプログラムデータの２つの部分から構成される。プログラムコードは、機械語で書かれた読み出し専用のコードである。プログラムデータは、オペレーティングシステムの実行命令によって実行されるプログラムコードのメモリ上の位置等のインフォメーション部分である。
【０００４】
プログラムは、通常は、電子計算機のハードディスクに保存されている。プログラムはオペレーティングシステムによって呼び出され実行するとき、プログラム全体で又はその一部が電子計算機のメインメモリであるRAM（Random  Access  Memory）に格納されて動作する。メインメモリは、電子計算機のCPU（中央処理装置）から直接データの読み書きできるメモリで、データを格納する単位容量ごとに番地番号をつけて管理されている。メインメモリの番地番号の小さい方を上位番地（High Memory）領域、番地番号が大きくなると下位番地（Low Memory）領域としている。以下、メインメモリを単にメモリとして説明する。
【０００５】
プログラムがオペレーティングシステムによって読み出されると、メモリの一部がこのプログラムに割り当てられて、その割り与えられたメモリの上位番地（High Memory）領域にプログラムデータが格納され、下位番地（Low Memory）領域にプログラムコードが格納される。プログラムデータは、スタックデータ（Stack data）、ヒープデータ（Heap data）、スタティックデータ（Static data）の３つのデータ領域に分かれている。これらの３つの領域は、お互いに独立してメモリに配置されている。実行されるプログラムが、オペレーティングシステムによってハードディスクから呼び出されると、最初は、プログラムコードが読み出されメモリに格納される。続いて、プログラムデータが読み出されてメモリに格納される。
【０００６】
図５は、電子計算機のメモリの構造を示す概念図である。メモリの上位番地側はスタックメモリ領域になっている。スタックメモリ領域は、プログラムが実行されるごとに、そのプログラムとプログラム内のサブルーチン用のスタックメモリがここに確保されてメモリの下位番地へと順番に格納される。スタックメモリは、引数（Argument）領域、リターンアドレス（Return Address）領域、スタックデータ領域等から構成される。
【０００７】
メモリの下位番地側は、ヒープデータ領域、スタティックデータ領域、プログラムコード領域等の領域から構成されている。スタティックデータ領域は、プログラムコード領域より上位番地側に位置し、グローバル変数とstatic C++クラスメンバーが予約されるメモリ領域である。スタティックデータ領域より上位番地側にはヒープデータ領域が位置する。ヒープデータ領域はＣ言語のmalloc()、alloc()関数、C++言語のnewオペレータに割り当てられている領域である。
【０００８】
スタックメモリ領域はＬＩＦＯ（Last-in,first-out）方式でアクセスされる。スタックメモリは、実行命令が終了後の次の命令が実行されるリターンアドレス等の関数パラメータやローカル変数等が格納される。このリターンアドレスはもっとも重要な値である。
【０００９】
図６には、Ｃ言語で書かれているプログラムを例示している。プログラムが実行されると、まずmain()関数が実行されて（行１〜３）、４行目のサブルーチンのsub(Data1)が呼び出されてプログラムの処理が１０行目に移っている。sub()サブルーチンでは、１６行目のreturn命令で、sub()を呼び出した元の位置へ処理を移している。このとき、メモリにどのようにデータが格納されるかを説明する。
【００１０】
サブルーチンが呼び出されると、図７に図示したように、スタックメモリ領域にデータが書き込まれる。スタックメモリ領域の上位番地側から「main()へのリターンアドレス」が格納されて、サブルーチン内のローカル変数が格納される領域が予約される。この例では、変数i（１１行目）とbuf（１２行目）がある。１４行目のstrcpy命令でサブルーチンの引数Dataの値をbufにコピーしている。このとき、引数Dataの値がbufのサイズより大きい場合は、ローカル変数i、場合によっては、main()ルーチンへのリターンアドレスまで上書きしてしまうことになる。このように、データが確保されたメモリの領域に入りきれないで別の変数のための領域にまで書き込まれる。これは、バッファオーバーフローである。リターンアドレスが別の値に書き換えられているので、プログラムは正常の動作をしなくなる。
【００１１】
通常これらのプログラム、プログラムのサブルーチン、関数が実行されて終わると、リターンアドレスに示された位置に戻され、プログラムの実行が継続される。しかし、プログラムの作り方に不具合があると、上に説明したように、データを書き込みするときにローカル変数の確保領域を超えてリターンアドレスを上書きすることが可能になる。
【００１２】
通常リターンアドレスの書き換えによってバッファオーバーフローを起こしたプログラムは、不定な実行状態となる。場合によっては、プログラムが暴走、あるいは停止することが殆どである。リターンアドレスが意図的に用意したメモリ番地に戻されると、オペレーティングシステムはこれを不正なコードと分からずにこのメモリ番地に格納されている命令を継続して実行させる。バッファオーバーフローによる脆弱性を利用した攻撃は、このように意図的に用意したコードを実行させることである。
【００１３】
このようなバッファオーバーフローによる不正コードの実行は、プログラムの実行管理を行っているオペレーティングシステムでは全く把握できない。この不正コードの実行を防ぐには、リターンアドレスの改ざん、書き換えを如何に防ぐか、あるいは検知できるかが非常に重要である。
【００１４】
この問題を解決する方法としては、オペレーティングシステムに修正を加える方法や、コンパイラにバッファオーバーフローを防ぐ仕組みを作る方法等が提案されている。オペレーティングシステムに修正を加える方法としては、非特許文献１のプロジェクトがある。このプロジェクトでは、オープンソースのオペレーティングシステムのバッファオーバーフローを防ぐためには、スタックのリターンアドレス領域を関数が実行されない別のメモリ領域に移す方法で対処している。
【００１５】
コンパイラにバッファオーバーフローを防ぐ仕組みをする方法としては、非特許文献２がある。この方法は、ＧＣＣコンパイラに、スタックメモリの下位番地に保護セクションを設けてデータのオーバーライトを検知している。
【００１６】
また、特許文献１の場合は、記憶装置に保護数値の領域を定義し、スタックメモリのデータを保護数値の領域に保存して保護し、処理指令を実行している。保護数値の領域にリターンアドレス等が保護されているためサブルーチン等の処理指令が実行されてもプログラムカウンタが保護される。
【非特許文献１】Openwall Linux kernel patch project,  URL:http://www.openwall.com/linux/
【非特許文献２】StackGuard: Simple Stack Smash Protection go GCC, URL: http://www.immunix.com/~wagle
【特許文献１】米国公開特許番号  US2001013094 A1-2001-08-09、“Memory device, stack protection system, computer system, compiler, stack protection method, storage medium and program transmission apparatus”.
【発明の開示】
【発明が解決しようとする課題】
【００１７】
上記のいずれの方法においても、プログラムコードの変更及びリビルドが必要である。よって、これらの方法を実施しする際には、時間が掛かる。また、この不正コードの実行を利用している代表的なものは、コンピュータウィルスである。従来からコンピュータウィルスからの防止手法はシグネチャ方式であり、未知の攻撃パターンの場合は何の効果も無い。そのため、不具合が生じる度にオペレーティングシステムの変更、パッチファイルの提供が必要とされている。
【００１８】
本発明は上述のような技術背景のもとになされたものであり、下記の目的を達成する。
本発明の目的は、電子計算機のメモリの番地に格納されているデータの改ざん防止、データ改ざんの検出を行う方法、そのプログラム、プログラムの記録媒体を提供することである。
本発明の目的は、プログラムの実行時におけるスタックメモリ内のリターンアドレスへの改ざん防止と検出を行う方法を提供することである。
本発明の他の目的は、ハードウェア、オペレーティングシステム、カーネルモードソフトウェア、アプリケーションソフトウェアを変更することなく利用できる不正コード実行の防止機能を提供することである。
本発明の更に他の目的は、アプリケーションソフトウェア及び、カーネルモードソフトウェアがバッファオーバーフローによる脆弱性を有するときも有効に不正コード実行の防止機能を提供することである。
本発明の更に他の目的は、不正コードが実行される前に検出し、不正なコードの実行を抑止することである。
【課題を解決するための手段】
【００１９】
本発明は、前記目的を達成するため、次の手段を採る。
【００２３】
本発明の第１の発明の不正コード実行の防止用プログラムは、電子計算機の記憶媒体に格納されているプログラムが、デバッグレジスタを有する構造を持つ中央演算処理装置によって実行されるとき、メモリのスタックメモリ領域に格納されているリターンアドレスが不正コードの実行によってオーバーライトされる前記メモリのバッファオーバーフローを検知し、前記バッファオーバーフローの発生を防止させるように前記電子計算機を機能させる不正コード実行の防止用プログラムである。
【００２４】
この不正コード実行の防止用プログラムは、前記電子計算機に、
前記プログラムが前記記憶媒体から呼び出されるとき、前記プログラムの中の分岐命令を取得して前記プログラムを解析するための解析機能と前記プログラムの中で一番最初に実行される命令の番地を、デバッグ機能に利用される前記デバッグレジスタに登録し、前記命令が実行されたとき、前記デバッグ機能によって、トレースコールバック関数が呼び出されるようにする登録機能と、
前記プログラムが実行され、前記中央演算処理装置によって前記分岐命令がトレースされ、前記分岐命令が前記解析機能で検知されたとき、前記デバッグ機能のトレースフラグをクリアにするトレース無効機能と、
前記中央演算処理装置によって最後に実行された前記分岐命令の情報を、汎用レジスタに読み取りする機能と、
前記汎用レジスタの内容から、前記分岐命令の種類を判別する判別機能と、
前記判別機能で前記分岐命令が前記プログラムのサブルーチンの呼び出し命令（CALL）である場合、前記呼び出し命令の前記リターンアドレスが格納されている、前記スタックメモリ領域のメモリ番地から、前記リターンアドレスを取得する機能と、
前記リターンアドレスを前記メモリに保存するリターンアドレス保存機能と、
前記クリアされた前記トレースフラグを設定し、前記分岐命令の前記トレースを再開する機能と、
前記判別機能で前記分岐命令が復帰命令(RET、RETxx)である場合、前記復帰命令で指定された前記リターンアドレスを前記スタックメモリ領域から読み取る読み取り機能と、
前記読み取り機能で読み取った値を、前記リターンアドレス保存機能で保存された値と比較するリターンアドレス比較機能と、
前記リターンアドレス比較機能で、前記読み取り機能で読み取った値と、前記リターンアドレス保存機能で保存された値が同じである場合、前記クリアされた前記トレースフラグを設定し、前記分岐命令の前記トレースを再開する機能と、
前記リターンアドレス比較機能で、前記読み取り機能で読み取った値と、前記リターンアドレス保存機能で保存された値が一致しない場合、前記呼び出し命令（CALL）の前記リターンアドレスが改ざんされたものと判定し、前記プログラムの流れを停止、前記プログラムの流れを一時停止、及びエラールーチンを実行する処理の内の１処理を行って、前記プログラムの流れを制御するための制御機能と
を実現させるためのプログラムであり、
更に、
前記制御機能は、前記読み取り機能で読み取った前記リターンアドレスを、前記リターンアドレス保存機能によって前記メモリに保存された前記リターンアドレスで、書き換えする機能と、
前記制御機能は、前記読み取り機能で読み取ったもので、書き換えられた後の値を保存し、前記値を用いて攻撃の種類、及び前記攻撃のパターンを解析する機能と
を前記電子計算機に実現させることを特徴とする。
【００２６】
また更に、前記プログラムは、アプリケーションソフトウェア、オペレーティングシス
テムのソフトウェアモジュール、カーネルモードソフトウェア、これらの中で使用する関
数、サブルーチンから選択される内１以上であると良い。
【００２７】
本発明の第２の発明の不正コード実行の防止用プログラムの記録媒体は、上述の不正コ
ード実行の防止用プログラムを記録した記録媒体である。
【発明の効果】
【００２８】
本発明によると、次の効果が奏される。
本発明の不正コード防止方法は、ハードウェア、オペレーティングシステム、カーネルモードソフトウェア、アプリケーションソフトウェアを変更することなく、不正コードの実行を防止できる。
本発明の不正コード防止方法は、アプリケーションソフトウェア及び、カーネルモードソフトウェアが、バッファオーバーフローによる脆弱性を有するときも有効に対応できる。
本発明の不正コード防止方法は、不正コードが実行される前に検出し、不正なコードの実行を抑止できる。
【発明を実施するための最良の形態】
【００２９】
以下、本発明の最良の実施の形態を図面によって具体的に説明する。
[実施の形態１]
以下、本発明の実施の形態１を説明する。 
本発明は、電子計算機のメインメモリに格納されているデータが書き換えをされ、改ざんされる行為を検知する方法を提供するものである。また、この方法により、電子計算機のメインメモリに格納されているデータが書き換えをされ、改ざんされる行為を検知し、書き換えまたは改ざんされたデータを復元するためのプログラムを提供する。更に、本発明は、そのプログラムを記録した記録媒体を提供するものである。この本発明の実施の形態の概要を説明する。
【００３０】
ＣＰＵのデバッグ機能は、アプリケーションプログラムが実行されるときに発生するエラーを検出するための機能である。このためには、ＣＰＵにデバッグレジスタと呼ばれる複数のメモリを用意しており、メインメモリの特定の番地の動作を監視するために利用している。このデバッグレジスタに監視する番地のアドレス及びCPU動作を登録し、この番地の値が変更されるときにＣＰＵがこれを検知してエラー信号を出している。そして、アプリケーションプログラムの実行に割り込みをして、別のプログラムを動作させることが可能である。
【００３１】
本発明の実施の形態１では、バッファオーバーフローによる不正コードの実行を検知し、データ改ざん等を防止するプログラムの動作を説明する。電子計算機上にプログラムが動作するときに、従来技術で説明したように、プログラム、サブプログラム、関数が呼び出されるごとにそのリターンアドレスがスタックメモリ領域に格納される。電子計算機のＣＰＵのデバッグレジスタには、プログラムの一番最初に実行する命令のポインタを指定して記録して、プロセス生成コールバック関数を登録して置く。そして、命令トレース機能を有効にする。命令トレース機能が有効のとき、CPUによって実行される命令をトレースし、分岐命令を検知し、リターンアドレスを取得する。
【００３２】
また同時に、リターンアドレスをメインメモリの別の領域にバックアップして置く。このバックアップされて保存されたリターンアドレスを、スタックメモリのリターンアドレスと比較して、リターンアドレスの改ざんを検知する。具体的には、分岐命令の実行をデバッグ機能によって無効にして、分岐命令を分析して、リターンアドレスの改ざんを検知する。スタックメモリに格納されているリターンアドレスが改ざんされると、実行されているプログラムに割り込みをし、制御を別のプログラムに移動させて、データ改ざん、不正コードの実行を防止することができる。バックアップしたリターンアドレスを、元の番地に書き換えし、プログラムを正常な動作に戻す。また、書き換えられたアドレスをバックアップして、バッファオーバーフローによるコンピュータウィルス攻撃のパターン解析にも利用することが可能である。
【００３３】
以下、本発明の実施の形態１の不正コード防止方法は、このデバッグレジスタを利用したデータの改ざんを検知し、改ざんされたデータを修復する方法を実現させるために、ドライバウェア層と、エラールーチンを提供するものである。このドライバウェア層は、上述のリターンアドレスを把握し、バックアップする機能を有する。エラールーチンは、リターンアドレスのデータが改ざんされると、この改ざんを修復するための機能を提供している。以下、本発明の実施の形態１を詳細に説明する。
【００３４】
図１には、本発明の実施の形態の概要を図示している。図１には、電子計算機上で動作するソフトウェア１、ドライバウェア２、ファイルシステムドライバ３、ハードディスク４が図示されている。通常、実行可能なプログラムはハードディスク４に実行可能ファイル５として保存され、オペレーティングシステムの呼び出し命令で読み出されメモリ６へ格納される。ソフトウェア１は、電子計算機上に動作しているアプリケーションプログラムを意味する。このアプリケーションプログラムは、オペレーティングシステムのカーネルモード又は、ユーザモードで動作するどのようなプログラムでも良い。
【００３５】
ドライバウェア２は、ファイルシステムドライバ３とオペレーティングシステムが提供するサービスとの間に位置するもので、オペレーティングシステムから電子計算機の各デバイスから／へ読み出し／書き込みをするときの制御を行うプログラムである。
【００３６】
ファイルシステムドライバ３は、電子計算機に内蔵又は接続されている記憶装置に格納されているデータを読み出し、この記憶装置にデータを書き込みするためのドライバである。ハードディスク４は、通常、電子計算機に内蔵されているハードディスクである。しかし、ソフトウェア１が格納され、オペレーティングシステムから呼び出されて実行可能であれば、外付けハードディスク、フラッシュメモリ、ＣＤ−ＲＯＭなどの外部記憶装置であっても良い。
【００３７】
本発明の実施の形態１では、オペレーティングシステムからプログラム（図１の実行可能ファイル５）を呼び出しする命令は、ドライバウェア２を介してファイルシステムドライバ３へ送信される形式をとる。
ファイルシステムドライバ３はハードディスク４からプログラムを呼び出し、ドライバウェア２へ渡す。ドライバウェア２はプログラムを解析してメインルーチン、サブルーチンを把握し、それぞれのリターンアドレスを取得し、バッファオーバーフローを検出する制御を行う。リターンアドレスは、CALL命令等の分岐命令で出力されてスタックメモリに格納され、RET、RETxx命令で戻るためのアドレスである。
この一連の動作を図３のフローチャートを参照しながら説明する。オペレーティングシステム、又はアプリケーションプログラムからプログラム（図１の実行可能ファイル５）を起動する（ステップ１）。ドライバウェア２は、プログラムの起動を検出する（ステップ２）。ドライバウェア２は、プログラムを解析してメインルーチン、サブルーチンを把握し、それぞれのリターンアドレスを取得する。ドライバウェア２は、プログラムの起動によって生成される引数、ローカル変数、関数アドレスを調べ（ステップ３）、関数アドレスを保存する。具体的には、プログラム内で実行されるコール（CALL）、リターン（RET、RETN）、ジャンプ（JMP）等の分岐命令の実行するイベントを調べリターンアドレスを取得し、保存する（ステップ４）。
【００３８】
そして、ドライバウェア２は、プログラムが実行している間に、コール命令（Call命令）等の分岐命令をフックするようにしてドライバウェア２へ制御を移動できるようにする（ステップ５）。具体的には、OSが提供するPsSetLoadImageNotifyRoutine()を呼び出し、プロセス起動時に呼び出されるコールバック関数（LoadImageNotifyRoutine）を登録して行われる。スレッド生成の場合は、_beginthread()の開始アドレスを取得し、この開始アドレスにブレークポイントを設置する。ドライバウェア２は、プログラムの実行時に、スタックメモリ上のリターンアドレスの保護と改ざんの検出機能を組み込む（ステップ６）。
【００３９】
リターンアドレスの検知には、上述のＣＰＵのデバッグ機能と命令トレース機能を利用する。このように、ＣＰＵのデバッグ機能の内、デバッグレジスタに格納された値のメモリ番地の命令が実行されるとき、命令を命令トレースするトレース機能があり、制御が指定された番地へ移動させることが可能である。このとき、ＣＰＵのデバッグレジスタにプログラムの一番最初に実行される命令のアドレスを登録して、命令トレース機能を有効にしておく。プログラムが実行されると、命令トレース機能で実行される全ての命令から分岐命令を検知する。分岐命令が検知されるとき、オペレーティングシステムは割り込み命令を出し、ドライバウェア２へ制御を移す。
リターンアドレスにこの機能を適用する。よって、リターンアドレスが書き換えられると、ドライバウェア２へ制御が移動するように設定される。ドライバウェア２はステップ１で指定されたプログラムを実行する（ステップ７）。
【００４０】
図４は、プログラムが起動されて実行されるときのバッファオーバーフローを検出する手順を示すフローチャートである。
【００４１】
オペレーティングシステム又はアプリケーションプログラムからは、プログラムを実行するときに呼び出し命令（Call命令）が実行されると、CPUの割り込みが発生し、ドライバウェア２に制御が移る（ステップ１０〜１１）。ドライバウェア２はプログラムの実行によって生成される引数、ローカル変数、関数アドレスを調べ（ステップ１２）、実行時におけるスタックメモリ上のリターンアドレスをデバッグ機能によって保護、又は、記憶する（ステップ１３）。
【００４２】
上述の記憶は、スタックメモリ上のリターンアドレスをメモリの別の領域にバックアップして保存する。リターンアドレスが改ざんされたときは、このバックアップしてリターンアドレスと比較して改ざんを検証することが可能になる。
【００４３】
そして、ドライバウェア３が命令（IRET）を出し（ステップ１４）、ステップ１１で割り込まれた実行アドレスへ制御を戻す（ステップ１５）、実行する（ステップ１６）。
呼び出された関数からの戻る直前で、ドライバウェアがステップ１３で記憶したリターンアドレスと、スタック上のリターンアドレスを比較する（ステップ１７〜１９）。ドライバウェア２がエラーを検出する（ステップ２０）。そして、プログラムの実行を中断して、エラールーチンへ制御が移る（ステップ２１）。エラールーチン（図示せず）は、エラーが検出されたときに実行され、プログラムの実行が停止、スタックメモリの内容の保存やリターンアドレスを事前に保存したデータで書き換えする等の機能を持つプログラムである。このエラールーチンによって、プログラムの実行を停止、継続、そして不正コードの保存ができる（ステップ２２）。
【００４４】
図２には、電子計算機が外部から攻撃される例を図示している。ネットワークカード１０を介して、ウィルスや不正コード等を有する外部データが送信されてくる。外部データはネットワークカード１０、ＮＤＩＳ１１、Ｗｉｎｓｏｃｋ１２を介してメモリ６に格納される。外部データがメモリ６に格納されるとき、プログラムのリターンアドレスの一部又は全部が書き換えられると、ＣＰＵがエラーを出力し制御がドライバウェア２に移る。ドライバウェア２はこのエラー検出を受けてエラールーチンをフックして対応する。
このように、バッファオーバーフローを利用した不正侵入、攻撃はすべて把握し、対処することができる。実行中のプロセスの停止、スタックメモリの内容の保存、元のプロセスの実行継続などができる。プロセスの停止によっては、実行しているプロセスを停止して、プログラムの暴走を止めることができる。スタックメモリの内容の保存によっては、不正コードを保存でき、その後の解析などの作業で攻撃、ウィルスの種類、そのパターンを把握できる。
【００４５】
本発明の実施の形態は、ユーザモードだけで動作するアプリケーションプログラムだけはなくて、カーネルモードで動作するプログラムにも適応される。また、同様な方法でバッファオーバーフローの手法を利用するプログラムであれば全てに適応できる。
【００４６】
（実施例）
本発明の実施の形態１の実施例を示す。本実施例では、Intel社（登録商標）の３２ビットアーキテクチャーのプロセッサで、命令トレース機能を実装しているものを想定している。具体的には、PentiumPro（登録商標）以後に開発されたプロセッサ、又はこのプロセッサと互換性のあるプロセッサである。オペレーティングシステムは、マイクロソフト社のWindows2000（登録商標）である。
ドライバウェア２が動作し、バッファオーバーフローの検知を行うための準備としての初期化処理、プログラムが実行されると発生されるプロセスとスレッドを検知し、メインルーチン、サブルーチンを把握する。そして、ドライバウェア２がバッファオーバーフローを検知すると、エラールーチンとしてプロセス中断処理を動作させて対処する。これらの動作について、詳細に説明する。
【００４７】
ドライバウェアが起動すると初期化処理を行う（図８を参照、説明は後述する。）。この初期化処理では、プログラムが呼び出されるとき生成されるプロセスとスレッドの検知を行う。この初期化処理の詳細は、図８〜１０のフローチャート（後述する）で示している。
この初期化処理を行った後は、プログラムが動作を開始する。このプログラムの動作中に実行されるジャンプ（JMP）、コール（CALL）、リターン（RET）等の分岐命令をすべて登録し、トレースする。CALL、RET、RETxx命令が実行されるとき、バッファオーバーフローを検知している。CALL、RET、RETxx命令の検知は、図１１、１２に示すフローチャートに示している。
【００４８】
CALL、RET、RETxx命令の検知された後の処理は、図１３〜図１６のフローチャートと、このフローチャートに対応する説明中のプログラムコードに示している。
【００４９】
（初期化処理）
図８のフローチャートは、初期化処理の概要を示している。まずは、ドライバウェアが起動し、バッファオーバーフローを監視するプロセス名をレジストリから読み込む（ステップ１００）。そして、監視対象のプロセスのプロセス生成コールバックを登録する（ステップ１０１）。このプロセス生成コールバックの登録について詳細には、図９のフローチャートに示している。その後、スタックレコーダを初期化し、メモリ領域を確保する（ステップ１０２）。そして、監視対象スレッドのスレッド生成イベントのフック設定を行う（ステップ１０３）。それから、実行命令のトレースを開始する。
プロセス生成コールバックの登録は、OSが提供するPsSetLoadImageNotifyRoutine()を呼び出し、プロセス起動時に呼び出されるコールバック関数（LoadImageNotifyRoutine）を登録して行われる。このコールバック関数は、次のプロトタイプで定義される。
【００５０】
0004518564.tif 000002
【００５１】
次に、図９のフローチャートには、プロセス生成コールバックの登録の手順を示している。プロセスが生成されるとLoadImageNotifyRoutine関数が呼び出される（ステップ１１０）。以下、LoadImageNotifyRoutine内での動作を示す。監視する対象のプロセスかを判定する（ステップ１１１）。この判定のときは、LoadImageNotifyRoutineの引数FullImageNameに、対象となるプロセスモジュール名が存在するかどうかを調べる。存在していた場合は次の処理に移る（はい）。
プロセスモジュールのエントリポイントアドレスを取得する（ステップ１１２）。Windowsで使用される実行モジュールファイルの先頭部分（ヘッダ）を調査し、最初に実行される関数（エントリポイント）のアドレスを取得する。そして、エントリポイントに、ブレークポイントを設置する（ステップ１１３）。このときのプログラムコードの例は次の通りである。
【００５２】
0004518564.tif 000003
【００５３】
そして、IA-32命令のトレース機能を有効にして、トレースコールバック関数（ASO_Hook_INT01H）の登録のためにIDT（割り込みディスクリプタテーブル）の01Hを書き換える（ステップ１１４）。この登録のためのプログラムコードは以下の通りである。
【００５４】
0004518564.tif 000004
【００５５】
プロセスが起動した時に最初に実行される命令にハードウェアブレークポイントを設定し、実行された際にトレースコールバック関数（ASO_Hook_INT01H）が呼び出されるようにする（ステップ１１５）。このためのプログラムコードは以下の通りである。
【００５６】
0004518564.tif 000005
【００５７】
スタックレコーダの初期化（ステップ１０２を参照）は、指定された監視対象のプロセスのスレッドが生成される度に動的に実施される。スタックレコーダの各スタックは、次のように定義される。
【００５８】
0004518564.tif 000006
【００５９】
図１０のフローチャートには、スレッド生成イベントのフック設定（ステップ１０３を参照）の手順を示している。スレッドが生成される（ステップ１２０）と、監視する対象のプロセスか否かを判定する（ステップ１２１）。生成されたスレッドが監視する対象のプロセスのときは、_beginthread()の開始アドレスを取得する（ステップ１２２）。この開始アドレスにブレークポイントを設置する（ステップ１２３）。それから、トレースを開始する（ステップ１２４）。
複数スレッドのシステムには、スレッドを生成するカーネルAPIであるNtCreateThreadをフックすることで適用させている。そのため、NtCreateThreadを呼び出す際に経由されるベクタ2Eの割り込みハンドラ（ASO_Hook_INT2EH）を書き換える。このときのプログラムコードは次のようになる。
【００６０】
0004518564.tif 000007
【００６１】
スレッド生成イベント（CreateThread()）のフック設定で使用されるプログラムコードは次のとおりである。
【００６２】
0004518564.tif 000008
【００６３】
このように、一連の初期化処理が終了すると、プログラムが実行され、CALL、RET等の分岐命令をトレースする。次に、トレースしているときの処理を、図１１、１２のフローチャートに示している。トレース処理が開始されると（ステップ１５０）、DR６のトレースフラッグをクリアして（ステップ１５１）、CALL命令、RET命令を判別している。図１１、図１２の分岐判定のときは（ステップ１５４〜１８３）、CALL、RET、RETN命令を判別し、それぞれ「CALL処理へ」、「RET処理へ」、「RENT処理へ」となっている。「CALL処理へ」、「RET処理へ」、「RENT処理へ」は、それぞれ図１３、図１４、図１５のフローチャートに示している。CALL、RET、RETN命令を判別するときのプログラムコードは、次のようになる。
【００６４】
0004518564.tif 000009
【００６５】
ここでは、CALL、RET、RETNの判別は、それぞれCALL_FOUND、RET_FOUND 、RETN_FOUNDとしてコード化されている。プログラムコードの分岐命令にてCALL_FOUNDにジャンプした場合、CALL命令が実行されたと見なして、図１３のフローチャートに示す処理が行われる。RET、RETNの場合は同様である。
図１３には、CALL命令が実行されるときの処理を示している。CALL命令の実行が開始されると（ステップ２００）、CALL命令に割り与えられたスタックメモリのスタックセグメント（CS）のアドレスを取得する（ステップ２０１）。そして、CALL命令で格納されるリターンアドレスのスタックポイントを取得する（ステップ２０２）。その後、スタックメモリからリターンアドレスを取得する（ステップ２０３）。このときのプログラムコードは次のようになる。
【００６６】
0004518564.tif 000010
【００６７】
この取得したリターンアドレスをスタックレコーダに登録する（ステップ２０４）。このときのプログラムコードは、次のようになる。
【００６８】
0004518564.tif 000011
【００６９】
そして、MSRとEFLAGを設定して命令トレースを再開する（ステップ２０５、２０６）。IRETDにて処理を完了。
図１４には、RET命令が実行されるときの処理を示している。RET命令の実行が開始されると（ステップ２５０）、RET命令に割り与えられたスタックメモリのスタックセグメント（CS）のアドレスを取得する（ステップ２５１）。そして、RET命令で指定されたリターンアドレスのスタックポインタを取得する（ステップ２５２）。その後、スタックメモリからリターンアドレスを取得する（ステップ２５３）。このときのプログラムコードは次のようになる。
【００７０】
0004518564.tif 000012
【００７１】
そして、スタックレコーダからリターンアドレスと同じ値があるかを検索する（ステップ２５４）。リターンアドレスは、このRET命令に対応するCALL命令のときにスタックレコーダに登録されているものである。しかし、リターンアドレスが改ざんされた場合は、スタックレコーダの中から同じアドレスが見つからない。このときは、プロセス中断処理（次のコードのTerminate_VirusCode()）へ移る（ステップ２６０）。同じアドレスが見つかると、スタックレコーダから１レコードを削除（ステップ２５５）する。このときのプログラムコードは次のようになる。
【００７２】
0004518564.tif 000013
【００７３】
そして、MSRとEFLAGを設定して命令トレースを再開する（ステップ２５６、２５７）。IRETDにて処理を完了。図１５には、RETN命令が実行されるときの処理を示している。RETN命令の実行が開始されると（ステップ３００）、RETN命令に割り与えられたスタックメモリのスタックセグメント（CS）のアドレスを取得する（ステップ３０１）。そして、RETN命令で指定されたリターンアドレスのスタックポイントを取得する（ステップ３０２）。その後、スタックメモリからリターンアドレスを取得する（ステップ３０３）。このときのプログラムコードは次のようになる。
【００７４】
0004518564.tif 000014
【００７５】
そして、スタックレコーダからリターンアドレスと同じ値があるかを検索する（ステップ３０４）。リターンアドレスは、このRETN命令に対応するCALL命令のときにスタックレコーダに登録されているものである。しかし、リターンアドレスが改ざんされた場合は、スタックレコーダの中から同じアドレスが見つからない。このときは、プロセス中断処理（次のコードのTerminate_VirusCode()）へ移る（ステップ３１０）。同じアドレスが見つかると、スタックレコーダから１レコードを削除（ステップ３０５）する。このときのプログラムコードは次のようになる。
【００７６】
0004518564.tif 000015
【００７７】
そして、MSRとEFLAGを設定して命令トレースを再開する（ステップ３０６、３０７）。IRETDにて処理を完了。
図１６には、JMP ESP処理が実行されるときの処理を示している。JMP ESPは、例えばネットワークを経由して侵入するウィルス等がスタックメモリ上のプログラムコードを実行するために必要な命令である。そのためスタックのリターンアドレスの検索結果に依存することなく、JMPESP命令を使用する実行モジュールは稀であるため禁止対象としてある。JMP ESPが判別すると、プロセス中断処理を行う（ステップ３５１）。
ステップ２６０、３１０、３５１のプロセス中断処理は、RET、RETN命令の次に実行される命令のアドレスを取得し、そこを不正な命令（INT3等）に書き換える。プロセスの実行を継続させ、不正な命令でプロセスを停止させる。このときのプログラムコードは次のようになる。
【００７８】
0004518564.tif 000016
【００７９】
上述したように、バッファオーバーフローを利用した不正侵入、攻撃はすべて把握し、対処することができる。実行しているプロセスを停止して、プログラムの暴走を止めることができる。このような方法でバッファオーバーフローを実現可能な、すべてのオペレーティングシステムにも適応可能である。
【産業上の利用可能性】
【００８０】
本発明は、コンピュータウィルス対策、外部からの不正侵入の防止、セキュリティが要求される分野のすべてに利用される。特に、ネットワークに接続して利用されるパソコン、スーパーコンピュータ、サーバを利用したシステムに利用してよい。個人情報保護、電子ファイルのセキュリティが要求される電子政府、軍事、防衛関連のシステムに用いられる。また、プログラムの欠陥、不正コードの利用を検知するとき利用すると良い。
【図面の簡単な説明】
【００８１】
【図１】図１は、本発明の概要を図示している概念図である。
【図２】図２は、本発明のバッファオーバーフローによるエラー検出を示す概念図である。
【図３】図３は、実行ファイルのロード時の手順を示すフローチャートである。
【図４】図４は、実行ファイルの実行時の手順を示すフローチャートである
【図５】図５は、メモリの構造を示す図である。
【図６】図６は、プログラムのメインルーチン、サブルーチンを例示した図ある。
【図７】図７は、スタックメモリの構造を示す図ある。
【図８】図８は、ドライバウェアが起動するときの初期化処理の手順を示すフローチャートである。
【図９】図９は、プロセス生成コールバックの登録の手順を示すフローチャートである。
【図１０】図１０は、スレッド生成イベントのフック設定の手順を示しているフローチャートである。
【図１１】図１１は、CALL、RET等の分岐命令をトレースしているときの処理の流れを示すフローチャートである。
【図１２】図１２は、図１１のCALLorJMP処理の処理手順を示すフローチャートである。
【図１３】図１３は、CALL命令が実行されるときの処理を示すフローチャートである。
【図１４】図１４は、RET命令が実行されるときの処理を示すフローチャートである。
【図１５】図１５は、RET命令が実行されるときの処理を示すフローチャートである。
【図１６】図１６は、JMP ESP処理の手順を示すフローチャートである。
【符号の説明】
【００８２】
１…ソフトウェア
２…ドライバウェア
３…ファイルシステムドライバ
４…ハードディスク
５…実行可能ファイル
６…メモリ
１０…ネットワークカード
１１…ＮＤＩＳ
１２…Ｗｉｎｓｏｃｋ
【図１】
0004518564.tif 000017
【図２】
0004518564.tif 000018
【図３】
0004518564.tif 000019
【図４】
0004518564.tif 000020
【図５】
0004518564.tif 000021
【図６】
0004518564.tif 000022
【図７】
0004518564.tif 000023
【図８】
0004518564.tif 000024
【図９】
0004518564.tif 000025
【図１０】
0004518564.tif 000026
【図１１】
0004518564.tif 000027
【図１２】
0004518564.tif 000028
【図１３】
0004518564.tif 000029
【図１４】
0004518564.tif 000030
【図１５】
0004518564.tif 000031
【図１６】
0004518564.tif 000032