Get Registry Key ACL As Enum - Delphi

DarkCoderSc personal avatar
DarkCoderSc

Jean-Pierre LESUEUR

uses
  System.SysUtils, Winapi.Windows, Generics.Collections;

// ...

type
  TRegistryKeyPermission = (
    rkpRead,
    rkpWrite,
    rkpExecute,
    rkpQueryValue,
    rkpSetValue,
    rkpCreateSubKey,
    rkpEnumerateSubKeys,
    rkpNotify,
    rkpDelete
  );
  TRegistryKeyPermissions = set of TRegistryKeyPermission;

// ...

procedure GetCurrentUserRegistryKeyAccess(const AHive : HKEY; const AKeyPath : String; out ARegistryKeyPermissions : TRegistryKeyPermissions);
begin
  ARegistryKeyPermissions := [];
  ///

  var AImpersonated := False;

  var ASecurityDescriptorSize := DWORD(0);

  var ptrSecurityDescriptor := PSecurityDescriptor(nil);
  var hToken := THandle(0);
  ///

  var AKeyHandle := HKEY(0);
  try
    var AResult := RegOpenKeyExW(AHive, PWideChar(AKeyPath), 0, READ_CONTROL, AKeyHandle);
    if AResult <> ERROR_SUCCESS then
      raise EWindowsException.Create('RegOpenKeyW', AResult);
    ///

    AImpersonated := ImpersonateSelf(SecurityImpersonation);

    if not OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, False, hToken) then
      raise EWindowsException.Create('OpenProcessToken');
    ///

    var AFlags := OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION;

    AResult := RegGetKeySecurity(AKeyHandle, AFlags, nil, ASecurityDescriptorSize);
    if (AResult <> ERROR_SUCCESS) and (AResult <> 122) then
      raise EWindowsException.Create('GetNamedSecurityInfoW', AResult);

    GetMem(ptrSecurityDescriptor, ASecurityDescriptorSize);

    AResult := RegGetKeySecurity(AKeyHandle, AFlags, ptrSecurityDescriptor, ASecurityDescriptorSize);
    if AResult <> ERROR_SUCCESS then
      raise EWindowsException.Create('GetNamedSecurityInfoW', AResult);

    ///
    if AccessCheck(KEY_READ, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpRead);

    if AccessCheck(KEY_WRITE, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpWrite);

    if AccessCheck(KEY_EXECUTE, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpExecute);

    if AccessCheck(KEY_QUERY_VALUE, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpQueryValue);

    if AccessCheck(KEY_SET_VALUE, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpSetValue);

    if AccessCheck(KEY_CREATE_SUB_KEY, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpCreateSubKey);

    if AccessCheck(KEY_ENUMERATE_SUB_KEYS, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpEnumerateSubKeys);

    if AccessCheck(KEY_NOTIFY, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpNotify);

    if AccessCheck(_DELETE, hToken, ptrSecurityDescriptor) then
      Include(ARegistryKeyPermissions, rkpDelete);
  finally
    if AKeyHandle <> 0 then
      RegCloseKey(AKeyHandle);

    if Assigned(ptrSecurityDescriptor) then
      FreeMem(ptrSecurityDescriptor, ASecurityDescriptorSize);

    if hToken <> 0 then
      CloseHandle(hToken);

    if AImpersonated then
      RevertToSelf();
  end;
end;

// ...

procedure PrintAccess(const ARegistryKeyPermissions : TRegistryKeyPermissions);
begin
  var AList := TList<String>.Create();
  try
    if rkpRead in ARegistryKeypermissions then
      AList.Add('Read');
    if rkpWrite in ARegistryKeypermissions then
      AList.Add('Write');
    if rkpExecute in ARegistryKeypermissions then
      AList.Add('Execute');
    if rkpQueryValue in ARegistryKeypermissions then
      AList.Add('Query Value');
    if rkpSetValue in ARegistryKeypermissions then
      AList.Add('Set Value');
    if rkpCreateSubKey in ARegistryKeypermissions then
      AList.Add('Create Sub Key');
    if rkpEnumerateSubKeys in ARegistryKeypermissions then
      AList.Add('Enumerate Sub Keys');
    if rkpNotify in ARegistryKeypermissions then
      AList.Add('Notify');
    if rkpDelete in ARegistryKeypermissions then
      AList.Add('Delete');

    if AList.Count = 0 then
      WriteLn('No access')
    else
      WriteLn(String.Join(',', AList.ToArray));
  finally
    FreeAndNil(AList);
  end;
end;

begin
  try
    var ARegistryKeyPermissions : TRegistryKeyPermissions;
    GetCurrentUserRegistryKeyAccess(HKEY_LOCAL_MACHINE, 'Software', ARegistryKeyPermissions);

    WriteLn('HKLM\Software:');
    PrintAccess(ARegistryKeyPermissions);
  except
    on e : Exception do
      WriteLn(e.Message);
  end;

// ...

Creating and researching code snippets takes time and effort. You’re welcome to share them through your own platforms, but please don’t forget to credit the original author, here: Jean-Pierre LESUEUR.

no AI logo


Depends On


Created

December 2, 2025

Last Revised

December 2, 2025