マルウェア対策サービスの保護

Windows 8.1は、マルウェアによる攻撃の頻繁なターゲットであるマルウェア対策サービスを保護するための保護されたサービスの新しい概念を導入しました。

マルウェア対策 (AM) ユーザー モード サービスの保護と、この機能をマルウェア対策サービスに含める方法について説明します。

この情報は、次のオペレーティング システムとその後続システムに適用されます。

  • Windows 8.1
  • Windows Server 2012 R2

ここで説明する参考資料とリソースは、このトピックの最後に記載されています。

概要

ほとんどのマルウェア対策ソリューションには、システムからマルウェアを検出して削除するための特殊な操作を実行するユーザー モード サービスが含まれます。 このユーザー モード サービスは、最新のウイルス定義と署名のダウンロードも頻繁に行います。 このユーザー モード サービスは、システムの保護を無効にする単一障害点であるため、マルウェアの頻繁なターゲットになります。 ユーザー モード サービスに対する攻撃から防御するには、マルウェア対策ベンダーがソフトウェアに多くの機能とヒューリスティックを追加する必要があります。 ただし、このような手法は完全には確実ではなく、Windows がサービスで実行する機能を特定し、その機能を選択的に有効にする必要があるため、エラーが発生しやすい傾向があります。

Windows 8.1では、マルウェア対策ユーザー モード サービスを保護されたサービスとして起動できるように、保護されたサービスの新しい概念が導入されました。 保護されたサービスとしてサービスが起動されると、Windows はコード整合性を使用して、信頼されたコードのみが保護されたサービスに読み込まれるようにします。 また、Windows では、これらのプロセスをコード挿入やその他の管理者プロセスからの攻撃から保護します。

このドキュメントでは、早期起動マルウェア対策 (ELAM) ドライバーを使用するマルウェア対策ベンダーがこの機能をオプトインし、保護されたサービスとしてマルウェア対策サービスを起動する方法について説明します。

システムで保護されたプロセス

Windows 8.1以降、システムクリティカルなコンポーネントに対する悪意のある攻撃からより適切に防御するために、カーネルに新しいセキュリティ モデルが配置されました。 この新しいセキュリティ モデルは、DRM コンテンツの再生など、特定のシナリオで使用されていた以前のバージョンの Windows の保護されたプロセス インフラストラクチャを、サード パーティのマルウェア対策ベンダーが使用できる汎用モデルに拡張します。 保護されたプロセス インフラストラクチャでは、信頼された署名されたコードの読み込みのみが許可され、コードインジェクション攻撃に対する防御が組み込まれています。

注意

次のスクリプト DLL は、保護されたプロセス (直接または間接的に読み込まれているかにかかわらず) 内の CodeIntegrity によって禁止されています (WinVerifyTrust や WinVerifyTrustEx scrobj.dlljscript9.dllscrrun.dlljscript.dllvbscript.dllなど)。

保護されたプロセスの詳細については、「Windows Vista の保護されたプロセス」を参照してください。

新しいセキュリティ モデルでは、システム保護プロセスと呼ばれる保護プロセス インフラストラクチャの少し異なるバリエーションが使用されます。これは、DRM コンテンツを分離しているため、この機能に適しています。 システムで保護された各プロセスには、プロセス内で読み込みが許可されている署名済みコードの署名ポリシーを示すレベルまたは属性が関連付けられています。 マルウェア対策サービスが保護されたサービス モードにオプトインした後、マルウェア対策ベンダーの証明書で署名された Windows 署名済みコードまたはコードのみが、そのプロセスでの読み込みが許可されます。 同様に、他の保護されたプロセス レベルでは、Windows によって異なるコード ポリシーが適用されます。

必要条件

マルウェア対策ユーザー モード サービスを保護されたサービスとして実行するには、マルウェア対策ベンダーに Windows マシンに ELAM ドライバーがインストールされている必要があります。 既存の ELAM ドライバー認定要件に加えて、ドライバーには、ユーザー モード サービス バイナリの署名に使用される証明書の情報を含む埋め込みリソース セクションが必要です。

重要

Windows 8.1では、証明書チェーンはドライバーの検証によって決定される既知のルートである必要があります。または、ルート証明書を含める必要があります。

