Partilhar via


Imitação de identidade

Alguns sistemas de arquivos podem achar útil executar operações em nome do chamador original. Por exemplo, um sistema de arquivos de rede pode precisar capturar as informações de segurança do chamador no momento em que um arquivo é aberto para que uma operação subsequente possa ser executada usando as credenciais apropriadas. Sem dúvida, existem inúmeros outros casos especiais em que esse tipo de recurso é útil, tanto dentro de um sistema de arquivos quanto em aplicativos específicos.

As principais rotinas necessárias para a imitação incluem:

  • PsImpersonateClientSeImpersonateClientEx--inicia a personificação. A menos que um thread específico seja indicado, a representação é feita no contexto de thread atual.

  • PsRevertToSelf--termina a representação no contexto de thread atual.

  • PsReferencePrimaryToken--contém uma referência no token primário (processo) para o processo especificado. Esta função pode ser usada para capturar o token para qualquer processo no sistema.

  • PsDereferencePrimaryToken--libera uma referência em um token primário referenciado anteriormente.

  • SeCreateClientSecurityFromSubjectContext--retorna um contexto de segurança do cliente útil para imitar a partir de um contexto de assunto (fornecido ao FSD durante o tratamento de IRP_MJ_CREATE, por exemplo).

  • SeCreateClientSecurity--cria um contexto de segurança de cliente com base nas credenciais de segurança de um thread existente no sistema.

  • ImpersonateSecurityContext--personifica o contexto de segurança dentro do ksecdd.sys, o serviço de segurança do kernel.

  • RevertSecurityContext--encerra a representação dentro ksecdd.sys, o serviço de segurança do kernel.

A representação é simples de implementar. O exemplo de código a seguir ilustra uma impersonação básica:

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

Existem inúmeras variantes deste código de imposturação que estão disponíveis para programadores de sistemas de ficheiros, mas isto oferece uma ilustração básica da técnica.