Top / CodeZine / ハードウェア DEP 機能の調査

ハードウェアDEP機能の調査 (CodeZine)
05.08.03、掲載開始。編集の力とは恐ろしいものですな。ここの原稿よりかなり読みやすいものになっています。

完成図

checknx 本体

Check NX-bit/XD-bit Tools v.0.1 w/src (MD5SUM : 93fcb3cfcdafd19c38c38068f713ceb8)

はじめに

この記事では、Windows XP SP2(XPSP2) より実装された DEP 機能について考察を行います。

今回、デモプログラム(checknx)を作成しました。このプログラムよりどのように DEP 機能が働いているかを確認し、実際にメモリが保護されているかを考察します。

対象読者

  • CPU の働き、特にNX-bit がどのように働くのか興味がある方
  • インラインアセンブラの組み込みに興味がある方

必要な環境

下記の環境が揃わないと面白くありません。Visual C++ version 6 SP6(MFC) で開発を行いましたが、他の開発環境でも簡単に移植できると思っています。

  • NX-bit/XD-bit が有効なシステム
  • Windows XP SP2/Windows Server 2003 SP1
    Windows 2000 以降で動作しますが Windows 2000 には DEP は実装されていません。

データ実行防止(DEP)機能について

ハードウェア DEP 機能

Windows XP SP2(XPSP2)/Windows Server 2003 SP1 よりサポートされた DEP(Data Execution Protections、データ実行防止) 機能というのはご存知でしょうか。

DEP 機能とは、XPSP2 にて新たに追加されたセキュリティ機能で、悪質なプログラムによるバッファ・オーバーラン等の攻撃からシステムを守る働きをします。DEP 機能には、CPU に備わったメモリ保護機能(NX-bit/XD-bit)を利用してるバッファ・オーバーランを検知する「ハードウェア DEP 機能」と、ソフトウェアのみによるバッファ・オーバーランを検知する「ソフトウェア DEP 機能」の2通りがあります。「ソフトウェア DEP 機能」は全てのシステムで適用されますが、「ハードウェア DEP 機能」の場合、CPU 自身が NX-bit/XD-bit という機能を持ち合わせていないと動作しません。

今回は、この NX-bit/XD-bit を使用した「ハードウェア DEP 機能」に焦点を合わせます。

NX-bit/XD-bit

NX-bit(No eXecute) は、AMD 社が搭載したメモリ保護機能で、AMD 社ではこの機能のことを「拡張ウィルス防止機能(Enhanced Virus Protection)」と命名しています。後に Intel 社も同様の機能を搭載していますが、名称は NX-bit ではなくXD-bit (eXecution Disable) と命名しています。機能的には NX-bit、XD-bit 共に同様と考えてよいでしょう。最近では、VIA 社や Transmeta 社の CPU にも NX-bit が採用されています。

NX-bit のメモリ保護機能

NX-bit は、システム上のメモリの実行可能・不可能の種類を示すフラグです。NX-bit が有効な場合、実行不可能なメモリ上でプログラムを実行しようとするとCPU は保護例外を起こし、システムに「ホントに実行していいの?」とお伺いを立てます。システムは保護例外に対し、意図して実行を続けることも出来ますし、その場で例外エラーを発生させることも出来ます。

単純な機能ですが、セキュリティ面でかなり役立つ機能と言われています。

悪質なプログラムの多くは、バッファ・オーバーランというプログラム上のバグを利用してシステムを破壊します。 バッファ・オーバーランは、プログラムを開発する上で 非常に発見しづらく、セキュリティが重要視される今日ですらバッファ・オーバーランによる攻撃が未だに行われています。NX-bit は、このバッファ・オーバーラン攻撃を ハードウェア的に検知し、未然にメモリを保護することを目的として開発されています。

ハードウェア/ソフトウェア DEP 機能の確認方法

以下の手順にて『データ実行防止』タブを開き、適用されている DEP 機能を確認します。

  1. システムのプロパティを開く
    『スタート』→『コントロールパネル』を選択し、コントロール パネル内の『パフォーマンスとメンテナンス』→『システム』を選択します。
  2. データ実行防止を開く
    システムのプロパティ内の『詳細設定』タブを選択し、パフォーマンス内にある『設定(S)』を選択します。パフォーマンス オプション内の『データ実行防止』タブを選択します。
  • ソフトウェア DEP の場合 (A.)
    ダイアログの下に『お使いのコンピュータのプロセッサでは、ハードウェアによる DEP はサポートされません。ただし、DEP ソフトウェアを使用することにより、ある種類の攻撃を阻止することが出来ます。』とのメッセージが表示されます。
    ソフトウェア DEP 機能が有効な場合のダイアログ表示
  • ハードウェア DEP が有効な場合 (B.)
    上記のメッセージは表示されません。見分け方はこの程度で非常に分かり辛いです。
    ハードウェア DEP 機能が有効な場合のダイアログ表示

DEP には以下の2通りあります。デフォルトでは「システム内のモジュールのみ有効(a.)」に設定されています。

  • システム内のモジュールのみに有効(a.)
  • Windows 内のプログラム全部に有効(b.)

