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

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 は、保護されたプロセス (直接または間接的に読み込まれているかどうかに関係なく) 内の CodeIntegrity によって禁止されています 。たとえば、AuthentiCode を介してスクリプト署名を確認する場合は WinVerifyTrustEx または WinVerifyTrustEx を使用します。 scrobj.dllscrrun.dlljscript.dlljscript9.dll、および vbscript.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. カタログの 追加 関数を使用して、アプリケーションにカタログを含めます。

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

リソース ファイル情報

リソース ファイルを作成し、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 オブジェクトは、証明書の単一の拡張キー使用法 (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 ドライバーのリソース セクションに含めてはなりません。

Note

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

Note

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

Note

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

Count

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

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

サービスの登録

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

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

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

インストール中、マルウェア対策ソフトウェア インストーラーは 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 に設定して、シグネチャの検証が失敗したときにデバッガーで中断します。

Note

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

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

リソース

For more info, see:

これらの Windows API 関数については、次の記事を参照してください。