ブート プロセス中に、ELAM ドライバーからこのリソース セクションが抽出され、証明書情報が検証され、マルウェア対策サービスが登録されます。 マルウェア対策サービスは、このドキュメントで後述するように、特別な API を呼び出すことによって、マルウェア対策ソフトウェアのインストール プロセス中に登録することもできます。

リソース セクションが ELAM ドライバーから正常に抽出され、ユーザー モード サービスが登録されると、サービスは保護されたサービスとして起動できます。 保護されたサービスが起動されると、システム上の他の保護されていないプロセスはスレッドを挿入できず、保護されたプロセスの仮想メモリへの書き込みは許可されません。

さらに、保護されたプロセスに読み込まれる Windows 以外の DLL は、適切な証明書で署名する必要があります。

ELAM ドライバーの詳細については、「 早期起動マルウェア対策 」を参照してください。

マルウェア対策サービスの署名要件

保護された状態で起動する必要があるユーザー モード サービスは、有効な証明書で署名する必要があります。 サービス EXE にはページ ハッシュ署名が必要で、サービスに読み込まれる Windows 以外の DLL も同じ証明書で署名する必要があります。 これらの証明書のハッシュは、ELAM ドライバーにリンクされるリソース ファイルに追加する必要があります。

注意

SHA256 ファイル/ページ ハッシュを使用する必要がありますが、証明書は SHA1 を引き続き使用できます。

マルウェア対策ベンダーは、既存の Authenticode 証明書を使用してマルウェア対策サービス バイナリに署名し、この Authenticode 証明書のハッシュをリソース セクションに含め、サービス バイナリへの署名に使用される証明書を示すようにすることをお勧めします。 この証明書を更新する場合は、更新された証明書ハッシュを使用して ELAM ドライバーの新しいバージョンをリリースする必要があります。

セカンダリ署名 (省略可能)

マルウェア対策ベンダーには、プライベート CA を設定し、この CA の証明書を使用して、マルウェア対策サービス バイナリをセカンダリ署名としてコード署名するオプションがあります。 プライベート CA を使用する主な利点は、ベンダーが、同じベンダーから複数の製品を区別するために使用できる特殊な EKU プロパティを使用して証明書を作成できることです。 また、プライベート CA 証明書の有効期限が通常より長いため、証明書の有効期限のために ELAM ドライバーを更新する必要も減ります。

サービス バイナリがプライベート CA 証明書で署名されている場合は、バイナリも既存の Authenticode 証明書でデュアル署名する必要があることに注意してください。 バイナリが既知の信頼できる CA (VeriSign など) によって署名されていない場合、コンピューターのユーザーはプライベート CA を信頼できないため、バイナリに対する信頼を持っていません。 既存の Authenticode 証明書を使用してバイナリをデュアル署名すると、下位レベルのオペレーティング システムでバイナリを実行することもできます。

証明機関を設定してインストールする方法の詳細については、「証明機関の 設定 」および「証明機関 のインストール」を参照してください。

注意

Windows Vista または Windows XP (または SHA2 パッチのない Windows 7) との互換性を確保するために、SHA256 ファイル/ページ ハッシュを使用して SignTool.exe を使用してバイナリに署名するときに、"/as" スイッチを使用できます。 これにより、ファイルにセカンダリ署名として署名が追加されます。 WINDOWS XP、Windows Vista、Windows 7 では最初の署名のみが表示されるため、SHA1 は最初にファイルに署名します。

DLL 署名の要件

前述のように、保護されたサービスに読み込まれる Windows 以外の DLL は、マルウェア対策サービスへの署名に使用されたのと同じ証明書で署名する必要があります。

カタログ署名

マルウェア対策ベンダーは、バイナリ署名を更新せずに、他の企業によって開発されたパッケージを含めることができます。 これを実現するには、次の手順に従って、Authenticode 証明書で署名されたカタログにバイナリを含めます。

  1. MakeCat を使用してカタログを生成する
  2. 適切な署名を持たないすべてのバイナリをカタログに追加する
  3. 他のバイナリと同様に、Authenticode 証明書を使用してカタログに署名します
  4. カタログの 追加 関数を使用して、アプリケーションにカタログを含めます。