上記より DEP には以下の4通りの設定があります。この中では (4) が一番厳しい DEP となります。

  • (1) (A.)-(a.)
  • (2) (A.)-(b.)
  • (3) (B.)-(a.)
  • (4) (B.)-(b.)

checknx によるデモ

ハードウェア DEP 機能の確認を確認するためサンプルプログラム「checknx」を作成しました。以下は Windows XP SP2 上で動作確認を行いました。

結果は以下の通り。

(1) と (2) の場合

1. Is Supported CPUID?           ---> OK
2. Is Supported Extended CPUID?  ---> OK
3. Is Supported NX/XD-bit?       ---> Not supported.
4. Is Supported NX/XD-bit by OS? ---> OK
5. Is Enabled NX/XD-bit by OS?   ---> Disable
6. Is working Hardware DEP?      ---> NOT working...

finish...

(3) の場合

1. Is Supported CPUID?           ---> OK
2. Is Supported Extended CPUID?  ---> OK
3. Is Supported NX/XD-bit?       ---> OK
4. Is Supported NX/XD-bit by OS? ---> OK
5. Is Enabled NX/XD-bit by OS?   ---> Enable
6. Is working Hardware DEP?      ---> NOT working...

finish...

(4) の場合

1. Is Supported CPUID?           ---> OK
2. Is Supported Extended CPUID?  ---> OK
3. Is Supported NX/XD-bit?       ---> OK
4. Is Supported NX/XD-bit by OS? ---> OK
5. Is Enabled NX/XD-bit by OS?   ---> Enable
6. Is working Hardware DEP?      ---> Working!
EXTRA. Try to Execute NX error?  ---> push [Try NX!]

finish...

checknx のアルゴリズム

  1. CPUID(0) が取得できるか?
    取得出来ない場合、該当 CPU か判断できないので終了。
  2. 拡張 CPUID (8000-0000h) が取得できるか?
    取得出来ない場合、NX-bit 機能が実装されていないと判断し終了。
    EAX の値が 8000-0000h 以上で無い場合も終了。これは Intel の拡張 CPUID 使用方法に記載されていた方法です。拡張 CPUID をサポートしていない場合、CPUID の最大 INDEX の値が返却されるのが仕様です。
  3. 拡張 CPUID (8000-0001h) が取得できるか?
    取得出来ない場合、NX-bit 機能が実装されていないと判断し終了。
    NX/XD-bit フラグが立っていない場合、NX-bit 機能が実装されていないと判断しますが継続(Software DEP 対応)。
  4. サポート OS かどうか?
    XPSP2 以降、もしくは w2k3SP1 以降で無い場合、DEP サポート OS ではないと判断し終了。
  5. NX-bit が有効かどうか?
    MSR(0xC0000080) の 11bit 目が立っている場合、NX-bit が働いていると判断し継続。 立っていない場合、NX-bit が働いていないと判断するが継続。
    RDMSR が実行出来なかった場合、取り敢えず継続。
  6. メモリ保護が行われているか?
    動的に取得した実行可能なメモリ上で実行を行い、問題が無ければメモリを実行不許可に変更し、再度実行を試みます。実行不許可にしたメモリ上で実行した時に保護エラーが発生した場合、メモリ保護が働いていると判断しました。
  7. EXTRA. 実際にメモリ保護が行われるダイアログでも見ますか =)
    6. の時点でメモリ保護が有効だった場合、実際にメモリ保護ダイアログを見るためのソフトウェアを用意しました(checknx 自身がエラーを出力するのは嫌なので)。
    『TRY NX!』ボタンが有効になっているはずなので押してみてください。以下のダイアログが表示されていればめでたく一般アプリケーションのメモリ保護エラーを拾える設定になっていることが確認できます。
    その後、見慣れた「問題が発生したため、、、」ダイアログが表示されます。『エラー報告を送信する(S)』を送っても何ら改善される余地はありませんので『送信しない(D)』を選択してくださいね =)。
データ実行防止エラーダイアログ

checknx の要点

CPUID 命令

CPUID(CPU Identification) 命令は i386 系の CPU より追加された命令です。この命令を実行することで使用している CPU の詳細情報を取得できます。例えば SSE 命令をサポートしているかどうかを CPUID 命令から取得し、サポートしている CPU ならば SSE 専用の高速化ライブラリを使用するというような切り分けに用いられます。

今回は NX-bit をサポートしているかどうかの確認のため使用します。

RDMSR 命令

RDMSR/WRMSR 命令は Pentium Pro より追加された命令です。この命令を実行することで CPU 内の MSR(Model-Specific Register)を読み書きすることが出来ます。一般的に MSR は CPU の動作を変更させることの出来る重要なレジスターであることより、特権レベルでないと読み書きできません。

今回は、実際に NX-bit によるメモリ保護を行っているかの確認に使用します。

SEH

