次の方法で共有


権限借用

一部のファイル システムでは、元の呼び出し元に代わって操作を実行すると便利な場合があります。 たとえば、ネットワーク ファイル システムでは、適切な資格情報を使用して後続の操作を実行できるように、ファイルが開かれたときに呼び出し元のセキュリティ情報をキャプチャする必要がある場合があります。 ファイル システム内と特定のアプリケーションの両方で、このタイプの機能が役立つ特殊なケースが他にも数多くあることは間違いありません。

偽装に必要な主要なルーチンは次のとおりです。

  • PsImpersonateClientSeImpersonateClientEx--なりすましを開始します。 特定のスレッドが指定されていない限り、偽装は現在のスレッド コンテキストで実行されます。

  • PsRevertToSelf--現在のスレッド コンテキスト内での偽装を終了します。

  • PsReferencePrimaryToken--指定されたプロセスのプライマリ (プロセス) トークンの参照を保持します。 この関数は、システム上の任意のプロセスのトークンをキャプチャするために使用できます。

  • PsDereferencePrimaryToken--以前に参照されたプライマリ トークンの参照を解放します。

  • SeCreateClientSecurityFromSubjectContext--サブジェクト コンテキスト (実行中に FSD に提供される) から偽装に役立つクライアント セキュリティ コンテキストを戻します。IRP_MJ_CREATE 取り扱いなど)。

  • SeCreateClientSecurity--システム上の既存のスレッドのセキュリティ資格情報に基づいてクライアント セキュリティ コンテキストを作成します。

  • ImpersonateSecurityContext--カーネル セキュリティ サービスである ksecdd.sys 内のセキュリティ コンテキストを偽装します。

  • RevertSecurityContext--カーネル セキュリティ サービスである ksecdd.sys 内での偽装を終了します。

偽装は簡単に実装できます。 次のコード例は、基本的な偽装を示しています。

NTSTATUS PerformSpecialTask(IN PFSD_CONTEXT Context)
{
  BOOLEAN CopyOnOpen;
  BOOLEAN EffectiveOnly;
  SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  NTSTATUS Status;
  PACCESS_TOKEN oldToken;

  //
  // We need to perform a task in the system process context
  //
  if (NULL == Context->SystemProcess) {

    return STATUS_NO_TOKEN;

  }

  //
  // Save the existing token, if any (otherwise NULL)
  //
  oldToken = PsReferenceImpersonationToken(PsGetCurrentThread(),
                                           &CopyOnOpen,
                                           &EffectiveOnly,
                                           &ImpersonationLevel);

  Status = PsImpersonateClient( PsGetCurrentThread(),
                                Context->SystemProcess,
                                TRUE,
                                TRUE,
                                SecurityImpersonation);
  if (!NT_SUCCESS(Status)) {

    if (oldToken)
        PsDereferenceImpersonationToken(oldToken);
    return Status;

  }

  //
  // Perform task - whatever it is
  //


  //
  // Restore to previous impersonation level
  //
  if (oldToken) {
    Status = PsImpersonateClient(PsGetCurrentThread(),
                                 oldToken,
                                 CopyOnOpen,
                                 EffectiveOnly,
                                 ImpersonationLevel);

    if (!NT_SUCCESS(Status)) {
      //
      // This is bad - we can't restore, we can't leave it this way 
      //
      PsRevertToSelf();
    }
    PsDereferenceImpersonationToken(oldToken);
  } else {
    PsRevertToSelf();
  }

  return Status;
}

ファイル システム開発者が利用できるこの偽装コードには多数の亜種が存在しますが、これはこの手法の基本的な例を示しています。