2

After reading this question and this blog post I came up with these commands

Set-Location HKLM:\Software\Classes\cmdfile\ShellEx\PropertySheetHandlers
$am = New-Object Security.Principal.NTAccount 'BUILTIN', 'Administrators'
$ke = Get-Acl 'ShimLayer Property Page'
$ke.SetOwner($am)
Set-Acl -AclObject $ke -Path 'ShimLayer Property Page'

However when I run them I get this message

Set-Acl : Requested registry access is not allowed.

How can I change the owner of this key?

Community
  • 1
  • 1
Zombo
  • 1
  • 62
  • 391
  • 407

3 Answers3

6

After reading these

Changing owner of key to Administrator

Set controls on files owned by TrustedInstaller

I came up with this working solution.

Function Enable-Privilege {
  param($Privilege)
  $Definition = @'
using System;
using System.Runtime.InteropServices;
public class AdjPriv {
  [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
  internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
    ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr rele);
  [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
  internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
  [DllImport("advapi32.dll", SetLastError = true)]
  internal static extern bool LookupPrivilegeValue(string host, string name,
    ref long pluid);
  [StructLayout(LayoutKind.Sequential, Pack = 1)]
  internal struct TokPriv1Luid {
    public int Count;
    public long Luid;
    public int Attr;
  }
  internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
  internal const int TOKEN_QUERY = 0x00000008;
  internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
  public static bool EnablePrivilege(long processHandle, string privilege) {
    bool retVal;
    TokPriv1Luid tp;
    IntPtr hproc = new IntPtr(processHandle);
    IntPtr htok = IntPtr.Zero;
    retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
      ref htok);
    tp.Count = 1;
    tp.Luid = 0;
    tp.Attr = SE_PRIVILEGE_ENABLED;
    retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
    retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,
      IntPtr.Zero);
    return retVal;
  }
}
'@
  $ProcessHandle = (Get-Process -id $pid).Handle
  $type = Add-Type $definition -PassThru
  $type[0]::EnablePrivilege($processHandle, $Privilege)
}

do {} until (Enable-Privilege SeTakeOwnershipPrivilege)
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
  'Software\Classes\cmdfile\ShellEx\PropertySheetHandlers\ShimLayer Property Page',
  'ReadWriteSubTree', 'TakeOwnership')
$owner = [Security.Principal.NTAccount]'Administrators'
$acl = $key.GetAccessControl()
$acl.SetOwner($owner)
$key.SetAccessControl($acl)
Community
  • 1
  • 1
Zombo
  • 1
  • 62
  • 391
  • 407
  • Note that you may need to change `$key=...LocalMachine` to something else like `ClassesRoot` like I needed to. Otherwise you're the only one that helped me out ! – Thibault Nov 06 '18 at 16:20
  • Nice solution, I made some adjustments and used for me needs to take ownership of the reg keys and then set the read access to deny for everyone to prevent options from showing up in File Explorer on some public PCs we are locking down tight. Very nice solution with the C code definition, etc. and allowing that to be run in PowerShell. I would have never figured this out. otherwise as all other solutions did not work that I tried. – Bitcoin Murderous Maniac Aug 02 '19 at 18:11
1

If the administrator group has been removed from the ACL then you will end up with this error. But you can use OpenSubKey() method to Retrieves the specified subkey for read or read/write access, requesting the specified access rights.

