Einzelnen Beitrag anzeigen

NicoDE
(Gast)

n/a Beiträge
 
#10

Re: Administratorrechte anfordern (Elevation/Impersonation ?

  Alt 1. Jun 2007, 15:29
Zitat von OregonGhost:
oder hoffen, dass NicoDE seine Wrapper-Funktionen findet
Die Hoffnung stirbt zuletzt
(sind genauso zu verwenden wie die API-Funktionen - die Fallbacks dürften auch das gleiche machen wie die jeweilige API *g*)
Delphi-Quellcode:
unit TokenTools;

interface

uses
  Windows;

function CheckTokenMembership(TokenHandle: THandle; SidToCheck: PSID;
  out IsMember: BOOL): BOOL; stdcall;
function SHTestTokenMembership(hToken: THandle; ulRID: ULONG): BOOL; stdcall;
function IsUserAnAdmin(): BOOL; stdcall;

implementation

function GetAdvApi32Lib(): HMODULE;
const
  ModuleName = 'ADVAPI32';
{$WRITEABLECONST ON}
const
  ModuleHandle: HMODULE = HMODULE(nil);
{$WRITEABLECONST OFF}
begin
  Result := ModuleHandle;
  if Result = HMODULE(nil) then
  begin
    Result := LoadLibrary(ModuleName);
    if Result <> HMODULE(nil) then
      ModuleHandle := Result;
  end;
end;

function CheckTokenMembership(TokenHandle: THandle; SidToCheck: PSID;
  out IsMember: BOOL): BOOL;
type
  TFNCheckTokenMembership = function(TokenHandle: THandle; SidToCheck: PSID;
    out IsMember: BOOL): BOOL; stdcall;
{$WRITEABLECONST ON}
const
  Initialized: Integer = 0;
  RealApiFunc: TFNCheckTokenMembership = nil;
{$WRITEABLECONST OFF}
type
  TAceHeader = packed record
    AceType : Byte;
    AceFlags: Byte;
    AceSize : Word;
  end;
  TAccessAllowedAce = packed record
    Header : TAceHeader;
    Mask : ACCESS_MASK;
    SidStart: DWORD;
  end;
const
  ACL_REVISION = 2;
  DesiredAccess = 1;
  GenericMapping: TGenericMapping = (
    GenericRead : STANDARD_RIGHTS_READ;
    GenericWrite : STANDARD_RIGHTS_WRITE;
    GenericExecute: STANDARD_RIGHTS_EXECUTE;
    GenericAll : STANDARD_RIGHTS_ALL
  );
var
  ClientToken: THandle;
  ProcessToken: THandle;
  SecurityDescriptorSize: Cardinal;
  SecurityDescriptor: PSecurityDescriptor;
  Dacl: PACL;
  PrivilegeSetBufferSize: ULONG;
  PrivilegeSetBuffer: packed record
    PrivilegeSet: TPrivilegeSet;
    Buffer: array [0..2] of TLUIDAndAttributes;
  end;
  GrantedAccess: ACCESS_MASK;
  AccessStatus: BOOL;
begin
  if Initialized = 0 then
  begin
    RealApiFunc := TFNCheckTokenMembership(
      GetProcAddress(GetAdvApi32Lib(), 'CheckTokenMembership'));
    InterlockedIncrement(Initialized);
  end;
  if Assigned(RealApiFunc) then
    Result := RealApiFunc(TokenHandle, SidToCheck, IsMember)
  else
  begin
    Result := False;
    IsMember := False;
    ClientToken := THandle(nil);
    try
      if TokenHandle <> THandle(nil) then
        ClientToken := TokenHandle
      else if not OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, False,
        ClientToken) then
      begin
        ClientToken := THandle(nil);
        if GetLastError() = ERROR_NO_TOKEN then
        begin
          if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY or
            TOKEN_DUPLICATE, ProcessToken) then
          try
            if not DuplicateToken(ProcessToken, SecurityImpersonation,
              @ClientToken) then
            begin
              ClientToken := THandle(nil);
            end;
          finally
            CloseHandle(ProcessToken);
          end;
        end;
      end;
      if ClientToken <> THandle(nil) then
      begin
        SecurityDescriptorSize := SizeOf(TSecurityDescriptor) +
          SizeOf(TAccessAllowedAce) + SizeOf(TACL) +
          3 * GetLengthSid(SidToCheck);
        SecurityDescriptor := PSecurityDescriptor(
          LocalAlloc(LMEM_ZEROINIT, SecurityDescriptorSize));
        if SecurityDescriptor <> nil then
        try
          if InitializeSecurityDescriptor(SecurityDescriptor,
            SECURITY_DESCRIPTOR_REVISION) then
          begin
            if SetSecurityDescriptorOwner(SecurityDescriptor, SidToCheck,
              False) then
            begin
              if SetSecurityDescriptorGroup(SecurityDescriptor, SidToCheck,
                False) then
              begin
                Dacl := PACL(SecurityDescriptor);
                Inc(PSecurityDescriptor(Dacl));
                if InitializeAcl(Dacl^,
                  SecurityDescriptorSize - SizeOf(TSecurityDescriptor),
                  ACL_REVISION) then
                begin
                  if AddAccessAllowedAce(Dacl^, ACL_REVISION, DesiredAccess,
                    SidToCheck) then
                  begin
                    if SetSecurityDescriptorDacl(SecurityDescriptor, True, Dacl,
                      False) then
                    begin
                      PrivilegeSetBufferSize := SizeOf(PrivilegeSetBuffer);
                      Result := AccessCheck(SecurityDescriptor, ClientToken,
                        DesiredAccess, GenericMapping,
                        PrivilegeSetBuffer.PrivilegeSet, PrivilegeSetBufferSize,
                        GrantedAccess, AccessStatus);
                      if Result then
                        IsMember := AccessStatus and
                          (GrantedAccess = DesiredAccess);
                    end;
                  end;
                end;
              end;
            end;
          end;
        finally
          LocalFree(HLOCAL(SecurityDescriptor));
        end;
      end;
    finally
      if (ClientToken <> THandle(nil)) and
        (ClientToken <> TokenHandle) then
      begin
        CloseHandle(ClientToken);
      end;
    end;
  end;