コード整合性が適切な署名を持たないパッケージに出くわした場合、承認された署名を持つカタログが検索されます。 これらの手順に従い、アプリケーションと共にインストールされている限り、このカタログが見つかります。

リソース ファイル情報

リソース ファイルを作成し、ELAM ドライバーにリンクする必要があります。 証明書のハッシュと他の証明書情報は、リソース ファイルに追加する必要があります。

システムがバイナリ イメージからリソースを正常に抽出し、埋め込み証明書情報を検証するには、リソース セクションを次のレイアウトにする必要があります。

MicrosoftElamCertificateInfo  MSElamCertInfoID
{
      3, // count of entries
      L”CertHash1\0”,
      Algorithm,
      L”EKU1\0”,
      L”CertHash2\0”,
      Algorithm,
      L”\0”, //No EKU for cert hash 2
      L”CertHash3\0”,
      Algorithm,
      L”EKU3a;EKU3b;EKU3c\0”,  //multiple EKU entries supported (max: 3)
}

ユーザー定義リソース ファイルの詳細については、「 ユーザー定義リソース」を参照してください。

CertHash

マルウェア対策サービスに署名するために使用される証明書のハッシュ。 Windows SDK に付属する CertUtil.exe ツールを使用してハッシュを取得できます。

certutil.exe –v <path to the signed file>

例:

マルウェア対策で保護されたサービス証明書ハッシュ (certhash)

アルゴリズム

アルゴリズム値は、証明書のアルゴリズムを表します。 次のアルゴリズム値がサポートされています。

0x8004 – SHA1 0x800c – SHA256 0X800d – SHA384 0x800e – SHA512

アルゴリズムの実際の名前ではなく、(上記のように) アルゴリズムの値を必ず含めてください。 たとえば、証明書が SHA256 アルゴリズムに基づいている場合は、リソース セクションに0x800cを含めます。

EKU

EKU オブジェクトは、証明書の 1 つの拡張キー使用法 (EKU) プロパティを表します。 これは省略可能であり、証明書に関連付けられている EKU がない場合は "\0" を指定する必要があります。同じシステムで実行されている 1 つのマルウェア対策ベンダーの製品とサービスが複数ある場合、マルウェア対策ベンダーはプライベート CA 証明書の EKU プロパティを使用して、1 つのサービスを別のサービスと区別できます。 たとえば、同じマルウェア対策ベンダーからシステム上で実行され、同じ CA によって署名された 2 つのサービスがある場合、保護対象として起動する必要があるサービスは、特別な EKU を含む CA によって発行された証明書で署名できます。 この EKU は、リソース セクションに追加する必要があります。 その後、EKU はシステムによって登録され、保護されたサービスを検証して起動するための証明書ハッシュとペアになります。

証明書チェーンにはコード署名 EKU (1.3.6.1.5.5.7.3.3) が含まれている必要がありますが、この EKU は ELAM ドライバーのリソース セクションに含めてはなりません。

注意

ELAM ドライバーの証明書情報に EKU 情報が含まれている場合は、バイナリに署名するときに同じ EKU を使用する必要があります。

注意

EKU での WINDOWS コード整合性の OID の文字列表現の最大長は 64 文字で、終端文字は 0 を含みます。  

注意

複数の EKU を指定すると、ロジックで AND 評価されます。 エンド エンティティ証明書は、指定されたエントリの ELAM リソース セクションで指定されたすべての EKU を満たす必要があります。

Count

マルウェア対策サービス バイナリが Authenticode 証明書とプライベート CA 証明書で署名されている場合は、リソース セクションにプライベート CA 証明書情報のみを追加する必要があります。

保護されたマルウェア対策サービスの起動

サービスの登録

マルウェア対策サービスは、保護された状態で開始する前に、システムに登録する必要があります。 マルウェア対策ソフトウェアのインストール中に、インストーラーは ELAM ドライバーをインストールし、システムを再起動してサービスを自動的に登録できます。 システムは、ELAM ドライバーにリンクされている前述のリソース ファイルから証明書情報を抽出することで、起動時にサービスを登録します。

