다음을 통해 공유


가장

일부 파일 시스템은 원래 호출자를 대신하여 작업을 수행하는 것이 유용할 수 있습니다. 예를 들어 네트워크 파일 시스템은 적절한 자격 증명을 사용하여 후속 작업을 수행할 수 있도록 파일을 열 때 호출자의 보안 정보를 캡처해야 할 수 있습니다. 이 유형의 기능이 파일 시스템 내에서뿐만 아니라 특정 애플리케이션 모두에서 유용한 다른 많은 특별한 경우는 의심의 여지가 없습니다.

가장에 필요한 주요 루틴은 다음과 같습니다.

  • PsImpersonateClientSeImpersonateClientEx--는 가장을 시작합니다. 특정 스레드가 표시되지 않는 한 가장은 현재 스레드 컨텍스트에서 수행됩니다.

  • PsRevertToSelf -- 현재 스레드 컨텍스트 내에서 가장을 종료합니다.

  • PsReferencePrimaryToken -- 지정된 프로세스에 대한 기본(프로세스) 토큰에 대한 참조를 보유합니다. 이 함수는 시스템의 모든 프로세스에 대한 토큰을 캡처하는 데 사용할 수 있습니다.

  • PsDereferencePrimaryToken -- 이전에 참조된 기본 토큰에 대한 참조를 해제합니다.

  • SeCreateClientSecurityFromSubjectContext--는 주체 컨텍스트에서 가장하는 데 유용한 클라이언트 보안 컨텍스트를 반환합니다(예: IRP_MJ_CREATE 처리하는 동안 FSD에 제공됨).

  • 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;
}

파일 시스템 개발자가 사용할 수 있는 이 가장 코드에는 다양한 변형이 있지만 이 방법은 이 기술에 대한 기본 설명을 제공합니다.