end;

function GetShell32Lib(): HMODULE;
const
  ModuleName = 'SHELL32';
{$WRITEABLECONST ON}
const
  ModuleHandle: HMODULE = HMODULE(nil);
{$WRITEABLECONST OFF}
begin
  Result := ModuleHandle;
  if Result = HMODULE(nil) then
  begin
    Result := LoadLibrary(ModuleName);
    if Result <> HMODULE(nil) then
      ModuleHandle := Result;
  end;
end;

function SHTestTokenMembership(hToken: THandle; ulRID: ULONG): BOOL; stdcall;
type
  TFNSHTestTokenMembership = function(hToken: THandle; ulRID: ULONG): BOOL; stdcall;
{$WRITEABLECONST ON}
const
  Initialized: Integer = 0;
  RealApiFunc: TFNSHTestTokenMembership = nil;
{$WRITEABLECONST OFF}
const
  SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
  SECURITY_BUILTIN_DOMAIN_RID = $00000020;
var
  SidToCheck: PSID;
begin
  if Initialized = 0 then
  begin
    RealApiFunc := TFNSHTestTokenMembership(
      GetProcAddress(GetShell32Lib(), 'SHTestTokenMembership'));
    InterlockedIncrement(Initialized);
  end;
  if Assigned(RealApiFunc) then
    Result := RealApiFunc(hToken, ulRID)
  else
  begin
    Result := AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
      SECURITY_BUILTIN_DOMAIN_RID, ulRID, 0, 0, 0, 0, 0, 0, SidToCheck);
    if Result then
    try
      if not CheckTokenMembership(THandle(nil), SidToCheck, Result) then
        Result := False;
    finally
      FreeSid(SidToCheck);
    end;
  end;
end;

function IsUserAnAdmin(): BOOL;
const
  DOMAIN_ALIAS_RID_ADMINS = $00000220;
type
  TFNIsUserAnAdmin = function(): BOOL; stdcall;
{$WRITEABLECONST ON}
const
  Initialized: Integer = 0;
  RealApiFunc: TFNIsUserAnAdmin = nil;
{$WRITEABLECONST OFF}
begin
  if Initialized = 0 then
  begin
    RealApiFunc := TFNIsUserAnAdmin(
      GetProcAddress(GetShell32Lib(), 'IsUserAnAdmin'));
    InterlockedIncrement(Initialized);
  end;
  if Assigned(RealApiFunc) then
    Result := RealApiFunc()
  else
    Result := SHTestTokenMembership(THandle(nil), DOMAIN_ALIAS_RID_ADMINS);
end;

end.
ps: Die von Luckie kopierte IsAdmin-Funktion enthält den klassischen Fehler (es wurde vergessen zu prüfen, ob die aktuelle Sid überhaupt im Token aktiviert ist).
pps: upz, da war aber noch nen blöder Fehler drin *g*
  Mit Zitat antworten Zitat