$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("Software\Classes\cmdfile\ShellEx\PropertySheetHandlers",[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::ChangePermissions)

Once you have it then you can use GetAccessControl() and SetAccessControl() method to get the permission back

$acl = $key.GetAccessControl()
$key.SetAccessControl($acl)

See this post for more information.

EDIT:

One more way to set the access control of registry

$ke = Get-Acl 'HKLM:\Software\Classes\cmdfile\ShellEx\PropertySheetHandlers\ShimLayer Property Page'

$rule = New-Object System.Security.AccessControl.RegistryAccessRule ("mydomain\myusername","FullControl","Allow")

$ke.SetAccessRule($rule)

$ke |Set-Acl -Path 'HKLM:\Software\Classes\cmdfile\ShellEx\PropertySheetHandlers\ShimLayer Property Page'
Rahul
  • 76,197
  • 13
  • 71
  • 125
  • @StevenPenny, it's related to registry else I would have tried before posting the answer but it should work per documentation. Edited the answer and removed `HKLM:\`. give it a try. – Rahul Jun 23 '14 at 17:26
  • 2
    Thanks for editing but you still have the wrong key, it is supposed to be `ShimLayer Property Page` as shown in the question. When using your command with that key I get `Exception calling "OpenSubKey" with "3" argument(s): "Requested registry access is not allowed."` – Zombo Jun 23 '14 at 17:52
1

Try it out:

# group BULTIN\Users takes full control of key and all subkeys
Take-Permissions("HKLM", "SOFTWARE\test")

# group Everyone takes full control of key and all subkeys
Take-Permissions("HKLM", "SOFTWARE\test", "S-1-1-0")

# group Everyone takes full control of key WITHOUT subkeys
Take-Permissions("HKLM", "SOFTWARE\test", "S-1-1-0", $false)

Just define this function:

function Take-Permissions {
    # Developed for PowerShell v4.0
    # Required Admin privileges
    # Links:
    #   http://shrekpoint.blogspot.ru/2012/08/taking-ownership-of-dcom-registry.html
    #   http://www.remkoweijnen.nl/blog/2012/01/16/take-ownership-of-a-registry-key-in-powershell/
    #   https://powertoe.wordpress.com/2010/08/28/controlling-registry-acl-permissions-with-powershell/

    param($rootKey, $key, [System.Security.Principal.SecurityIdentifier]$sid = 'S-1-5-32-545', $recurse = $true)

    switch -regex ($rootKey) {
        'HKCU|HKEY_CURRENT_USER'    { $rootKey = 'CurrentUser' }
        'HKLM|HKEY_LOCAL_MACHINE'   { $rootKey = 'LocalMachine' }
        'HKCR|HKEY_CLASSES_ROOT'    { $rootKey = 'ClassesRoot' }
        'HKCC|HKEY_CURRENT_CONFIG'  { $rootKey = 'CurrentConfig' }
        'HKU|HKEY_USERS'            { $rootKey = 'Users' }
    }

    ### Step 1 - escalate current process's privilege
    # get SeTakeOwnership, SeBackup and SeRestore privileges before executes next lines, script needs Admin privilege
    $import = '[DllImport("ntdll.dll")] public static extern int RtlAdjustPrivilege(ulong a, bool b, bool c, ref bool d);'
    $ntdll = Add-Type -Member $import -Name NtDll -PassThru
    $privileges = @{ SeTakeOwnership = 9; SeBackup =  17; SeRestore = 18 }
    foreach ($i in $privileges.Values) {
        $null = $ntdll::RtlAdjustPrivilege($i, 1, 0, [ref]0)
    }

    function Take-KeyPermissions {
        param($rootKey, $key, $sid, $recurse, $recurseLevel = 0)

        ### Step 2 - get ownerships of key - it works only for current key
        $regKey = [Microsoft.Win32.Registry]::$rootKey.OpenSubKey($key, 'ReadWriteSubTree', 'TakeOwnership')
        $acl = New-Object System.Security.AccessControl.RegistrySecurity
        $acl.SetOwner($sid)
        $regKey.SetAccessControl($acl)

        ### Step 3 - enable inheritance of permissions (not ownership) for current key from parent
        $acl.SetAccessRuleProtection($false, $false)
        $regKey.SetAccessControl($acl)

        ### Step 4 - only for top-level key, change permissions for current key and propagate it for subkeys
        # to enable propagations for subkeys, it needs to execute Steps 2-3 for each subkey (Step 5)
        if ($recurseLevel -eq 0) {
            $regKey = $regKey.OpenSubKey('', 'ReadWriteSubTree', 'ChangePermissions')
            $rule = New-Object System.Security.AccessControl.RegistryAccessRule($sid, 'FullControl', 'ContainerInherit', 'None', 'Allow')
            $acl.ResetAccessRule($rule)
            $regKey.SetAccessControl($acl)
        }

        ### Step 5 - recursively repeat steps 2-5 for subkeys
        if ($recurse) {
            foreach($subKey in $regKey.OpenSubKey('').GetSubKeyNames()) {
                Take-KeyPermissions $rootKey ($key+'\'+$subKey) $sid $recurse ($recurseLevel+1)
            }
        }
    }

    Take-KeyPermissions $rootKey $key $sid $recurse
}
Argimko
  • 516
  • 5
  • 12