インストール フェーズでは、ELAM ドライバーが読み込まれ、システムの状態を検証するために、システムを再起動することを強くお勧めします。 ただし、再起動を回避する必要がある場合、Windows では、マルウェア対策インストーラーが API を使用して保護されたサービスとしてサービスを登録するためのメカニズムも公開されます。

システムを再起動せずにサービスを登録する

インストール中、マルウェア対策ソフトウェア インストーラーは InstallELAMCertificateInfo API を呼び出し、ELAM ドライバー ファイルへのハンドルを提供できます。 システムは ELAM ドライバーを開き、内部ルーチンを呼び出して ELAM ドライバーが正しく署名されていることを確認し、ELAM ドライバーに関連付けられているリソース セクションから証明書情報を抽出します。 関数の構文については、 InstallELAMCertificateInfo を参照してください。

コード例:

HANDLE FileHandle = NULL;

FileHandle = CreateFile(<Insert Elam driver file name>,
                        FILE_READ_DATA,
                        FILE_SHARE_READ,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL
                        );

if (InstallElamCertificateInfo(FileHandle) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

保護されたサービスの開始

インストーラーは、次の手順に従って、保護されたサービスを作成、構成、および開始できます。

  1. CreateService API を呼び出してサービス オブジェクトを作成し、サービス コントロール マネージャー (SCM) データベースに追加します。

  2. SetServiceObjectSecurity API を呼び出して、手順 1 で作成したサービス オブジェクトのセキュリティ記述子を設定します。

  3. ChangeServiceConfig2 API を呼び出して、Winsvc.h で追加された新しいSERVICE_CONFIG_LAUNCH_PROTECTED列挙値 (Windows 8.1時点) を指定して、サービスを保護済みとしてマークします。

    コード例:

    SERVICE_LAUNCH_PROTECTED_INFO Info;
    SC_HANDLE hService;
    
    Info.dwLaunchProtected = SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT;
    
    hService = CreateService (/* ... */);
    
    if (ChangeServiceConfig2(hService,
                             SERVICE_CONFIG_LAUNCH_PROTECTED,
                             &Info) == FALSE)
    {
        Result = GetLastError();
    }
    
  4. StartService API を呼び出してサービスを開始します。 保護された状態でサービスを開始すると、SCM はコード整合性 (CI) サブシステムを使用して証明書情報を検証します。 証明書情報が CI によって検証されると、SCM は保護されたサービスとしてサービスを起動します。

    1. InstallELAMCertificateInfo API を呼び出してサービスを登録していない場合、この手順は失敗します。
    2. システムの起動フェーズ中にサービスが自動的に開始するように構成されている場合は、この手順を回避して、システムを再起動するだけです。 再起動中、システムは自動的にサービスを登録し (ELAM ドライバーが正常に起動した場合)、保護モードでサービスを開始します。

保護された子プロセスの起動

新しいセキュリティ モデルでは、マルウェア対策で保護されたサービスが、保護された子プロセスを起動することもできます。 これらの子プロセスは、親サービスと同じ保護レベルで実行され、そのバイナリは ELAM リソース セクションを介して登録されたのと同じ証明書で署名する必要があります。

マルウェア対策で保護されたサービスが保護された状態で子プロセスを起動できるようにするには、新しい拡張属性キー (PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL) が公開されており、 UpdateProcThreadAttribute API で使用する必要があります。 PROTECTION_LEVEL_SAMEの属性値へのポインターを UpdateProcThreadAttribute API に渡す必要があります。

メモ:

  • この新しい属性を使用するには、CreateProcess 呼び出しのプロセス作成フラグ パラメーターにCREATE_PROTECTED_PROCESSも指定する必要があります。
  • /ac スイッチを使用して署名されたサービス バイナリにクロス証明書を含め、それを既知の CA にチェーンする必要があります。 既知のルート CA に適切にチェーンされていない自己署名証明書は機能しません。

コード例:

DWORD ProtectionLevel = PROTECTION_LEVEL_SAME;
SIZE_T AttributeListSize;

STARTUPINFOEXW StartupInfoEx = { 0 };

StartupInfoEx.StartupInfo.cb = sizeof(StartupInfoEx);

if (InitializeProcThreadAttributeList(NULL,
                                      1,
                                      0,
                                      &AttributeListSize) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

StartupInfoEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc(
    GetProcessHeap(),
    0,
    AttributeListSize
    );

if (InitializeProcThreadAttributeList(StartupInfoEx.lpAttributeList,
                                      1,
                                      0,
                                      &AttributeListSize) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

if (UpdateProcThreadAttribute(StartupInfoEx.lpAttributeList,
                              0,
                              PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL,
                              &ProtectionLevel,
                              sizeof(ProtectionLevel),
                              NULL,
                              NULL) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

PROCESS_INFORMATION ProcessInformation = { 0 };

if (CreateProcessW(ApplicationName,
                   CommandLine,
                   ProcessAttributes,
                   ThreadAttributes,
                   InheritHandles,
                   EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS,
                   Environment,
                   CurrentDirectory,
                   (LPSTARTUPINFOW)&StartupInfoEx,
                   &ProcessInformation) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

更新プログラムとサービス

マルウェア対策サービスが保護として起動された後、他の保護されていないプロセス (および管理者) は、サービスを停止できません。 サービス バイナリの更新の場合、マルウェア対策サービスはインストーラーからコールバックを受け取って、サービスを提供できるように停止する必要があります。 サービスが停止した後、マルウェア対策インストーラーはアップグレードを実行し、「 サービスの登録保護されたサービスとしてのサービスの開始 」セクションで説明した手順に従って証明書を登録し、保護されたサービスを開始できます。

サービスでは、信頼された呼び出し元のみがサービスを停止できることを確認する必要があることに注意してください。 信頼されていない呼び出し元にこれを許可すると、サービスを保護する目的は無効になります。

サービスの登録解除

保護されたサービスをアンインストールするときは、 ChangeServiceConfig2 API を呼び出して、サービス自体を保護されていないものとしてマークする必要があります。 保護されていないプロセスが保護されたサービスの構成を変更することはシステムで許可されないため、 ChangeServiceConfig2 の呼び出しは保護されたサービス自体によって行われる必要があることに注意してください。 保護されていない状態で実行するようにサービスを再構成した後、アンインストーラーは、マルウェア対策ソフトウェアをシステムから削除するための適切な手順を実行できます。

マルウェア対策で保護されたサービスのデバッグ

保護されたプロセス セキュリティ モデルの一部として、他の保護されていないプロセスでは、スレッドを挿入したり、保護されたプロセスの仮想メモリに書き込んだりすることはできません。 ただし、カーネル デバッガー (KD) は、マルウェア対策で保護されたプロセスのデバッグに使用できます。 KD は、マルウェア対策サービスが保護された状態で実行されているかどうかを確認するためにも使用できます。

dt –r1 nt!_EPROCESS <Process Address>
+0x67a Protection       : _PS_PROTECTION
      +0x000 Level            : 0x31 '1'
      +0x000 Type             : 0y0001
      +0x000 Signer           : 0y0011

Type メンバーの値が 0y0001 の場合、サービスは保護されたとおりに実行されます。

さらに、マルウェア対策で保護されたサービスでは、次の SC コマンドのみが許可されます。

  • sc config start=Auto
  • sc qc
  • sc start
  • sc interrogate
  • sc sdshow

デバッガーがアタッチされている場合は、レジストリで次のフラグを使用して、署名されていない (または不適切に署名された) バイナリがマルウェア対策で保護されたサービスに読み込まれたときにデバッガーを中断します。

Key:   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI
Value: DebugFlags      REG_DWORD

値を 00000400 に設定して、署名の検証が失敗したときにデバッガーで中断します。

注意

保護されたプロセスの制限事項:

  1. UI または GUI を持つプロセスは、カーネルがメモリ内のプロセスをロックし、それに対する書き込みを許可しないため、保護できません。
  2. Windows 10バージョン 1703 (Creators 更新) より前のバージョンでは、保護されたプロセスでは、ローカル セキュリティ機関 (LSA) と保護されたプロセス間の証明書共有の制限により、TLS または SSL 通信プロトコルを使用できません。

リソース

For more info, see:

これらの Windows API 関数は、この記事で参照されています。