Enumerating Registry Key Permissions

Share your advanced PureBasic knowledge/code with the community.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Enumerating Registry Key Permissions

Post by SFSxOI »

Nothing special, just a snippet of C++ code from work for a larger project that I quickly converted to PureBasic and stuffed it in a procedure. Thought it might help someone. Should be easy to adapt to most needs. Gets the account permissions for a registry key (actually a sub key of a main hive key). This is raw code, not refined in any way, there will be clean up and changes in my final code (see some of the notes in the code, they might give you some ideas too so i left some of the notes in). Only been tested on Windows 7 x86, didn't test on 64 bit yet.

Code: Select all

Structure SID
  Revision.b
  SubAuthorityCount.b
  *IdentifierAuthority.SID_IDENTIFIER_AUTHORITY
  SubAuthority.l[#ANYSIZE_ARRAY]
EndStructure

Enumeration ;ACL_INFORMATION_CLASS
  #AclRevisionInformation = 1
  #AclSizeInformation
EndEnumeration

Enumeration ; SID_NAME_USE
  #SidTypeUser = 1
  #SidTypeGroup
  #SidTypeDomain
  #SidTypeAlias
  #SidTypeWellKnownGroup
  #SidTypeDeletedAccount
  #SidTypeInvalid
  #SidTypeUnknown
  #SidTypeComputer
  #SidTypeLabel
EndEnumeration

#DACL_SECURITY_INFORMATION = $00000004 ; Include the discretionary access control List (DACL).

Procedure.q TopHiveKey(HiveKeyConvert$)
  Protected HiveKeyx.q
  
  If Right(HiveKeyConvert$, 1) = "\"
    HiveKeyConvert$ = RemoveString(HiveKeyConvert$, "\", #PB_String_NoCase, Len(HiveKeyConvert$) - 1, 1)
  EndIf
  
  HiveKeya$=StringField(HiveKeyConvert$,1,"\")
  HiveKeyTop$=UCase(HiveKeya$)
  Select HiveKeyTop$
    Case "HKEY_CLASSES_ROOT"
      HiveKeyx = #HKEY_CLASSES_ROOT 
    Case "HKEY_CURRENT_USER"
      HiveKeyx = #HKEY_CURRENT_USER
    Case "HKEY_LOCAL_MACHINE"
      HiveKeyx = #HKEY_LOCAL_MACHINE
    Case "HKEY_USERS"
      HiveKeyx = #HKEY_USERS
    Case "HKEY_CURRENT_CONFIG"
      HiveKeyx = #HKEY_CURRENT_CONFIG
    Default
      HiveKeyx = #Null
  EndSelect
  ProcedureReturn HiveKeyx
  
EndProcedure

Procedure.s KeyConvert(KeyToConvert$)
  
  If Right(KeyToConvert$, 1) = "\"
    KeyToConvert$ = RemoveString(KeyToConvert$, "\", #PB_String_NoCase, Len(KeyToConvert$) - 1, 1)
  EndIf
  
  GetBackSlash=FindString(KeyToConvert$,"\",1)
  KeyNameX$=Right(KeyToConvert$,(Len(KeyToConvert$)-GetBackSlash))
  If Left(KeyNameX$, 1) = "\" 
    KeyNameX$ = Right(KeyNameX$, Len(KeyNameX$) - 1) 
  EndIf
  ProcedureReturn KeyNameX$
EndProcedure

Procedure.s Reg_EnumAccountKeyAccessPermission(Key.s, sel_out.i, sid_count.i)
  Protected HiveKey.q, KeyName$, bRtnBool.b, FuncRet.i, retfunc.i, hKey.i
  Protected *pSecDesc.SECURITY_DESCRIPTOR, *pDacl.ACL, *pAce.ACCESS_ALLOWED_ACE, aclSize.ACL_SIZE_INFORMATION
  Protected szAccountName.s, szDomainName.s, dwAccountNameSize.i, dwDomainNameSize.i, snu.i
  Protected bDaclDefault.b, bDaclPresent.b, nLengthNeeded.l = 0, aclAceCount.i, acl_ACECount.i
  
  HiveKey = TopHiveKey(Key)
  KeyName$ = KeyConvert(Key)
  
  FuncRet = RegOpenKeyEx_(HiveKey, @KeyName$, 0, #KEY_ALL_ACCESS, @hKey)
  
  If FuncRet = #ERROR_SUCCESS
      
    retfunc = RegGetKeySecurity_(hKey, #DACL_SECURITY_INFORMATION, #Null, @nLengthNeeded)
    If retfunc = #ERROR_INSUFFICIENT_BUFFER
      *pSecDesc = LocalAlloc_(#LPTR, nLengthNeeded) ; can't use LocalAlloc in final - swap for heap function in final
      If *pSecDesc = #Null
        ProcedureReturn ""
      EndIf
      retfunc = RegGetKeySecurity_(hKey, #DACL_SECURITY_INFORMATION, *pSecDesc, @nLengthNeeded)
    EndIf
    
    If retfunc = #ERROR_SUCCESS
      If *pSecDesc
        GetSecurityDescriptorDacl_(*pSecDesc, @bDaclPresent, @*pDacl, @bDaclDefault)
        If bDaclPresent = 0
          RegCloseKey_(hKey)
          ProcedureReturn "No DACL"
        Else
          GetAclInformation_(*pDacl, @aclSize, SizeOf(aclSize), #AclSizeInformation)
          If sel_out = 0
            acl_ACECount = aclSize\AceCount
            LocalFree_(*pSecDesc); can't use LocalFree in final - swap for heap function in final
            RegCloseKey_(hKey)
          EndIf
          If sel_out > 0 And sel_out < 4
            ;For aclAceCount = 0 To aclSize\AceCount
            GetAce_(*pDacl, sid_count, @*pAce)
            
            bRtnBool = LookupAccountSid_(#Null, @*pAce\SidStart, 0, @dwAccountNameSize, 0, @dwDomainNameSize, @snu)
            szAccountName = Space(dwAccountNameSize)
            szDomainName = Space(dwDomainNameSize)
            bRtnBool = LookupAccountSid_(#Null, @*pAce\SidStart, @szAccountName, @dwAccountNameSize, @szDomainName, @dwDomainNameSize, @snu)
            
            ; If-EndIf section below to be replaced by array later
            ; Specific Access Rights
            If *pAce\Mask & #KEY_QUERY_VALUE = #KEY_QUERY_VALUE
              SpecificAcess$ + "KEY_QUERY_VALUE -  "
              If *pAce\Mask & #KEY_SET_VALUE = #KEY_SET_VALUE
                SpecificAcess$ + "KEY_SET_VALUE -  "
                If *pAce\Mask & #KEY_CREATE_SUB_KEY = #KEY_CREATE_SUB_KEY
                  SpecificAcess$ + "KEY_CREATE_SUB_KEY -  "
                  If *pAce\Mask & #KEY_ENUMERATE_SUB_KEYS = #KEY_ENUMERATE_SUB_KEYS
                    SpecificAcess$ + "KEY_ENUMERATE_SUB_KEYS -  "
                    If *pAce\Mask & #KEY_NOTIFY = #KEY_NOTIFY
                      SpecificAcess$ + "KEY_NOTIFY -  "
                      If *pAce\Mask & #KEY_CREATE_LINK = #KEY_CREATE_LINK
                        SpecificAcess$ + "KEY_CREATE_LINK -  "
                        If *pAce\Mask & #KEY_READ = #KEY_READ
                          SpecificAcess$ + "KEY_READ -  " ; ;KEY_EXECUTE (0x20019)
                          If *pAce\Mask & #KEY_WRITE = #KEY_WRITE
                            SpecificAcess$ + "KEY_WRITE -  "
                            If *pAce\Mask & #KEY_EXECUTE = #KEY_EXECUTE
                              SpecificAcess$ + "KEY_EXECUTE -  " ; same As KEY_READ (0x20019)
                              If *pAce\Mask & #KEY_ALL_ACCESS = #KEY_ALL_ACCESS
                                SpecificAcess$ + "KEY_ALL_ACCESS -  "
                              EndIf
                            EndIf
                          EndIf
                        EndIf
                      EndIf
                    EndIf
                  EndIf
                EndIf
              EndIf
            EndIf
            SpecificAcess$ = RemoveString(SpecificAcess$, " - ", #PB_String_NoCase, Len(SpecificAcess$) - 3, 1) ; goes away later with string formatting
            
            ;Standard Access Rights
            If *pAce\Mask & #DELETE = #DELETE
              StandardAcess$ + "DELETE -  "
              If *pAce\Mask & #READ_CONTROL = #READ_CONTROL
                StandardAcess$ + "READ_CONTROL -  "
                If *pAce\Mask & #WRITE_DAC = #WRITE_DAC
                  StandardAcess$ + "WRITE_DAC -  "
                  If *pAce\Mask & #WRITE_OWNER = #WRITE_OWNER
                    StandardAcess$ + "WRITE_OWNER -  "
                    If *pAce\Mask & #SYNCHRONIZE = #SYNCHRONIZE
                      StandardAcess$ + "SYNCHRONIZE -  "
                      If *pAce\Mask & #STANDARD_RIGHTS_REQUIRED = #STANDARD_RIGHTS_REQUIRED
                        StandardAcess$ + "STANDARD_RIGHTS_REQUIRED -  "
                        If *pAce\Mask & #STANDARD_RIGHTS_READ = #STANDARD_RIGHTS_READ
                          StandardAcess$ + "STANDARD_RIGHTS_READ -  "
                          If *pAce\Mask & #STANDARD_RIGHTS_WRITE = #STANDARD_RIGHTS_WRITE
                            StandardAcess$ + "STANDARD_RIGHTS_WRITE -  "
                            If *pAce\Mask & #STANDARD_RIGHTS_EXECUTE = #STANDARD_RIGHTS_EXECUTE
                              StandardAcess$ + "STANDARD_RIGHTS_EXECUTE -  "
                              If *pAce\Mask & #STANDARD_RIGHTS_ALL = #STANDARD_RIGHTS_ALL
                                StandardAcess$ + "STANDARD_RIGHTS_ALL -  "
                                If *pAce\Mask & #SPECIFIC_RIGHTS_ALL = #SPECIFIC_RIGHTS_ALL
                                  StandardAcess$ + "SPECIFIC_RIGHTS_ALL -  "
                                EndIf
                              EndIf
                            EndIf
                          EndIf
                        EndIf
                      EndIf
                    EndIf
                  EndIf
                EndIf
              EndIf
            EndIf
            StandardAcess$ = RemoveString(StandardAcess$, " - ", #PB_String_NoCase, Len(StandardAcess$) - 3, 1); goes away later with string formatting
            ; ************* If-EndIf section above to be replaced by array later ********
            
            ; ************below not used this implementation - later use in framework
            ;Select snu
              ;Case #SidTypeUser
                ;sidtypeuse$ = "User SID"
              ;Case #SidTypeGroup
                ;sidtypeuse$ = "Group SID"
              ;Case #SidTypeDomain
                ;sidtypeuse$ = "Domain SID"
              ;Case #SidTypeAlias
                ;sidtypeuse$ = "Alias SID"
              ;Case #SidTypeWellKnownGroup
                ;sidtypeuse$ = "SID for a well-known group"
              ;Case #SidTypeDeletedAccount
                ;sidtypeuse$ = "SID for a deleted account"
              ;Case #SidTypeInvalid
                ;sidtypeuse$ = "SID that is not valid"
              ;Case #SidTypeUnknown
                ;sidtypeuse$ = "SID of unknown type"
              ;Case #SidTypeComputer
                ;sidtypeuse$ = "SID for a computer"
              ;Case #SidTypeLabel
                ;sidtypeuse$ = "Mandatory integrity label SID"
              ;Default
                ;sidtypeuse$ = "SID of unknown type"
                ;EndSelect
                ;************** end section not used this implementation
            
            Select *pAce\Header\AceType
              Case #ACCESS_ALLOWED_ACE_TYPE
                AceType$ = "ACCESS_ALLOWED_ACE_TYPE"
                ;Break
              Case #ACCESS_DENIED_ACE_TYPE
                AceType$ = "ACCESS_DENIED_ACE_TYPE"
                ;Break
              Case #SYSTEM_AUDIT_ACE_TYPE
                AceType$ = "SYSTEM_AUDIT_ACE_TYPE"
                ;Break
              Default
                AceType$ = "Unknown ACE type"
                ;Break
            EndSelect
            ;Next aclAceCount
            LocalFree_(*pSecDesc); can't use LocalFree in final - swap for heap function in final
            RegCloseKey_(hKey)
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
      
    Select sel_out
      Case 0
        procret$ = Str(acl_ACECount)
      Case 1
        procret$ = "Account = " + szAccountName + "  Domain = " + szDomainName + "  Specific Access Rights = " + SpecificAcess$ ; specific access rights
      Case 2
        procret$ = "Account = " + szAccountName + "  Domain = " + szDomainName + "  Standard Access Rights = " + StandardAcess$ ; standard access rights
      Case 3
        procret$ = "Account = " + szAccountName + "  Domain = " + szDomainName + "  ACE Type = " +  AceType$; ACE Type
      Default ; just for form and in case
        procret$ = "Invalid output selection."
    EndSelect
    
    ProcedureReturn procret$

EndProcedure
  
  ; Reg_EnumAccountKeyAccessPermission(Key.s, sel_out.i, sid_count.i)
  ; Where: Key.s is the registry key we want permissions for - sel_out is the return we want (see last select -endselect in code) - sid_count is the account we are getting information for (0 to max available)
  ; first, get the acl ace count to find the max number of accounts with DACL we can query
  acecnt_max_available.i = Val(Reg_EnumAccountKeyAccessPermission("HKEY_CURRENT_USER\Control Panel\TestKey", 0, 0))
  Debug "Maximum available accounts with DACL = " + Str(acecnt_max_available) ; the number of accounts - the first account starts at 0 and goes to the max 'acecnt' (max available)
  Debug ""
  ; now the loop to enum
  For i = 0 To acecnt_max_available - 1
    Debug Reg_EnumAccountKeyAccessPermission("HKEY_CURRENT_USER\Control Panel", 1, i)
    Debug ""
    Debug Reg_EnumAccountKeyAccessPermission("HKEY_CURRENT_USER\Control Panel", 2, i)
    Debug ""
    Debug Reg_EnumAccountKeyAccessPermission("HKEY_CURRENT_USER\Control Panel", 3, i)
    Debug ""
  Next
  
  ; notice the rem'd out loop in the code, thats for putting the stuff in an array later - and removing the 'sid_count' parameter - not implemented yet

Note: Just changed the post code to remove the extra calls to the procedure in the enum loop, left 'em in by accident while i was checking something else, sorry 'bout that
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Enumerating Registry Key Permissions

Post by SFSxOI »

This is an example of the returned information:

Code: Select all

Maximum available accounts with DACL = 4

Account = MMXC  Domain = MMXC-PC  Specific Access Rights = KEY_QUERY_VALUE -  KEY_SET_VALUE -  KEY_CREATE_SUB_KEY -  KEY_ENUMERATE_SUB_KEYS -  KEY_NOTIFY -  KEY_CREATE_LINK -  KEY_READ -  KEY_WRITE -  KEY_EXECUTE -  KEY_ALL_ACCESS 

Account = MMXC  Domain = MMXC-PC  Standard Access Rights = DELETE -  READ_CONTROL -  WRITE_DAC -  WRITE_OWNER 

Account = MMXC  Domain = MMXC-PC  ACE Type = ACCESS_ALLOWED_ACE_TYPE

Account = SYSTEM  Domain = NT AUTHORITY  Specific Access Rights = KEY_QUERY_VALUE -  KEY_SET_VALUE -  KEY_CREATE_SUB_KEY -  KEY_ENUMERATE_SUB_KEYS -  KEY_NOTIFY -  KEY_CREATE_LINK -  KEY_READ -  KEY_WRITE -  KEY_EXECUTE -  KEY_ALL_ACCESS 

Account = SYSTEM  Domain = NT AUTHORITY  Standard Access Rights = DELETE -  READ_CONTROL -  WRITE_DAC -  WRITE_OWNER 

Account = SYSTEM  Domain = NT AUTHORITY  ACE Type = ACCESS_ALLOWED_ACE_TYPE

Account = Administrators  Domain = BUILTIN  Specific Access Rights = KEY_QUERY_VALUE -  KEY_SET_VALUE -  KEY_CREATE_SUB_KEY -  KEY_ENUMERATE_SUB_KEYS -  KEY_NOTIFY -  KEY_CREATE_LINK -  KEY_READ -  KEY_WRITE -  KEY_EXECUTE -  KEY_ALL_ACCESS 

Account = Administrators  Domain = BUILTIN  Standard Access Rights = DELETE -  READ_CONTROL -  WRITE_DAC -  WRITE_OWNER 

Account = Administrators  Domain = BUILTIN  ACE Type = ACCESS_ALLOWED_ACE_TYPE

Account = RESTRICTED  Domain = NT AUTHORITY  Specific Access Rights = KEY_QUERY_VALUE 

Account = RESTRICTED  Domain = NT AUTHORITY  Standard Access Rights = 

Account = RESTRICTED  Domain = NT AUTHORITY  ACE Type = ACCESS_ALLOWED_ACE_TYPE


The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Post Reply