昨年10月の発売以来、マイクロソフト社のWindows 7の販売本数は9,000万本に達しており、Windows販売史上最速という記録を更新しているといわれています。今回は、Windows 7で新たに強化された内部構造に関し、2回に渡って取り上げる予定です。まず第1回目は、多くの人が興味を示している、新軽量カーネル「MinWin」について紹介したいと思います。
多くの人が新軽量カーネル「MinWin」に大きな関心を寄せている一方で、大半の人が「MinWin」を正しく理解していません。中には、「MinWin」と「Server Core」を混同している人も少なくありません。では、「MinWin」とは、正確に何を指すのでしょうか?
正常にインストールできたXPMでは、「Enhanced Mode」、「Basic Mode」、「Virtual Applications Mode」の3種類のモードが使用可能です。Windows XPのデスクトップをそのまま表示して使う「Enhanced Mode」と「Basic Mode」は、通常のVirtual PCを使う場合と、見た目は全く変わらず、Virtual PCとWindows XP仮想マシンが表示されます。
過去、マイクロソフト社がWindows Server 2008で実現したものの1つに、「Server Core」(旧名称:「Server Foundation」)がありました。これは、ADやDNS、DHCPサーバー、インターネットインフォメーションサービス(IIS)といった一般的なサーバー機能の動作に必要なコンポーネントを集めた、Windows OSのサブセット製品でした。一方「MinWin」は、上位層のコンポーネントに依存しない、独立型の小規模なOSです。一般的には、Windows 7に付属して出荷される、最小構成の独立型Windowsコンポーネントセットとしてよく知られています。
マイクロソフト社のあるWindows開発者は、「MinWin」を「アーキテクチャの階層に沿ったコードの修正」と説明しています。実際、初の「MinWin」ベースのOSと言われるWindows Vista以降(Windows Vistaではすでに複数のコンポーネント化と修正が行われています)は、OSのどのコンポーネントにも、他のコンポーネントとの依存関係を表す「階層番号」が割り振られており、OSのコアに近いコンポーネントほど、小さな番号が割り当てられています。「コード修正」はコアのアーキテクチャチームが行い、この修正によって、下位層のコンポーネントが上位層のコンポーネントに依存する、という依存関係の問題を解決しました。次に、Windows 7における「階層化」と「コード修正」の方法を、例を使って説明しましょう。
ApiSet Stub DLLs:
api-ms-win-core-console-l1-1-0.dll
api-ms-win-core-datetime-l1-1-0.dll
api-ms-win-core-debug-l1-1-0.dll
api-ms-win-core-delayload-l1-1-0.dll
api-ms-win-core-errorhandling-l1-1-0.dll
api-ms-win-core-fibers-l1-1-0.dll
api-ms-win-core-file-l1-1-0.dll
api-ms-win-core-handle-l1-1-0.dll
api-ms-win-core-heap-l1-1-0.dll
api-ms-win-core-interlocked-l1-1-0.dll
api-ms-win-core-io-l1-1-0.dll
api-ms-win-core-libraryloader-l1-1-0.dll
api-ms-win-core-localization-l1-1-0.dll
api-ms-win-core-localregistry-l1-1-0.dll
api-ms-win-core-memory-l1-1-0.dll
api-ms-win-core-misc-l1-1-0.dll
api-ms-win-core-namedpipe-l1-1-0.dll
api-ms-win-core-processenvironment-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-0.dll
api-ms-win-core-profile-l1-1-0.dll
api-ms-win-core-rtlsupport-l1-1-0.dll
api-ms-win-core-string-l1-1-0.dll
api-ms-win-core-synch-l1-1-0.dll
api-ms-win-core-sysinfo-l1-1-0.dll
api-ms-win-core-threadpool-l1-1-0.dll
api-ms-win-core-util-l1-1-0.dll
api-ms-win-core-xstate-l1-1-0.dll
api-ms-win-security-base-l1-1-0.dll
api-ms-win-security-lsalookup-l1-1-0.dll
api-ms-win-security-sddl-l1-1-0.dll
api-ms-win-service-core-l1-1-0.dll
api-ms-win-service-management-l1-1-0.dll
api-ms-win-service-management-l2-1-0.dll
api-ms-win-service-winsvc-l1-1-0.dll
これを見ると、「Kernel32!OpenProcess」が実際には大した働きをせず、単に、スタブDLLの1つ(api-ms-win-core-synch-l1-1-0.dll)からインポートされる「OpenProcess_0」へジャンプしているだけ、ということがわかります。
IDA ProとDependency Walkerを使えば、この依存関係はひと目でわかります。しかし、「api-ms-win-core-synch-l1-1-0!OpenProcess」を逆アセンブルしたコードをより詳しく見てみると、驚いたことにこの関数は実際には空で、単に0を返してくるにすぎません。しかもエクスポートした関数のうち、引数が3のものはすべて、同じ関数スタブ(下図参照)を共有していることが分かるでしょう。では、「Kernel32!OpenProcess」は結局のところ空関数なのに、なぜうまく機能するのでしょうか?
その秘密は、このDLLのロードプロセスにあります。デバッガWindbgの出力結果から、「Kernel32!OpenProcess」は実行中に「api-ms-win-core-synch-l1-1-0!OpenProcess」にジャンプしないことがわかります。さらに、「OpenProcess」のインポートテーブル・エントリーは、実際には「Kernelbase!OpenProcess」のアドレスで埋められていて、「api-ms-win-*.dll」はいずれもプロセスアドレス空間(!pebの出力を参照)にロードされないことがわかりました。
実際に動作するコードは、「Kernel32!OpenProcess」から「Kernelbase!OpenProcess」(下図参照)に移動し、そこでさらに「Ntdll!ZwOpenProcess」を実行しています。ちなみに、「アーキテクチャの階層に沿ったコードの修正」では、「OpenProcess」だけでなくほとんどのWin32 APIがその対象となりました。
次回では、Windows 7の新機能である、仮想化とリモート・アプリケーションを組み合わせた「Windows XP Mode(XPM)」について取り上げたいと思います。
関連記事
- [2010/06/23] Windows 7 解剖 – 2:「XP Mode」について
※本ページの内容はMcAfee Blogの抄訳です。
原文:Windows 7 – Kernel API Refactoring