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

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

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

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

  • Windows 8.1
  • Windows Server 2012 R2

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

はじめに

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

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

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

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

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

Note

次のスクリプト DLL は、AuthentiCode 経由でスクリプト署名をチェックする WinVerifyTrust または WinVerifyTrustEx 経由など、保護されたプロセス (直接または間接的に読み込まれるかどうかにかかわらず) 内の CodeIntegrity によって禁止されています: scrobj.dllscrrun.dlljscript.dlljscript9.dllvbscript.dll

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

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

要件

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

重要

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

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

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

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

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

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

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

Note

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

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

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

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

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

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

Note

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

DLL 署名の要件

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

カタログ署名

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

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

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

リソース ファイルの情報

リソース ファイルを作成し、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>

次に例を示します。

anti-malware protected service certificate hash (certhash)

アルゴリズム

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

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

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

EKU

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

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

Note

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

Note

EKU 内の OID の Windows コード整合性の文字列表現の最大長は 64 文字 (ゼロ終端文字を含む) です。  

Note

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

カウント

マルウェア対策サービス バイナリが 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 (Windows 8.1 の時点) で追加された新しい SERVICE_CONFIG_LAUNCH_PROTECTED 列挙値を指定します。

    コード例:

    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 ドライバーが正常に起動した場合)、保護モードでサービスを開始します。
    3. サービスの開始が失敗する場合は、「コード整合性のイベント ログとシステム監査」とそれに続くトピックをご覧ください。 そこでは、コード整合性システムによってサービスの開始が妨げられた理由を説明する詳細なエラー メッセージがわかります。 それらのログは、サービスが読み込もうとして読み込めなかった DLL を特定するのにも役立ちます。

子プロセスを保護済みとして起動する

新しいセキュリティ モデルでは、マルウェア対策の保護されたサービスでも、子プロセスを保護済みとして起動できます。 これらの子プロセスは、親サービスと同じ保護レベルで実行され、そのバイナリは 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 に設定します。

Note

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

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

リソース

For more info, see:

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