如何从 C# 中删除注册表符号 link 键:"An error is preventing this key from being opened. Details: Access is denied"
How to delete registry symbolic link key from C#: "An error is preventing this key from being opened. Details: Access is denied"
我使用 NtObjectManager library 创建了一个符号注册表项:
using NtApiDotNet;
using System;
namespace poc
{
class Program
{
const string SrcKey = @"HKEY_CURRENT_USER\SOFTWARE\ABC";
const string TargetKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\XYZ";
static NtKey CreateSymbolicLink(string name, string target)
{
name = NtKeyUtils.Win32KeyNameToNt(name);
target = NtKeyUtils.Win32KeyNameToNt(target);
return NtKey.CreateSymbolicLink(name, null, target);
}
static void Main(string[] args)
{
var link = CreateSymbolicLink(SrcKey, TargetKey)
}
}
}
当我尝试从注册表 (Regedit.exe
) 中删除密钥时,失败并出现错误:
ABC cannot be opened. An error is preventing this key from being
opened. Details: Access is denied
即使有 SYSTEM
权限(使用 psexec
启动 SYSTEM
cmd)我也试图删除它,但我仍然收到同样的错误。
函数NtKey.CreateSymbolicLink
是calling SetSymbolicLinkTarget
which calls eventually到SetValue
这样的:
SetValue(SymbolicLinkValueName, RegistryValueType.Link, Encoding.Unicode.GetBytes(target), throw_on_error);
我还没想好怎么删除它。
我找到了关于使用 C++ 删除符号注册表项的 ,但它只是调用 lpfnZwDeleteKey
,我不知道 C# 的等价物是什么。
我尝试了 NtKey.UnloadKey
函数,我认为它可能有帮助,但没有。
我可以使用 James 的工具 CreateRegSymlink
删除它:
CreateRegSymlink.exe -d "HKCU\Software\XYZ"
我注意到 calling DeleteRegSymlink
正在做这件事。
当我检查什么是 inside it 时,我注意到它通过调用 RegPathToNative
:
将注册表路径转换为真实路径
bstr_t symlink = RegPathToNative(lpSymlink);
Here 你可以看到 RegPathToNative
的工作。
然后它调用:
InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE | OBJ_OPENLINK, nullptr, nullptr);
我认为这是神奇的地方。
如果您对如何从符号注册表路径中找到真正的 link 有任何建议,请告诉我。
编辑(10/1/2022)-感谢@RbMm:
我创建了一个使用 REG_OPTION_OPEN_LINK
打开 symlink 的函数,然后使用 ZwDeleteKey
删除它,但重要的是将权限设置为 RegistryRights.Delete
正如@RbMm 提到的:
const int REG_OPTION_OPEN_LINK = 0x0008;
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
static extern int RegOpenKeyExW(SafeRegistryHandle hKey, String lpSubKey,
int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
[DllImport("ntdll.dll")]
private static extern int ZwDeleteKey(SafeRegistryHandle hKey);
public static RegistryKey OpenSubKeySymLink(this RegistryKey key, string name, RegistryRights rights = RegistryRights.ReadKey, RegistryView view = 0)
{
var error = RegOpenKeyExW(key.Handle, name, REG_OPTION_OPEN_LINK, ((int)rights) | ((int)view), out var subKey);
if (error != 0)
{
subKey.Dispose();
throw new Win32Exception(error);
}
return RegistryKey.FromHandle(subKey); // RegistryKey will dispose subKey
}
static void Main(string[] args)
{
RegistryKey key;
key = OpenSubKeySymLink(Microsoft.Win32.Registry.CurrentUser, @"SOFTWARE\Microsoft\Windows\ABC", RegistryRights.Delete, 0);
ZwDeleteKey(key.Handle);
}
我使用 NtObjectManager library 创建了一个符号注册表项:
using NtApiDotNet;
using System;
namespace poc
{
class Program
{
const string SrcKey = @"HKEY_CURRENT_USER\SOFTWARE\ABC";
const string TargetKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\XYZ";
static NtKey CreateSymbolicLink(string name, string target)
{
name = NtKeyUtils.Win32KeyNameToNt(name);
target = NtKeyUtils.Win32KeyNameToNt(target);
return NtKey.CreateSymbolicLink(name, null, target);
}
static void Main(string[] args)
{
var link = CreateSymbolicLink(SrcKey, TargetKey)
}
}
}
当我尝试从注册表 (Regedit.exe
) 中删除密钥时,失败并出现错误:
ABC cannot be opened. An error is preventing this key from being opened. Details: Access is denied
即使有 SYSTEM
权限(使用 psexec
启动 SYSTEM
cmd)我也试图删除它,但我仍然收到同样的错误。
函数NtKey.CreateSymbolicLink
是calling SetSymbolicLinkTarget
which calls eventually到SetValue
这样的:
SetValue(SymbolicLinkValueName, RegistryValueType.Link, Encoding.Unicode.GetBytes(target), throw_on_error);
我还没想好怎么删除它。
我找到了关于使用 C++ 删除符号注册表项的 lpfnZwDeleteKey
,我不知道 C# 的等价物是什么。
我尝试了 NtKey.UnloadKey
函数,我认为它可能有帮助,但没有。
我可以使用 James 的工具 CreateRegSymlink
删除它:
CreateRegSymlink.exe -d "HKCU\Software\XYZ"
我注意到 calling DeleteRegSymlink
正在做这件事。
当我检查什么是 inside it 时,我注意到它通过调用 RegPathToNative
:
bstr_t symlink = RegPathToNative(lpSymlink);
Here 你可以看到 RegPathToNative
的工作。
然后它调用:
InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE | OBJ_OPENLINK, nullptr, nullptr);
我认为这是神奇的地方。
如果您对如何从符号注册表路径中找到真正的 link 有任何建议,请告诉我。
编辑(10/1/2022)-感谢@RbMm:
我创建了一个使用 REG_OPTION_OPEN_LINK
打开 symlink 的函数,然后使用 ZwDeleteKey
删除它,但重要的是将权限设置为 RegistryRights.Delete
正如@RbMm 提到的:
const int REG_OPTION_OPEN_LINK = 0x0008;
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
static extern int RegOpenKeyExW(SafeRegistryHandle hKey, String lpSubKey,
int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
[DllImport("ntdll.dll")]
private static extern int ZwDeleteKey(SafeRegistryHandle hKey);
public static RegistryKey OpenSubKeySymLink(this RegistryKey key, string name, RegistryRights rights = RegistryRights.ReadKey, RegistryView view = 0)
{
var error = RegOpenKeyExW(key.Handle, name, REG_OPTION_OPEN_LINK, ((int)rights) | ((int)view), out var subKey);
if (error != 0)
{
subKey.Dispose();
throw new Win32Exception(error);
}
return RegistryKey.FromHandle(subKey); // RegistryKey will dispose subKey
}
static void Main(string[] args)
{
RegistryKey key;
key = OpenSubKeySymLink(Microsoft.Win32.Registry.CurrentUser, @"SOFTWARE\Microsoft\Windows\ABC", RegistryRights.Delete, 0);
ZwDeleteKey(key.Handle);
}