更改注册表文件夹权限会引发访问被拒绝
Posted
技术标签:
【中文标题】更改注册表文件夹权限会引发访问被拒绝【英文标题】:Changing Registry Folder Permissions throws Access denied 【发布时间】:2015-06-29 11:15:08 【问题描述】:我尝试使用以下代码更改一些注册权限:
$acl = Get-Acl HKLM:\SYSTEM\CurrentControlSet\Services\TrustedInstaller
$inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$Rule = New-Object System.Security.AccessControl.RegistryAccessRule ("Administrators","FullControl","ContainerInherit","none","Allow")
$acl.AddAccessRule($Rule)
$acl | Set-Acl
当我运行它时,我收到错误
set-acl : Der angeforderte Registrierungszugriff ist unzulässig.
In C:\perm.ps1:6 Zeichen:8
+ $acl | set-acl
+ ~~~~~~~
+ CategoryInfo : PermissionDenied: (HKEY_LOCAL_MACH...rustedInstaller:String) [Set-Acl], SecurityException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShell.Commands.SetAclCommand
当我在注册表中手动将权限更改为完全访问时,我没有收到错误消息。我在与修改权限成功的 regedit 相同的用户下运行 Powershell-Script。 (使用 Powershell ISE)
【问题讨论】:
您是否在提升的会话中运行 ISE? 以“以管理员身份运行”开始 请显示完整的错误信息。 您可能需要先获得树的所有权,然后才能将管理员添加到访问控制列表中。 @AnsgarWiechers 实际上有趣的问题,我已经尝试使用 procmon 进行调试,Powershell 提升访问被拒绝,同时声称权限“读/写”,而regedit.exe
声称“查询值,枚举子键, Read Control, Write DAC" 并获得成功。
【参考方案1】:
显然您在尝试通过不受信任的应用程序 (Powershell) 修改 TrustedInstaller 的注册表项时遇到了Windows File Protection self-defence。 Regedit 可能不受此规则的约束,或者被该服务传递地允许更改此 ACL。 (可能 regedit.exe 在启动时获得所有权特权,这就是重点)链接的问题包含一个解决方案,另一个副本可用here。我把它复制到这里。
function enable-privilege
param(
## The privilege to adjust. This set is taken from
## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
[ValidateSet(
"SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
"SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
"SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
"SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
"SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
"SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
"SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
"SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
"SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
"SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
"SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
$Privilege,
## The process on which to adjust the privilege. Defaults to the current process.
$ProcessId = $pid,
## Switch to disable the privilege, rather than enable it.
[Switch] $Disable
)
## Taken from P/Invoke.NET with minor adjustments.
$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 relen);
[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 SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
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;
if(disable)
tp.Attr = SE_PRIVILEGE_DISABLED;
else
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 $ProcessId).Handle
$type = Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
enable-privilege SeTakeOwnershipPrivilege
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("SOFTWARE\powertoe",[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::takeownership)
# You must get a blank acl for the key b/c you do not currently have access
$acl = $key.GetAccessControl([System.Security.AccessControl.AccessControlSections]::None)
$me = [System.Security.Principal.NTAccount]"t-alien\tome"
$acl.SetOwner($me)
$key.SetAccessControl($acl)
# After you have set owner you need to get the acl with the perms so you can modify it.
$acl = $key.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ("T-Alien\Tome","FullControl","Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)
$key.Close()
此解决方案未经测试,尽管毫无疑问它不会起作用。
【讨论】:
以上是关于更改注册表文件夹权限会引发访问被拒绝的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用 FileLock、Python 写入文件时权限被拒绝