メモリ整合性互換コードを実装する

このセクションでは、メモリ整合性互換コードを実装する方法について説明します。

Note

メモリの整合性は、ハイパーバイザーで保護されたコードの整合性 (HVCI) またはハイパーバイザーによって適用されるコードの整合性と呼ばれることがあり、当初はDevice Guardの一部としてリリースされました。 Device Guardは、グループポリシーまたはWindowsレジストリでメモリの整合性とVBS設定を検索する場合を除き、使用されなくなりました。

互換性のあるコードを実装するには、ドライバー コードが次の条件を満たしていることを確認します。

  • 既定で NX にオプトインする
  • メモリ割り当て (NonPagedPoolNx) に NX API/フラグを使用する
  • 書き込み可能かつ実行可能なセクションを使用しない
  • 実行可能ファイルのシステム メモリを直接変更しない
  • カーネルで動的コードを使用しない
  • データ ファイルを実行可能ファイルとして読み込まない
  • セクションのアラインメントは、0x1000 (PAGE_SIZE) の倍数とする。 E.g. DRIVER_ALIGNMENT=0x1000

システムで使用するために予約されていない次の一連の DDI は、影響を受ける可能性があります。

DDI 名
ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithQuotaTag
ExAllocatePoolWithTag
ExAllocatePoolWithTagPriority
ExInitializeNPagedLookasideList
ExInitializeLookasideListEx
MmAllocateContiguousMemory
MmAllocateContiguousMemorySpecifyCache
MmAllocateContiguousMemorySpecifyCacheNode
MmAllocateContiguousNodeMemory
MmCopyMemory
MmMapIoSpace
MmMapLockedPages
MmMapLockedPagesSpecifyCache
MmProtectMdlSystemAddress
ZwAllocateVirtualMemory
ZwCreateSection
ZwMapViewOfSection
NtCreateSection
NtMapViewOfSection
ClfsCreateMarshallingArea
NDIS
NdisAllocateMemoryWithTagPriority
ストレージ
StorPortGetDataInBufferSystemAddress
StorPortGetSystemAddress
ChangerClassAllocatePool
ディスプレイ
DxgkCbMapMemory
VideoPortAllocatePool
オーディオ ミニポート
IMiniportDMus::NewStream
IMiniportMidi::NewStream
IMiniportWaveCyclic::NewStream
IPortWavePci::NewMasterDmaChannel
IMiniportWavePci::NewStream
Audio Port クラス
PcNewDmaChannel
PcNewResourceList
PcNewResourceSublist
IFS
FltAllocatePoolAlignedWithTag
FltAllocateContext
WDF
WdfLookasideListCreate
WdfMemoryCreate
WdfDeviceAllocAndQueryProperty
WdfDeviceAllocAndQueryPropertyEx
WdfFdoInitAllocAndQueryProperty
WdfFdoInitAllocAndQueryPropertyEx
WdfIoTargetAllocAndQueryTargetProperty
WdfRegistryQueryMemory

HLK のコード整合性テストを使用してメモリ整合性ドライバーの互換性をテストする

関連するシステム基礎セキュリティ テストの詳細については、「ハイパーバイザー コード整合性準備テスト」および「メモリの整合性と VBS」を参照してください。

関連するデバイスの基礎テストの詳細については、「Device.DevFund テスト」を参照してください。

次の表を使用して出力を解釈し、さまざまな種類のメモリ整合性の非互換性を解決するために必要なドライバー コードの変更を決定します。

警告 解決方法

プールの種類 (Execute)

呼び出し元は、実行可能なプールの種類を指定しました。 実行可能メモリを要求するメモリ割り当て関数を呼び出しています。

すべてのプールの種類に実行可能でない NX フラグが含まれていることを確認してください。

ページ保護 (Execute)

呼び出し元は、実行可能ページの保護を指定しました。

"no execute" ページ保護マスクを指定してください。

ページ マッピング (Execute)

呼び出し元は、実行可能なメモリ記述子リスト (MDL) マッピングを指定しました。

