如何以编程方式为管理员提供注册表项的所有权?

当我将一些机器升级到Windows 10时,我遇到了一个奇怪的问题,其中对RuntimeBroker的错误权限导致了问题。 我找到了一个在线解决方案 ,建议更改权限(首先在注册表中,然后在DCOM配置中),我正在尝试编写一个小型.NET应用程序来自动化该过程。

目前相关注册表项的所有者是NT SERVICE\TrustedInstaller ,我正在尝试将其更改为COMPUTER\Administrators 。 我有一个简单的WPF应用程序,其requestedExecutionLevel设置为“requireAdministrator”,但我仍遇到问题。 这是一段代码来说明问题:

 using System.Security.AccessControl; using System.Security.Principal; using Microsoft.Win32; namespace PermissionFixer { public class Fixer { public void Fix() { var subKey = Registry.ClassesRoot.OpenSubKey(@"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}", true); if (subKey != null) { var admins = new NTAccount("Administrators"); var ac = subKey.GetAccessControl(); ac.SetOwner(admins); ac.AddAccessRule(new RegistryAccessRule(admins, RegistryRights.FullControl, AccessControlType.Allow)); subKey.SetAccessControl(ac); } } } } 

麻烦的是,在遇到“不允许请求注册表访问”的SecurityException之前,它甚至没有超过对OpenSubKey()的调用。 我认为这是因为管理员还没有访问权限(记住它属于TrustedInstaller),但它变成了鸡蛋和鸡蛋的问题。 奇怪的是,当我手动使用regedit ,我可以将所有者更改为管理员,我很确定我的regedit实例是以管理员身份运行的。

我怎样才能在.NET中使用它?

我想通了,幸运的是,有可能用.NET类实现。 以下是调用OpenSubKey的方法:

 var subKey = Registry.ClassesRoot.OpenSubKey(@"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership); 

然后你必须调用AddAccessRule()的调用…在拥有所有权之前你不能修改它; 你必须连续进行这两项操作。 因此,首先获取所有权,然后重新打开具有不同访问权限的密钥以添加访问规则。

编辑:我今天发现你必须首先通过挂钩P / Invoke调用来操作运行应用程序的令牌。 我在另一个Stack Overflow问题中找到了一个名为TokenManipulator的类。 在项目中包含该类,然后在调用OpenSubKey之前为您的令牌授予Backup,Restore和TakeOwnership权限。 所以你的方法最终会看起来像这样:

 try { TokenManipulator.AddPrivilege("SeRestorePrivilege"); TokenManipulator.AddPrivilege("SeBackupPrivilege"); TokenManipulator.AddPrivilege("SeTakeOwnershipPrivilege"); var subKey = Registry.ClassesRoot.OpenSubKey(@"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership); // code to change owner... } finally { TokenManipulator.RemovePrivilege("SeRestorePrivilege"); TokenManipulator.RemovePrivilege("SeBackupPrivilege"); TokenManipulator.RemovePrivilege("SeTakeOwnershipPrivilege"); }