Home > database >  How to delete registry symbolic link key from C#: "An error is preventing this key from being o
How to delete registry symbolic link key from C#: "An error is preventing this key from being o

Time:01-10

I created a symbolic registry key by using the NtObjectManager library like that:

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)
        }
    }
}

When I tried to delete the key from Registry (Regedit.exe) it failed with error:

ABC cannot be opened. An error is preventing this key from being opened. Details: Access is denied

I tried to delete it even with SYSTEM permissions (using psexec to launch a SYSTEM cmd) but I still received the same error.

The function NtKey.CreateSymbolicLink is calling SetSymbolicLinkTarget which calls eventually to SetValue like that:

SetValue(SymbolicLinkValueName, RegistryValueType.Link, Encoding.Unicode.GetBytes(target), throw_on_error);  

I didn't figure out yet how to delete it.
I found an answer about deleting symbolic registry key with C but it just calls lpfnZwDeleteKey and I don't know what is the equivalent to C#.

I tried the function NtKey.UnloadKey function, I thought it might help but it didn't.

CodePudding user response:

I was able to delete it using James's tool CreateRegSymlink like that:

CreateRegSymlink.exe -d "HKCU\Software\XYZ"   

I noticed that it is being done by calling DeleteRegSymlink.
When I checked what is inside it, I noticed it convert the registry path to a real path by calling RegPathToNative:

bstr_t symlink = RegPathToNative(lpSymlink);  

Here you can see what the RegPathToNative work.
Then it calls:

InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE | OBJ_OPENLINK, nullptr, nullptr);  

Which is I think where the magic happens.
If you have any suggestion how to find the real link from a symbolic registry path, let me know.


EDIT(10/1/2022) - thanks to @RbMm:
I created a function to open symlink using REG_OPTION_OPEN_LINK and then deletes it with ZwDeleteKey but the important thing was to set the rights to RegistryRights.Delete as @RbMm mentioned:

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);
}

  •  Tags:  
  • Related