使用されたマスクに MdlMappingNoExecute が含まれていることを確認してください。 詳細については、「MmGetSystemAddressForMdlSafe」をご覧ください

Execute-Write セクション

イメージには、実行可能かつ書き込み可能なセクションが含まれています。

セクションのアラインメント エラー

このイメージには、ページがアラインされていないセクションが含まれています。

セクションのアラインメントは、0x1000 (PAGE_SIZE) の倍数である必要があります。 E.g. DRIVER_ALIGNMENT=0x1000

実行可能なセクション内の IAT

インポートアドレステーブル (IAT) は、メモリの実行可能なセクションである必要はありません。

この問題は、IAT がメモリの読み取りおよび実行 (RX) のみのセクションにある場合に発生します。 これは、参照されている DLL の正しいアドレスを設定するために、OS が IAT に書き込むことができないことを意味します。

この問題を発生させる方法の1つとして、コードリンクで /MERGE (セクションの結合) オプションを使用する方法があります。 たとえば、.rdata (読み取り専用の初期化されたデータ) を .text データ (実行可能コード) とマージすると、最終的に IAT がメモリの実行可能なセクションに存在することになる可能性があります。


サポートされていない再配置

Windows 10 バージョン 1507 から Windows 10 バージョン 1607 では、アドレス空間レイアウトのランダム化 (ASLR) が使用されているため、アドレスのアラインメントとメモリの再配置で問題が発生する可能性があります。 オペレーティング システムは、リンカーによって設定された既定のベース アドレスから、ASLR によって割り当てられた実際の場所へアドレスを再配置する必要があります。 この再配置では、ページ境界をまたがることはできません。 たとえば、ページのオフセット0x3FFC で始まる64ビットアドレス値を考えてみます。 このアドレス値は、オフセット0x0003 の次のページに重なっています。 Windows 10 バージョン 1703 より前では、この種類のオーバーラップする再配置はサポートされていません。

このような状況は、グローバル構造体型の変数初期化子が、及ぶ再配置を避けるために変数を移動できないようにレイアウトされた別のグローバルへのポインターが不整合になっている場合に発生する可能性があります。 リンカーはその変数を移動しようとしますが、それができない場合もあります。たとえば、適切にアラインされていない大きな構造体や、適切にアラインされていない構造体の大きな配列の場合などです。 必要に応じて、 /Gy (COMDAT)オプションを使用してモジュールを組み立て、リンカーがモジュールコードを可能な限り配置できるようにする必要があります。

#include <pshpack1.h>

typedef struct _BAD_STRUCT {
      USHORT Value;
      CONST CHAR *String;
} BAD_STRUCT, * PBAD_STRUCT;

#include <poppack.h>

#define BAD_INITIALIZER0 { 0, "BAD_STRING" },
#define BAD_INITIALIZER1 \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      \
      BAD_INITIALIZER0      

#define BAD_INITIALIZER2 \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      \
      BAD_INITIALIZER1      

#define BAD_INITIALIZER3 \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      \
      BAD_INITIALIZER2      

#define BAD_INITIALIZER4 \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      \
      BAD_INITIALIZER3      

BAD_STRUCT MayHaveStraddleRelocations[4096] = { // as a global variable
      BAD_INITIALIZER4
};

この問題が発生する可能性がある場合は、アセンブラーコードの使用に関連する他の状況もあります。


ドライバーの検証ツールのコード整合性

ドライバーの検証ツールのコード整合性オプション フラグ (0x02000000) を使用すると、この機能への準拠を検証する追加のチェックを有効にできます。 これをコマンド ラインから有効にするには、次のコマンドを使用します。

verifier.exe /flags 0x02000000 /driver <driver.sys>

検証ツールの GUI を使用している場合にこのオプションを選択するには、[カスタム設定の作成 (コード開発者用)] を選択し、[次へ] を選択してから、[コード整合性チェック] を選択します。

検証ツールのコマンド ライン /query オプションを使用して、現在のドライバー検証ツール情報を表示できます。

verifier /query

参照

ドライバーのセキュリティ チェックリスト