SEH (Structured Exception Handling, 構造化例外処理) は Windows に標準で実装されているシステムレベルの例外処理です。今回は SEH を用いて CPUID 命令を直接実行しています。本来ならシステムが CPUID 命令をサポートしているか複雑な手順で確認してから CPUID 命令を実行する必要があります。仮に cpuid 命令をサポートしていない CPU で命令を実行した場合、CPU はシステムに対し一般保護例外を発行し、通常システムはその時点で実行を中断します。

SEH は、この一般保護エラーを例外処理として処理することが出来、実行を中断させること無く処理を続けることが出来ます。今回はこの機能を利用して CPUID 命令をサポートしているかどうかのチェックを省いています(手抜き?)。そもそも Windows XP を実行出来る CPU を実装しているのであれば CPUID 命令は当然実装されているであろう、という考えもありました。

一般保護エラーを発生させること無く CPUID 命令をサポートしているかどうかの処理については AP-485*1 が詳しいです。

ZwSystemDebugControl

上記で説明した RDMSR 命令ですが通常の方法では実行できません。一般的には特権レベルで動作するデバイスドライバを作成し、Read/Write/DeviceIoConrol を経由して MSR 情報を取得します。ひよひよさんの CrystalCPUID*2 はこの方法を用いているようです。デバイスドライバによる取得方法は自由度が高いのですが、手順が面倒くさい、少しのミスがクリティカル(BSoD?) 等、QuickHack には向いていません。

そこで今回は ZwSystemDebugControl という非公開の Native API を用いて MSR 情報を取得することにしました。元ネタは SecurityFocus に投稿されたセキュリティ・ホール情報です。この投稿に対し Microsoft 社は Debug 権限を取得できた時点で相当危険な状態であり動作は仕様、との見解のようです。折角ですので今回使わせてもらいました =)。ただし残念ながらこの API は Windows XP でのみでしか使用出来ないようです。Windows Server 2003 や Windows XP x64 Edition では関数が正常に動作しないようでした。

Native API は、Kernel mode と User mode との橋渡しに使用される API で基本的には非公開情報のようです。

VirtualAlloc

当初、スタックを使って一般保護エラーを発生させようと試みたのですが、Release build の時と Debug build の時で挙動が異なり、安定して(?)エラーを発生させることが出来ませんでした。そこで、明示的に VirtualAlloc にて明示的に実行可能なメモリ領域を作成し問題なくデータ実行が行えることを確認した後、実行可能なメモリ領域を実行不可能なメモリ領域に変更し、再度、データ実行が行えるかで DEP が有効かどうかを判定しました。実行不可能なメモリ領域に変更してもデータ実行が行えた場合、DEP が働いていないと判断しました。

DEP 環境下でデータ実行が必要である場合(動的コード生成を実行するアプリケーション等)、明示的にデータ実行を可能にするフラグを立ててメモリ取得を行うことが推奨されています。

	// Read/Write/Execute
	pf = (PBYTE)VirtualAlloc( NULL, 4, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
	if( pf == NULL ){ return FALSE; }
	*pf     = 0xC3;	// ret*4
	*(pf+1) = 0xC3;
	*(pf+2) = 0xC3;
	*(pf+3) = 0xC3;

	pfunc = (PFUNC)pf;

	// SEH
	__try{
		(*pfunc)();
	}__except(EXCEPTION_EXECUTE_HANDLER){
		// unknown...
		goto cleanup;
	}

	// Read/Write, NO Execute
	if( VirtualProtect(pf, 4, PAGE_READWRITE, &dwProt) ){
		__try{
			(*pfunc)();
		}__except(EXCEPTION_EXECUTE_HANDLER){
			// work NX-bit!
			bRet = TRUE;
		}
	}

まとめ

今回の調査より、ハードウェア DEP が動作している環境下では常に NX-bit が使用されていることが分かりました。ただし、デフォルトの設定ではシステムに関わる部分に限ったメモリ保護であり、全てのアプリケーションが保護されるわけではありませんでした。これは、NX-bit による一般保護エラーが発生した場合でも、システムに直接関わるモジュールではない場合、そのまま実行を続けることを許す処理になっていると考えられます。

データ保護設定を「次に選択するものを除くすべてのプログラムおよびサービスについて DEP を有効にする(U:)」に変更することより、全てのアプリケーションに対しデータ保護が有効になります。

ユーザーのシステム環境を守るためにも、ハードウェア DEP が有効である環境で安全に動作するアプリケーション開発が求められることになるでしょう。それに備えるためにも今後、全てのアプリケーションでハードウェア DEP を有効にした環境で開発を行うことが 推奨されることになるかもしれません。

参考資料

インテル

AMD

マイクロソフト

DEP に関する記事

Native API に関する情報

関連書籍


From SyncHack


History

  • 05.07.27、First update! -- Mc.N 2005-07-27 03:37:30 (水)
  • CodeZine にて掲載開始。 -- Mc.N 2005-08-03 12:51:42 (水)

*1 AP-485 Intel Processor Identification and the CPUID Instruction
*2 http://crystalmark.info/

Last-modified: 2005.10.20 (木) 15:39:40 (6988d)