BluePointLilac/ContextMenuManager · error · PrivilegeNotHeldException
SeRestorePrivilege
Error message
SeRestorePrivilege
What it means
After SeTakeOwnershipPrivilege is enabled, the code enables SeRestorePrivilege (the Restore privilege) via NativeMethod.TrySetPrivilege(NativeMethod.Restore, true). This privilege is required to actually change the owner of a securable object — taking ownership alone does not let you write a new owner SID into the security descriptor. If TrySetPrivilege returns false, it throws PrivilegeNotHeldException with 'SeRestorePrivilege'.
Source
Thrown at ContextMenuManager/BluePointLilac.Methods/RegTrustedInstaller.cs:180
if(regPath.IsNullOrWhiteSpace()) return;
RegistryKey key = null;
WindowsIdentity id = null;
//利用试错判断是否有写入权限
try { key = RegistryEx.GetRegistryKey(regPath, true); }
catch
{
try
{
//获取当前用户的ID
id = WindowsIdentity.GetCurrent();
//添加TakeOwnership特权
bool flag = NativeMethod.TrySetPrivilege(NativeMethod.TakeOwnership, true);
if(!flag) throw new PrivilegeNotHeldException(NativeMethod.TakeOwnership);
//添加恢复特权(必须这样做才能更改所有者)
flag = NativeMethod.TrySetPrivilege(NativeMethod.Restore, true);
if(!flag) throw new PrivilegeNotHeldException(NativeMethod.Restore);
//打开没有权限的注册表路径
key = RegistryEx.GetRegistryKey(regPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership);
RegistrySecurity security = key.GetAccessControl(AccessControlSections.All);
//得到真正所有者
//IdentityReference oldId = security.GetOwner(typeof(SecurityIdentifier));
//SecurityIdentifier siTrustedInstaller = new SecurityIdentifier(oldId.ToString());
//使进程用户成为所有者
security.SetOwner(id.User);
key.SetAccessControl(security);
//添加完全控制
RegistryAccessRule fullAccess = new RegistryAccessRule(id.User, RegistryRights.FullControl,
InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow);
security.AddAccessRule(fullAccess);View on GitHub (pinned to 55507155dd)
Solutions
- Run as Administrator to obtain a full, unfiltered token with SeRestorePrivilege enabled
- Verify the privilege via Local Security Policy > User Rights Assignment > 'Restore files and directories'
- Run 'whoami /priv' in an elevated prompt to confirm SeRestorePrivilege shows as Enabled
- If the Administrators group was stripped of the right via GPO, restore it or run under an account that retains both privileges
Example fix
// before (passes TakeOwnership, fails on Restore)
NativeMethod.TrySetPrivilege(NativeMethod.TakeOwnership, true);
NativeMethod.TrySetPrivilege(NativeMethod.Restore, true);
// after (check both before attempting ownership change)
using(var identity = WindowsIdentity.GetCurrent())
{
var privs = identity.Token.GetPrivileges();
if(!privs.Contains("SeTakeOwnershipPrivilege") ||
!privs.Contains("SeRestorePrivilege"))
throw new InvalidOperationException(
"Both SeTakeOwnershipPrivilege and SeRestorePrivilege are required.");
} Defensive patterns
Strategy: validation
Validate before calling
static bool HasAllRequiredPrivileges()
{
// TrySetPrivilege with enable=false just checks availability without changing state
return NativeMethod.TrySetPrivilege(NativeMethod.TakeOwnership, false)
&& NativeMethod.TrySetPrivilege(NativeMethod.Restore, false);
}
if(!HasAllRequiredPrivileges())
throw new InvalidOperationException(
"Both SeTakeOwnershipPrivilege and SeRestorePrivilege are required."); Try / catch
catch(PrivilegeNotHeldException ex) when(ex.Privilege == "SeRestorePrivilege")
{
throw new InvalidOperationException(
"SeRestorePrivilege is required to change registry key owner. " +
"Run elevated and verify 'Restore files and directories' right.", ex);
} Prevention
- Both SeTakeOwnershipPrivilege AND SeRestorePrivilege are needed atomically — verify both before attempting ownership changes
- Use an elevated manifest (requestedExecutionLevel level='requireAdministrator') to guarantee a full token at startup
- Verify privileges with 'whoami /priv' — both must show as Enabled, not just Present
- If the Administrators group was stripped of the Restore right via GPO, coordinate with IT policy before proceeding
- Cache the result of the double-privilege check and surface a clear UI message rather than letting the exception propagate mid-operation
When it happens
Trigger: The process successfully enabled SeTakeOwnershipPrivilege but cannot enable SeRestorePrivilege, because the account/token lacks the 'Restore files and directories' user right. This can happen with an elevated token where the Restore right was removed by policy, or with a partially-restricted admin token.
Common situations: Admin elevation succeeded (so error [2] passes) but group policy removed the 'Restore files and directories' right from the Administrators group. Running under a custom service account that was granted TakeOwnership but not Restore. UAC-filted token that has Restore present-but-disabled and the enable call fails due to token restrictions.
Related errors
AI-assisted analysis of BluePointLilac/ContextMenuManager@55507155dd (2026-08-13).
Data as JSON: /api/errors/e25ee058bd41b357.
Report an issue: GitHub.