プラットフォームのセキュリティFlow Guard を制御する

Control Flow Guard とは

Control Flow Guard (CFG) は、メモリ破損の脆弱性に対処するために作成された高度に最適化されたプラットフォーム セキュリティ機能です。 アプリケーションがコードを実行できる場所に厳しい制限を設けることで、バッファー オーバーフローなどの脆弱性を通じて任意のコードを実行することが悪用されるのがはるかに困難になります。 CFG は、 /GSDEPASLR などの以前のエクスプロイト軽減テクノロジを拡張します。

  • メモリの破損やランサムウェア攻撃を防ぎます。
  • 攻撃対象領域を減らすために、特定の時点で必要なものにサーバーの機能を制限します。
  • バッファー オーバーフローなどの脆弱性によって任意のコードを悪用するのが困難になります。

この機能は Microsoft Visual Studio 2015 で使用でき、"CFG 対応" バージョンの Windows で実行されます。これは、デスクトップ用の x86 および x64 リリース、および Windows 10 および Windows 8.1 Update (が kb3000850) です。

開発者は、アプリケーションに対して CFG を有効にすることを強くお勧めします。 CFG が有効になっていて、CFG が有効になっていないコードが正常に実行されるため、コードのすべての部分に対して CFG を有効にする必要はありません。 ただし、すべてのコードに対して CFG を有効にしないと、保護のギャップを開くことができます。 また、CFG が有効になっているコードは、Windows の "CFG に対応していない" バージョンでも正常に動作するため、それらと完全に互換性があります。

CFG を有効にする方法

ほとんどの場合、ソース コードを変更する必要はありません。 Visual Studio 2015 プロジェクトにオプションを追加するだけで、コンパイラとリンカーは CFG を有効にします。

最も簡単な方法は、Project |に移動することです|のプロパティ構成プロパティ |C/C++ |コード生成し、Control Flow Guard に [はい] (/guard:cf) を選択します。

cfg property in visual studio

または、Project |に /guard:cf を追加します。|のプロパティ構成プロパティ |C/C++ |コマンド ライン |追加のオプション (コンパイラの場合) と /guard:cfProject ||のプロパティ構成プロパティ |リンカー |コマンド ライン |追加オプション (リンカーの場合)。

cfg property for compilercfg property for linker

詳細については、「/guard (コントロール Flow ガードを有効にする)」を参照してください。

コマンド ラインからプロジェクトをビルドする場合は、同じオプションを追加できます。 たとえば、test.cpp というプロジェクトをコンパイルする場合は、 cl /guard:cf test.cpp /link /guard:cf を使用します。

メモリ管理 API の SetProcessValidCallTargets を使用して、CFG によって有効と見なされる icall ターゲット アドレスのセットを動的に制御することもできます。 同じ API を使用して、ページが CFG の無効なターゲットか有効なターゲットかを指定できます。 VirtualProtect 関数と VirtualAlloc 関数は、既定で、実行可能ページとコミット済みページの指定された領域を有効な間接呼び出しターゲットとして扱います。 Just-in-Time コンパイラの実装時など、この動作をオーバーライドするには、VirtualAlloc を呼び出すときにPAGE_TARGETS_INVALIDを指定するか、メモリ保護定数で詳しく説明されているように VirtualProtect を呼び出すときにPAGE_TARGETS_NO_UPDATEを指定します。

バイナリがガードFlow制御下にあることを伝える方法

/headers オプションと /loadconfig オプション (dumpbin /headers /loadconfig test.exe) を使用して、Visual Studio コマンド プロンプトから dumpbin ツール (Visual Studio 2015 インストールに含まれています) を実行します。 CFG の下のバイナリの出力では、ヘッダー値に "Guard" が含まれており、読み込み構成の値に "CF Instrumented" と "FID table present" が含まれている必要があります。

output from dumpbin /headers

output from dumpbin /loadconfig

CFG は実際にどのように機能しますか?

ソフトウェアの脆弱性は、多くの場合、実行プログラムに可能性の低い、異常な、または極端なデータを提供することによって悪用されます。 たとえば、攻撃者は、予想よりも多くの入力をプログラムに提供することで、バッファー オーバーフローの脆弱性を悪用し、プログラムによって予約された領域を過剰に実行して応答を保持することができます。 これにより、関数ポインターを保持する可能性のある隣接するメモリが破損する可能性があります。 プログラムがこの関数を呼び出すと、攻撃者によって指定された意図しない場所にジャンプする可能性があります。

ただし、CFG からのコンパイルと実行時のサポートの強力な組み合わせは、間接呼び出し命令を実行できる場所を厳密に制限する制御フロー整合性を実装します。

コンパイラは次の処理を行います。

  1. コンパイルされたコードに軽量のセキュリティ チェックを追加します。
  2. 間接呼び出しの有効なターゲットであるアプリケーション内の関数のセットを識別します。

Windows カーネルによって提供されるランタイム サポート:

  1. 有効な間接呼び出しターゲットを識別する状態を効率的に維持します。
  2. 間接呼び出し先が有効であることを確認するロジックを実装します。

次の手順を示します。

cfg pseudocode

実行時に CFG チェックが失敗すると、Windowsはプログラムを直ちに終了し、無効なアドレスを間接的に呼び出そうとする悪用を中断します。