Udostępnij przez


Personifikacja

Niektóre systemy plików mogą okazać się przydatne do wykonywania operacji w imieniu oryginalnego obiektu wywołującego. Na przykład system plików sieciowych może wymagać przechwycenia informacji zabezpieczających obiektu wywołującego w momencie otwarcia pliku, aby można było wykonać kolejną operację przy użyciu odpowiednich poświadczeń. Bez wątpienia istnieje wiele innych specjalnych przypadków, w których ten typ funkcji jest przydatny, zarówno w systemie plików, jak i w określonych aplikacjach.

Kluczowe procedury wymagane do personifikacji obejmują:

  • PsImpersonateClientSeImpersonateClientEx--inicjuje personifikację. O ile nie wskazano określonego wątku, podszywanie się jest wykonywane w bieżącym kontekście wątku.

  • PsRevertToSelf — kończy uzurpację w bieżącym kontekście wątku.

  • PsReferencePrimaryToken — zawiera odwołanie do tokenu podstawowego (procesu) dla określonego procesu. Ta funkcja może służyć do przechwytywania tokenu dla dowolnego procesu w systemie.

  • PsDereferencePrimaryToken — zwalnia odwołanie do wcześniej przywoływanego tokenu podstawowego.

  • SeCreateClientSecurityFromSubjectContext --zwraca kontekst zabezpieczeń klienta przydatny do impersonacji z kontekstu podmiotu (dostarczonego do FSD podczas obsługi IRP_MJ_CREATE, na przykład).

  • SeCreateClientSecurity — tworzy kontekst zabezpieczeń klienta, oparty na kredencjach zabezpieczeń istniejącego wątku w systemie.

  • ImpersonateSecurityContext--przyjmuje kontekst zabezpieczeń w ksecdd.sys, usługa zabezpieczeń jądra.

  • RevertSecurityContext — kończy podszywanie się w ramach ksecdd.sys, usługi zabezpieczeń jądra.

Personifikacja jest prosta do zaimplementowania. W poniższym przykładzie kodu pokazano podstawową impersonację:

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

Istnieje wiele wariantów tego kodu personifikacji, które są dostępne dla deweloperów systemów plików, ale stanowi to podstawową ilustrację techniki.