(57)【特許請求の範囲】
【請求項１】
コンピュータのメモリの状態を記録したメモリダンプから、前記コンピュータで動作していたアプリケーションのコールスタックを取得するコールスタック取得装置であって、
前記メモリダンプから、前記コールスタックの作成対象となるスレッドの所属するプロセスのメモリ空間を再現するメモリ空間再現部と、
前記再現されたメモリ空間から、メモリに保存された前記スレッドのレジスタ情報を、前記スレッドの実行コンテキストとして取得する実行コンテキスト取得部と、
前記取得した前記スレッドの実行コンテキストに含まれるスタックポインタから、現在のスタックの位置を取得するスタック位置取得部と、
前記取得した実行コンテキストに含まれる現在実行中の命令ポインタから、現在実行中の関数を取得する関数取得部と、
前記メモリ空間に含まれる実行ファイルに埋め込まれたメタデータを解釈することにより、前記現在実行中の関数が使用するスタックの幅を取得し、前記取得したスタックの幅に基づき、スタック上の戻りアドレスを取得することで、前記現在実行中の関数の呼び出し元関数を特定し、前記特定した呼び出し元関数を現在実行中の関数として前記メタデータの解釈に基づく戻りアドレス取得を繰り返し行うことにより、前記現在実行中の関数の呼び出し元となる一連の関数を特定し、前記特定した一連の関数を示すコールスタックを取得するスタック取得部と
を備えることを特徴とするコールスタック取得装置。
【請求項２】
前記スレッドのレジスタ情報は、
前記スレッドの動作中にＯＳ（Operating  System）がメモリに保存したレジスタ情報である
ことを特徴とする請求項１に記載のコールスタック取得装置。
【請求項３】
前記実行ファイルに埋め込まれたメタデータは、
前記実行ファイルに埋め込まれた例外処理用データのうち、前記実行ファイルで用いられる関数のスタックの巻き戻しのための情報である
ことを特徴とする請求項１に記載のコールスタック取得装置。
【請求項４】
コンピュータのメモリの状態を記録したメモリダンプから、前記コンピュータで動作していたアプリケーションのコールスタックを取得するコールスタック取得方法であって、
前記メモリダンプから、前記コールスタックの作成対象となるスレッドの所属するプロセスのメモリ空間を再現するステップと、
前記再現されたメモリ空間から、メモリに保存された前記スレッドのレジスタ情報を、前記スレッドの実行コンテキストとして取得するステップと、
前記取得した前記スレッドの実行コンテキストに含まれるスタックポインタから、現在のスタックの位置を取得するステップと、
前記取得した実行コンテキストに含まれる現在実行中の命令ポインタから、現在実行中の関数を取得するステップと、
前記メモリ空間に含まれる実行ファイルに埋め込まれたメタデータを解釈することにより、前記現在実行中の関数が使用するスタックの幅を取得し、前記取得したスタックの幅に基づき、スタック上の戻りアドレスを取得することで、前記現在実行中の関数の呼び出し元関数を特定し、前記特定した呼び出し元関数を現在実行中の関数として前記メタデータの解釈に基づく戻りアドレス取得を繰り返し行うことにより、前記現在実行中の関数の呼び出し元となる一連の関数を特定し、前記特定した一連の関数を示すコールスタックを取得するステップと
をコールスタック取得装置が実行することを特徴とするコールスタック取得方法。
【請求項５】
コンピュータのメモリの状態を記録したメモリダンプから、前記コンピュータで動作していたアプリケーションのコールスタックを取得するためのコールスタック取得プログラムであって、
前記メモリダンプから、前記コールスタックの作成対象となるスレッドの所属するプロセスのメモリ空間を再現するステップと、
前記再現されたメモリ空間から、メモリに保存された前記スレッドのレジスタ情報を、前記スレッドの実行コンテキストとして取得するステップと、
前記取得した前記スレッドの実行コンテキストに含まれるスタックポインタから、現在のスタックの位置を取得するステップと、
前記取得した実行コンテキストに含まれる現在実行中の命令ポインタから、現在実行中の関数を取得するステップと、
前記メモリ空間に含まれる実行ファイルに埋め込まれたメタデータを解釈することにより、前記現在実行中の関数が使用するスタックの幅を取得し、前記取得したスタックの幅に基づき、スタック上の戻りアドレスを取得することで、前記現在実行中の関数の呼び出し元関数を特定し、前記特定した呼び出し元関数を現在実行中の関数として前記メタデータの解釈に基づく戻りアドレス取得を繰り返し行うことにより、前記現在実行中の関数の呼び出し元となる一連の関数を特定し、前記特定した一連の関数を示すコールスタックを取得するステップと
をコンピュータに実行させるためのコールスタック取得プログラム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、コールスタック取得装置、コールスタック取得方法、および、コールスタック取得プログラムに関する。
【背景技術】
【０００２】
コンピュータとインターネットの普及に伴い、サイバー攻撃もまた高度化・多様化している。特定組織を狙った標的型攻撃では未知のコンピュータウイルス（マルウェア）が用いられることも多く、未然に防ぐことが難しくなっている。そのため、攻撃を受けた後に、原因の特定や被害の最小化等の対応を迅速に行うことが求められている。【０００３】
こうした対応を行うインシデントレスポンスで行われる手法の１つにメモリフォレンジックスと呼ばれる被害端末のメモリ解析がある。コンピュータは、実行する命令（コード）や使用するデータをメモリ上に保存しながら動作する。そのため、メモリには、動いていたアプリケーションの状態、開かれていたファイル、レジストリ等のリソース、実行していたコードや読み書きしたデータ、通信先や送受信データ等、その瞬間の実行状態（動作状態）が含まれている。したがって、メモリに残ったデータを解析することで、そのときに何が起こっていたか把握することができる。【０００４】
しかし、既存のメモリフォレンジックス技術では、動作していた個々のアプリケーションが、具体的にどのような動作をしていたか等を知ることは難しい。アプリケーションの動作状態を知る方法として、例えば、プログラムのデバッグ等で利用されているスタックトレースと呼ばれる技術がある。アプリケーションを実行するスレッドは、各々スタックと呼ばれるデータ領域を持ち、関数が呼び出されるたびに呼び出し元を示すアドレス（戻りアドレス）がスタックに積まれる。スタックに積まれた戻りアドレスは、呼び出された関数の処理を終了する際に、呼び出し元関数へ戻るために利用され、破棄される。スタックトレースは、スタックの構造を解析し、保持されている戻りアドレスを取得していくことで、その時点での関数呼び出しの入れ子状態（コールスタック）を明らかにする。したがって、アプリケーションを実行していた各スレッドに対し、メモリダンプからスタックトレースと同等の結果が得られれば、アプリケーションの動作状態の把握が可能になると考えられる。【０００５】
一般的なスタックトレースは、スタック内に保存されたフレームポインタ（もしくはベースポインタ）を辿ることで戻りアドレスを取得する。スタックには、戻りアドレスだけでなく、関数が使用するデータも保持している。フレームポインタは、スタックの先頭を示すスタックポインタとは別に、現在実行中の関数が使用する、スタック内のデータ領域を示している。一般的な関数は、最初にスタックに呼び出し元が使用していたフレームポインタの値を積み、その位置を自身のフレームポインタとして設定する。【０００６】
具体的には、図１に示すように、スタックにはフレームポインタが示す位置に、呼び出し元の関数が使用していたフレームポインタが存在し、その１つ前のエントリに呼び出し元への戻りアドレスが格納されている。そのため、現在のフレームポインタの値から、前のフレームポインタと戻りアドレスの取得を繰り返していくことでスタック内の戻りアドレスを取得できる。
【先行技術文献】
【非特許文献】
【０００７】
【非特許文献１】S.M.Hejazi，et  al.,  “Extraction  of  Forensically  Sensitive  Information  from  Windows  Physical  Memory”,  Digital  Investigation  6,  Supplement,  S121-S131,  2009
【非特許文献２】A.R.Arasteh，et  al.,  “Forensic  Memory  Analysis:  From  Stack  and  Code  to  Execution  History”,  Digital  Investigation  4,  Supplement,  S114-S125,  2007
【発明の概要】
【発明が解決しようとする課題】
【０００８】
ここで、スタックトレースをメモリフォレンジックスに適用するためには、メモリダンプのみから、（１）実行コンテキストの取得と、（２）スタック内の戻りアドレスの取得とを行うことが必要となる。【０００９】
しかし、障害発生時の状態等を付加されている特殊なメモリダンプ（クラッシュダンプ、コアダンプ）を除き、一般的なメモリダンプは実行コンテキストを持たない。すなわち、一般的なメモリダンプは、スタック領域の位置やフレームポインタの値、実行していたコードのアドレス等を取得できない。【００１０】
また、フレームポインタは関数の実行に不可欠なものではないため、コンパイラの最適化によってフレームポインタを使わない実行ファイルが存在する。さらに、64ビット版Windows（登録商標）等、実行環境全体としてフレームポインタを使用しないことを前提としているものも存在する。このようにフレームポインタが使われない場合、前述のようなスタック内のフレームポインタを辿って戻りアドレスを取得していくことはできない。【００１１】
ここで、既存技術として非特許文献１や非特許文献２に記載される技術があるが、フレームポインタを使わない実行環境へは適用できない。また、フレームポインタを使わない実行環境ファイルへの対策として、スタック内の戻りアドレスをスキャンにより見つけることで（２）スタック内の戻りアドレスの取得を行う手法も提案されている。当該手法は、（１）実行コンテキストの取得によりスタックの位置が特定できていればフレームポインタを使用しているか否かに変わらず使用可能であるが、戻りアドレスでない関数ポインタ等を誤検知する可能性があるという問題がある。【００１２】
以上から、既存技術では、フレームポインタを使用しないことを前提とした環境に対して、（１）実行コンテキストの取得を実現できず、（２）スタック内の戻りアドレスの取得についても誤検知する可能性があった。そのため、フレームポインタを使用しないことを前提とした環境では、メモリダンプから、アプリケーションの動作状態を示すコールスタックを取得することができない可能性があった。【００１３】
そこで、本発明は、前記した問題を解決し、フレームポインタを使用しないことを前提とした環境であっても、メモリダンプから、アプリケーションの動作状態を示すコールスタックを取得することを課題とする。
【課題を解決するための手段】
【００１４】
前記した課題を解決するため、本発明は、コンピュータのメモリの状態を記録したメモリダンプから、前記コンピュータで動作していたアプリケーションのコールスタックを取得するコールスタック取得装置であって、前記メモリダンプから、前記コールスタックの作成対象となるスレッドの所属するプロセスのメモリ空間を再現するメモリ空間再現部と、前記再現されたメモリ空間から、メモリに保存された前記スレッドのレジスタ情報を、前記スレッドの実行コンテキストとして取得する実行コンテキスト取得部と、前記取得した前記スレッドの実行コンテキストに含まれるスタックポインタから、現在のスタックの位置を取得するスタック位置取得部と、前記取得した実行コンテキストに含まれる現在実行中の命令ポインタから、現在実行中の関数を取得する関数取得部と、前記メモリ空間に含まれる実行ファイルに埋め込まれたメタデータを解釈することにより、前記現在実行中の関数が使用するスタックの幅を取得し、前記取得したスタックの幅に基づき、スタック上の戻りアドレスを取得することで、前記現在実行中の関数の呼び出し元関数を特定し、前記特定した呼び出し元関数を現在実行中の関数として前記メタデータの解釈に基づく戻りアドレス取得を繰り返し行うことにより、前記現在実行中の関数の呼び出し元となる一連の関数を特定し、前記特定した一連の関数を示すコールスタックを取得するスタック取得部とを備えることを特徴とする。
【発明の効果】
【００１５】
本発明によれば、フレームポインタを使用しないことを前提とした環境であっても、メモリダンプから、アプリケーションの動作状態を示すコールスタックを取得することができる。
【図面の簡単な説明】
【００１６】
【図１】図１は、フレームポインタが使われている場合のスタックの構造を説明する図である。
【図２】図２は、本実施形態のコールスタック取得装置の構成例および動作概要を説明する図である。
【図３】図３は、ETHREAD構造体とKTRAP_FRAME構造体との関係を説明する図である。
【図４】図４は、図２のスタックトレース部が用いる実行コンテキストとPE32+ファイルの一例を示す図である。
【図５】図５は、図２のコールスタック取得装置の処理手順を示すフローチャートである。
【図６】図６は、図５のＳ６の処理における、メモリダンプに含まれる実行ファイル（例えば、PE32+形式の実行ファイル）のメタデータの解釈により、現在実行中の関数の呼び出し元となる一連の関数それぞれに対応する戻りアドレスを取得する処理を詳細に示すフローチャートである。
【図７】図７は、図２のコールスタック取得装置の適用例を示す図である。
【図８】図８は、コールスタック取得プログラムを実行するコンピュータを示す図である。
【発明を実施するための形態】
【００１７】
以下、図面を参照しながら、本発明を実施するための形態（実施形態）について説明する。本発明は本実施形態に限定されない。
【００１８】
［概要］
本実施形態のコールスタック取得装置１０（図２参照）は、メモリダンプと、スレッドＩＤ（コールスタックの取得対象となるスレッドのスレッドＩＤ）との入力を受け付けると、当該スレッドＩＤの実行コンテキストを収集し、アプリケーションの動作状態を示すコールスタックの取得を行う。
【００１９】
なお、メモリダンプは、コンピュータのメモリの状態を記録したものであり、例えば、物理メモリダンプ、仮想メモリダンプ、実行中のコンピュータのライブメモリ、コンピュータ休止時に作成される状態保存データ、仮想マシンのサスペンドデータやスナップショット等があるが、本実施形態のコールスタック取得装置１０は、メモリダンプの種類やその取得方法に影響を受けない。また、コールスタック取得装置１０は、メモリダンプ取得時において、実行状態やデータ構造参照用データ等を特別に付加するような特殊なツールや機能も必要としない。つまり、コールスタック取得装置１０は、コンピュータの障害時情報等の付加情報がメモリダンプに含まれていない場合であっても、コールスタックを取得することができる。
【００２０】
また、以下では、コールスタック取得装置１０が、64ビット版Windows環境のメモリダンプ中に含まれる64ビットアプリケーションを対象に処理を行う場合を例に説明するが、他のＯＳ（Operating  System）環境のメモリダンプを対象に処理を行ってもよい。
【００２１】
［構成］
図２を用いてコールスタック取得装置１０の構成例を説明する。コールスタック取得装置１０は、例えば、メモリダンプと、スレッドＩＤとを入力とし、入力されたスレッドＩＤのスレッドのコールスタックを取得し、出力する。
【００２２】
コールスタック取得装置１０は、準備部（メモリ空間再現部）１１と、実行コンテキスト取得部１２と、スタックトレース部１３とを備える。
【００２３】
準備部１１は、メモリダンプと、スレッドＩＤとを入力とし、メモリダンプから、当該スレッドＩＤのスレッドの所属するプロセスの仮想メモリ空間の再現と、当該スレッドの管理データ（スレッドオブジェクト）の取得とを行う。
【００２４】
実行コンテキスト取得部１２は、準備部１１により取得された仮想メモリ空間とスレッド（スレッドオブジェクト）とを入力とし、スレッドに対して仮想メモリ空間から実行コンテキストの取得を行う。
【００２５】
スタックトレース部１３（スタック位置取得部、関数取得部、スタック取得部）は、準備部１１により取得されたスレッドおよび再現された仮想メモリ空間と、実行コンテキスト取得部１２により取得された実行コンテキストとを入力とし、当該スレッドのスタック内から各関数への戻りアドレスを取得することでコールスタックを取得し、出力する。
【００２６】
例えば、アプリケーションを実行しているスレッドの１つが、mainからfuncA、funcAからfuncB、funcBからfuncC、という順に関数を呼び出す動作を行っていた場合、スタックトレース部１３は、これらの関数を順に積み上げたコールスタック（図２参照）を取得し、出力する。
【００２７】
なお、コールスタック取得装置１０は、スレッドの識別に、スレッドＩＤを用いているが、スレッド管理データの仮想アドレスや物理アドレス等を用いてもよい。
【００２８】
次に、準備部１１を詳細に説明する。準備部１１は、以下の（１）および（２）を行う。（１）メモリダンプから、仮想メモリ空間を再現する。（２）メモリダンプに含まれるスレッドオブジェクトを列挙し、指定されたスレッドＩＤに対応するスレッドオブジェクトを取得する。
【００２９】
（１）では、準備部１１は、例えば、メモリダンプに含まれるカーネルや各プロセスに対応したページテーブルを検出し、そのデータを解釈することで仮想メモリ空間を再現する。なお、メモリダンプが仮想メモリダンプの場合、メモリダンプ自体が仮想メモリ空間であるため、再現は不要である。
【００３０】
（２）では、準備部１１は、例えば、プロセスオブジェクト（EPROCESS構造体）が持つスレッドのリストや、シグネチャスキャン等により、指定されたスレッドＩＤに対応するスレッドオブジェクトを取得する。
【００３１】
なお、上記の（１）および（２）の処理は、例えば、以下の文献に記載される技術を用いて実行される。
【００３２】
Michael  Hale  Ligh,  et  al.,  “The  Art  of  Memory  Forensics:  Detecting  Malware  and  Threats  in  Windows,  Linux,  and  Mac  Memory,  Linux,  and  Mac  Memory”,  Wiley  Publishing，  2014
【００３３】
準備部１１が、プロセスオブジェクト（EPROCESS構造体）の持つスレッドのリストを用いる場合、まず、カーネルが持つプロセスリストを辿り、対象のスレッドの所属するプロセスを示すEPROCESS構造体を取得する。ここで、EPROCESS構造体のThreadListHeadメンバにスレッドのリストが保持されているので、準備部１１は、このリストを探索することで、対象のスレッドＩＤに対応するスレッドオブジェクト（ETHREAD構造体）を列挙できる。
【００３４】
また、準備部１１が、シグネチャスキャンを行う場合、ETHREAD構造体が持つ値の特徴をシグネチャ化し、物理アドレス空間もしくは仮想アドレス空間をスキャンし、当該ETHREAD構造体を発見する。
【００３５】
次に、実行コンテキスト取得部１２を詳細に説明する。実行コンテキスト取得部１２は、まず、準備部１１が取得したスレッドオブジェクトから、当該スレッドオブジェクトが保持する実行コンテキストを取得する。
【００３６】
Windowsでは、システムコールの発行や割り込みが発生した場合、例えば、メモリ内のKTRAP_FRAMEと呼ばれる構造体にこれまで使用されていたレジスタの値を保存する。図３に示す通り、ETHREAD構造体内のTcb.TrapFrameメンバに、KTRAP_FRAME構造体のポインタが保持されている。したがって、準備部１１が取得したスレッドオブジェクト、すなわち、ETHREAD構造体から上記の構造を辿ることで各種レジスタの値を取得することができる。
【００３７】
なお、本実施形態では、実行コンテキスト取得部１２が実行コンテキストを取得する際、KTRAP_FRAME構造体を用いる場合について説明したが、スレッドの実行コンテキストすべてもしくは一部を保持するデータ構造なら、KTRAP_FRAME構造体以外の構造体を用いてもよい。例えば、下記が挙げられる。
【００３８】
例えば、ＯＳがWindowsの場合、KTRAP_FRAME構造体、CONTEXT構造体、WOW64_CONTEXT構造体、KTHREAD/ETHREAD構造体、KPCR/KPRCB構造体、TEB/NT_TIB構造体、USER_STACK構造体、KPROCESSOR_STATE構造体、KNONVOLATILE_CONTEXT_POINTERS構造体等を用いてもよい。また、ＯＳがLinux（登録商標）の場合、thread_info構造体、thread_struct構造体、pt_regs構造体、task_struct構造体、sigcontext構造体等を用いてもよい。さらに、jmp_buf構造体、スタック等を用いてもよい。
【００３９】
次に、スタックトレース部１３は、準備部１１により作成されたスレッドおよび仮想メモリ空間と、実行コンテキスト取得部１２により取得された実行コンテキストとを入力として、当該スレッドのスタックから戻りアドレスを取得することでコールスタックを取得し、出力する。
【００４０】
具体的には、スタックトレース部１３は、下記のステップ（Ａ）およびステップ（Ｂ）を実行した後、ステップ（Ｃ）を繰り返し実行することによりスタックから取得されたすべての戻りアドレスを取得する。ここでは、スタックトレース部１３は、ステップ（Ａ）〜ステップ（Ｃ）の処理を、図４に例示する実行コンテキストと、実行ファイル（PE32+ファイル）とを用いて実行する場合を例に説明する。
【００４１】
この実行コンテキストは、図４に示すように、ＲＳＰレジスタ、ＲＩＰレジスタ、各種レジスタを含む。また、PE32+ファイルは、PEヘッダ、Exception  Directory（例外処理用データのディレクトリ）、.text  セクション等を含む。この例外処理用データは、例外処理においてスタックの巻き戻し（すなわち、関数呼び出しの巻き戻し）に必要な情報（UNWIND_INFO、アンワインド情報）を含む。
【００４２】
ステップ（Ａ）：スタックトレース部１３は、実行コンテキスト取得部１２により取得されたスレッドの実行コンテキストに含まれるスタックポインタ（ＲＳＰレジスタ）から、現在のスタックの位置(上限)を取得する。
【００４３】
ステップ（Ｂ）：スタックトレース部１３は、実行コンテキスト取得部１２により取得されたスレッドの実行コンテキストに含まれる現在実行中の命令ポインタ（ＲＩＰレジスタ）から、現在実行中の命令（関数）の位置を取得する。これにより、スタックトレース部１３は、現在実行中の関数を取得することができる。
【００４４】
ステップ（Ｃ）：スタックトレース部１３は、例えば、PE32+形式の実行ファイル（図４参照）が持つ例外処理用データを解釈し、ステップ（Ｂ）で取得された現在実行中の関数が使用するスタックの幅を特定し、ステップ（Ａ）で取得した現在のスタックの位置から、特定したスタックの幅分スタックポインタを巻き戻した位置に存在する戻りアドレスを取得することで、現在実行中の関数の呼び出し元の関数を特定する。
【００４５】
すなわち、ステップ（Ｃ）において、スタックトレース部１３は、仮想メモリ空間に含まれる実行ファイルに埋め込まれたメタデータに基づく関数が使用するスタックの幅の特定と、特定した幅に基づいた戻りアドレス取得とを繰り返し行う。これにより、スタックトレース部１３は、現在のスタックの位置から、現在実行中の関数の呼び出し元となる一連の関数を辿ることができる。そして、スタックトレース部１３は、現在実行中の関数の呼び出し元となる一連の関数に対応する戻りアドレスを、当該関数が呼び出された順に積み上げたコールスタックを取得する。
【００４６】
このステップ（Ｃ）において、スタックトレース部１３は、例えば、PE32+ファイルの持つ例外処理用データのうち、各関数に対応したスタック巻き戻しのための情報（アンワインド情報）、すなわち、RUNTIME_FUNCTION構造体、UNWIND_INFO構造体、UNWIND_CODE構造体を解釈する。
【００４７】
このRUNTIME_FUNCTION構造体は、関数の情報、具体的には、関数の範囲と対応するUNWIND_INFO構造体へのRVA（相対仮想アドレス）を持つ。
【００４８】
UNWIND_INFO構造体は、スタックの巻き戻しに必要な情報を持つ。UNWIND_CODE構造体は、スタックの確保に関連した動作を示すオペレーションコードと、それに付随する情報を持つ。具体的なオペレーションコードとして、例えば、不揮発性整数レジスタをスタックにプッシュすることを示すUWOP_PUSH_NONVOL、スタック上に領域を確保することを示すUWOP_ALLOC_SMALL、UWOP_ALLOC_LARGE等がある。UNWIND_INFO構造体は、関数で行われるスタックを確保する処理の情報として、UNWIND_CODE構造体の配列を持っている。
【００４９】
スタックトレース部１３は、これらのメタデータを解釈することでスタックの巻き戻しをエミュレーションし、戻りアドレスを取得することでコールスタックを取得する。このコールスタックの取得手順の詳細は後記する。
【００５０】
以上説明したコールスタック取得装置１０によれば、フレームポインタを使用しないことを前提とした環境であっても、メモリダンプから、アプリケーションの動作状態を示すコールスタックを取得することができる。
【００５１】
［処理手順］
次に、図５を用いて、コールスタック取得装置１０の処理手順の例を説明する。なお、コールスタック取得装置１０は、メモリダンプと、スレッドＩＤ（コールスタックの取得対象となるスレッドのスレッドＩＤ）との入力を受け付け済みであるものとする。また、実行ファイルは、PE32+形式の実行ファイルである場合を例に説明する。
【００５２】
コールスタック取得装置１０の準備部１１は、メモリダンプから仮想メモリ空間を再現し（Ｓ１）、また、メモリダンプから、指定されたスレッドＩＤに対応するスレッドオブジェクトを取得する（Ｓ２）。次に、実行コンテキスト取得部１２は、仮想メモリ空間から、スレッドオブジェクトが保持する各種レジスタの値を当該スレッドの実行コンテキストとして取得する（Ｓ３）。
【００５３】
Ｓ３の後、スタックトレース部１３は、Ｓ３で取得した実行コンテキストに含まれるスタックポインタから、現在のスタックの位置を取得し（Ｓ４）、Ｓ３で取得した実行コンテキストに含まれる現在実行中の命令ポインタから、現在実行中の関数を取得する（Ｓ５）。その後、スタックトレース部１３は、メモリダンプに含まれるPE32+形式の実行ファイルのメタデータを解釈することによって、現在実行中の関数の呼び出し元となる一連の関数それぞれに対応する戻りアドレスを取得し、コールスタックを取得する（Ｓ６）。そして、スタックトレース部１３は、取得したコールスタックを出力する。
【００５４】
ここで、図５のＳ６の処理における、メモリダンプに含まれる実行ファイルのメタデータの解釈により、現在実行中の関数の呼び出し元となる一連の関数それぞれに対応する戻りアドレスを取得する処理について、図６を用いて詳細に説明する。ここでも、実行ファイルは、PE32+形式の実行ファイルである場合を例に説明する。
【００５５】
まず、スタックトレース部１３は、プロセスオブジェクト（EPROCESS構造体）が持つメモリマップ管理データ構造であるVADツリーを参照し、RIPが示すアドレスを含む連続したメモリ領域のベースアドレスを特定する（Ｓ６０１）。このVADツリーの参照方法は、例えば、以下の文献に記載される方法を用いる。
【００５６】
Brendan  Dolan-Gavitt,“The  VAD  Tree:  A  Process-Eye  View  of  Physical  Memory”，  Digital  Investigation  4,  Supplement,  S62-S64,  Sep  2007
【００５７】
Ｓ６０１の後、スタックトレース部１３は、Ｓ６０１で特定したメモリ領域の先頭のPEヘッダのシグネチャの有無を確認し、PE32+形式の実行ファイルやDLL（Dynamic  Link  Library）が存在することを確認する（Ｓ６０２）。
【００５８】
Ｓ６０２で、スタックトレース部１３は、PEヘッダのシグネチャの有無を確認し、PE32+形式の実行ファイルやDLLが存在することが確認できると（Ｓ６０３でＹｅｓ）、PEヘッダを解釈することで、Exception  Directory（IMAGE_DIRECTORY_ENTRY_EXCEPTION）のRVAを取得し、Exception  Directoryがロードされている仮想アドレスを算出する（Ｓ６０４）。
【００５９】
Ｓ６０４の後、スタックトレース部１３は、Ｓ６０４で算出された仮想アドレスにロードされているException  Directory（.pdataセクション）に含まれるRUNTIME_FUNCTION構造体の配列からRIPに対応するものを取得する（Ｓ６０５）。
【００６０】
Ｓ６０５の後、スタックトレース部１３は、Ｓ６０５で取得したRUNTIME_FUNCTION構造体のUnwindDataメンバからUNWIND_INFO構造体の仮想アドレスを算出し、UNWIND_INFO構造体を取得する（Ｓ６０６）。
【００６１】
Ｓ６０６の後、スタックトレース部１３は、Ｓ６０６で取得したUNWIND_INFO構造体に含まれるUNWIND_CODE構造体の配列を解釈し、UNWIND_CODE構造体それぞれに対応する処理を行うことで、スタックポインタの巻き戻し（RSPの更新）とスタックに退避されていた各種レジスタの値の復元とを行う（Ｓ６０７）。
【００６２】
なお、スタックトレース部１３は、Ｓ６０６で取得したアンワインド情報（UNWIND_INFO構造体に示される情報）が他のアンワインド情報を参照している場合（Ｓ６０８でＹｅｓ）、参照している他のアンワインド情報のUNWIND_INFO構造体についてＳ６０６の処理を実行し、取得したUNWIND_INFO構造体に対しＳ６０７の処理を実行する。
【００６３】
一方、Ｓ６０８において、スタックトレース部１３が、Ｓ６０６で取得したアンワインド情報（UNWIND_INFO構造体に示される情報）が他のアンワインド情報を参照していない場合（Ｓ６０８でＮｏ）、Ｓ６０７での巻き戻し後のRSPの示す位置に存在するデータを戻りアドレスとして取得し、RSPを１エントリ分巻き戻し、取得した戻りアドレスの値でRIPを更新する（Ｓ６０９）。つまり、スタックトレース部１３は、現在実行中の命令の位置（ポインタ）を、１つ前の関数呼び出しの位置に移動させる。そして、スタックトレース部１３は、Ｓ６０９による更新後のRSPがスタックの底（下限)に到達するまで、Ｓ６０９による更新後のRIPを対象に、Ｓ６０１以降の処理を繰り返し実行する。つまり、スタックトレース部１３は、Ｓ６０９による更新後のRSPがスタックの底（下限）に到達しておらず、かつ、戻りアドレスとして取得した値が実行可能領域であれば（Ｓ６１０でＮｏ）、再度Ｓ６０１以降の処理を実行し、Ｓ６０９による更新後のRSPがスタックの底（下限）に到達、または、戻りアドレスとして取得した値が実行可能領域でなければ（Ｓ６１０でＹｅｓ）、処理を終了する。本実施形態では実行コンテキストに含まれるRSPから連続する確保済みのメモリ領域の範囲をスタックの範囲としたが、他の方法で対象にする範囲を指定することも可能である。例えば、ＯＳ等がスタックの範囲を管理している場合はそのデータ構造から取得が可能である。また、入力値として探索する範囲の大きさ等をユーザから指定可能とする方法も考えられる。
【００６４】
なお、Windowsは、動的に生成されたコードでも例外処理をサポートするため、専用の管理テーブル（RtlpDynamicFunctionTable）と登録用API（RtlAddFunctionTable  API等）を用意している。したがって、Ｓ６０３で、スタックトレース部１３が、PEヘッダが確認できなかった場合（Ｓ６０３でＮｏ）であっても、専用の管理テーブル（RtlpDynamicFunctionTable）を参照することで、RUNTIME_FUNCTION構造体を取得することができる。
【００６５】
すなわち、Ｓ６０３で、スタックトレース部１３が、PEヘッダを確認できなかった場合（Ｓ６０３でＮｏ）、スタックトレース部１３は、まず、VADツリーからntdll.dllがロードされているベースアドレスを取得し、シンボル情報と合わせてRtlpDynamicFunctionTableの仮想アドレスを算出する（Ｓ６１１）。そして、スタックトレース部１３は、Ｓ６１１で算出された仮想アドレスにあるRtlpDynamicFunctionTableを参照し、RIPに対応するRUNTIME_FUNCTION構造体を取得する（Ｓ６１２）。その後、スタックトレース部１３は、Ｓ６１２で取得したRUNTIME_FUNCTION構造体を用いて、Ｓ６０６以降の処理を行う。
【００６６】
このようにすることで、スタックトレース部１３は、メモリダンプに含まれる実行ファイルのメタデータ（例えば、PE32+形式の実行ファイルに含まれる例外処理用データや、Windowsが例外処理用に用意する管理テーブル等）を解釈することにより、スレッドが実行していた関数の呼び出し元となる関数が分かる。そして、スタックトレース部１３は、当該関数の呼び出し元となる一連の関数を順に辿ることで、スレッドが実行中であった関数を、呼び出し順に積み上げたコールスタックを取得することができる。
【００６７】
［その他の実施形態］
なお、コールスタック取得装置１０は、コールスタックの作成にあたり、RUNTIME_FUNCTION構造体、UNWIND_INFO構造体、UNWIND_CODE構造体等を用いる場合を例に説明したが、各関数が使用するスタックの幅やスタックの使用方法を特定可能なデータ構造であれば、これらの構造体に限定されない。
【００６８】
例えば、Windowsでは、FPO_DATA構造体、STACKFRAME/STACKFRAME64構造体、EXCEPTION_REGISTRATION_RECORD構造体、EXCEPTION_RECORD構造体、IMAGE_FUNCTION_ENTRY64構造体がある。したがって、コールスタック取得装置１０は、これらの構造体を用いてコールスタックを取得してもよい。また、ELF形式の実行ファイルの場合、コールスタック取得装置１０は、.eh_frameや.debug_frameセクション等に埋め込まれたＣＦＩ（Call  Frame  Information）等のDWARF形式のデバッグ情報を用いて、コールスタックを取得してもよい。
【００６９】
また、本実施形態のコールスタック取得装置１０は、インシデントレスポンス、エンドポイント脅威監視、仮想化基盤による仮想計算機（ＶＭ、Virtual  Machine）の監視等、様々な場面に用いることができる。
【００７０】
［適用例］
例えば、図７の符号７０１に示すように、インシデントレスポンスにコールスタック取得装置１０を用いてもよい。この場合、コールスタック取得装置１０は、被害ＰＣのメモリダンプを解析し、コールスタックを取得する。そして、フォレンジックアナリスト等が、作成されたコールスタックの内容を見ることで、被害ＰＣの被害状況や対策を検討し、インシデントレスポンスを速やかに行うことができる。
【００７１】
また、図７の符号７０２に示すように、脅威監視サーバによる監視対象ＰＣ（エンドポイント）の脅威監視にコールスタック取得装置１０を用いてもよい。この場合、コールスタック取得装置１０は、脅威監視サーバに装備される。そして、脅威監視サーバは、監視Agentにより監視された監視対象ＰＣのメモリの監視データ（メモリダンプ）を取得すると、コールスタック取得装置１０により、メモリダンプを解析し、監視対象ＰＣのコールスタックを取得する。脅威監視サーバは、取得されたコールスタックを分析することで、監視対象ＰＣの動作状態を監視することができる。
【００７２】
さらに、図７の符号７０３に示すように、仮想化基盤による仮想計算機（ＶＭ）の監視にコールスタック取得装置１０を用いてもよい。この場合、コールスタック取得装置１０は、仮想化基盤となるコンピュータに装備される。そして、仮想化基盤となるコンピュータは、自身の内部に構築された各ＶＭのメモリ（仮想化メモリ）を監視し、監視の結果得られた各ＶＭのメモリダンプから各ＶＭのコールスタックを取得する。そして、仮想化基盤となるコンピュータは、各ＶＭのコールスタックを分析することで、各ＶＭの動作状態を監視することができる。
【００７３】
［プログラム］
また、上記の実施形態で述べたコールスタック取得装置１０の機能を実現するプログラムを所望の情報処理装置（コンピュータ）にインストールすることによって実装できる。例えば、パッケージソフトウェアやオンラインソフトウェアとして提供される上記のプログラムを情報処理装置に実行させることにより、情報処理装置をコールスタック取得装置１０として機能させることができる。ここで言う情報処理装置には、デスクトップ型またはノート型のパーソナルコンピュータが含まれる。また、その他にも、情報処理装置にはスマートフォン、携帯電話機やＰＨＳ（Personal  Handyphone  System）等の移動体通信端末、さらには、ＰＤＡ（Personal  Digital  Assistants）等がその範疇に含まれる。また、コールスタック取得装置１０を、クラウドサーバに実装してもよい。
【００７４】
図８を用いて、上記のプログラム（コールスタック取得プログラム）を実行するコンピュータの一例を説明する。図８に示すように、コンピュータ１０００は、例えば、メモリ１０１０と、ＣＰＵ１０２０と、ハードディスクドライブインタフェース１０３０と、ディスクドライブインタフェース１０４０と、シリアルポートインタフェース１０５０と、ビデオアダプタ１０６０と、ネットワークインタフェース１０７０とを有する。これらの各部は、バス１０８０によって接続される。
【００７５】
メモリ１０１０は、ＲＯＭ（Read  Only  Memory）１０１１およびＲＡＭ（Random  Access  Memory）１０１２を含む。ＲＯＭ１０１１は、例えば、ＢＩＯＳ（Basic  Input  Output  System）等のブートプログラムを記憶する。ハードディスクドライブインタフェース１０３０は、ハードディスクドライブ１０９０に接続される。ディスクドライブインタフェース１０４０は、ディスクドライブ１１００に接続される。ディスクドライブ１１００には、例えば、磁気ディスクや光ディスク等の着脱可能な記憶媒体が挿入される。シリアルポートインタフェース１０５０には、例えば、マウス１１１０およびキーボード１１２０が接続される。ビデオアダプタ１０６０には、例えば、ディスプレイ１１３０が接続される。
【００７６】
ここで、図８に示すように、ハードディスクドライブ１０９０は、例えば、ＯＳ１０９１、アプリケーションプログラム１０９２、プログラムモジュール１０９３およびプログラムデータ１０９４を記憶する。前記した実施形態で説明した各種データや情報は、例えばハードディスクドライブ１０９０やメモリ１０１０に記憶される。
【００７７】
そして、ＣＰＵ１０２０が、ハードディスクドライブ１０９０に記憶されたプログラムモジュール１０９３やプログラムデータ１０９４を必要に応じてＲＡＭ１０１２に読み出して、上述した各手順を実行する。
【００７８】
なお、上記のコールスタック取得プログラムに係るプログラムモジュール１０９３やプログラムデータ１０９４は、ハードディスクドライブ１０９０に記憶される場合に限られず、例えば、着脱可能な記憶媒体に記憶されて、ディスクドライブ１１００等を介してＣＰＵ１０２０によって読み出されてもよい。あるいは、上記のプログラムに係るプログラムモジュール１０９３やプログラムデータ１０９４は、ＬＡＮ（Local  Area  Network）やＷＡＮ（Wide  Area  Network）等のネットワークを介して接続された他のコンピュータに記憶され、ネットワークインタフェース１０７０を介してＣＰＵ１０２０によって読み出されてもよい。
【符号の説明】
【００７９】
１０  コールスタック取得装置
１１  準備部
１２  実行コンテキスト取得部
１３  スタックトレース部
【図１】
0006734481.tif 000002
【図２】
0006734481.tif 000003
【図３】
0006734481.tif 000004
【図４】
0006734481.tif 000005
【図５】
0006734481.tif 000006
【図６】
0006734481.tif 000007
【図７】
0006734481.tif 000008
【図８】
0006734481.tif 000009