Checking if registry key is link to (or copy of) another one

How can I check out if registry key is link to another one using winapi?

For example, I need to find out which branch is original HKEY_LOCAL_MACHINE\SECURITY\SAM or HKEY_LOCAL_MACHINE\SAM\SAM, HKEY_CURRENT_USER or HKEY_USERS\S-1-5-21.

I'm confused with types of keys and values. Does key have type? Can I use REG_LINK type for this purpose?

Upvotes: 1

Views: 1525

Answers (1)

RbMm
RbMm

Reputation: 33734

First of all we must open the key itself, rather than the key that the potential symbolic link key refers to (which is the default behavior).

For this we need to use REG_OPTION_OPEN_LINK option in call RegOpenKeyExW or ZwOpenKeyEx. An alternative way is to use OBJ_OPENLINK attribute in OBJECT_ATTRIBUTES. and use this in call ZwOpenKey[Ex]

After the key is opened we can query (starting from win7) undocumented KeyFlagsInformation information via ZwQueryKey. If the flags shows that this is symbolic link - we can query SymbolicLinkValue value to get the link target key. Note that even if this value exists with type REG_LINK - this doesn't prove that this is symbolic link.

struct KEY_CONTROL_FLAGS_INFO_W7  // KeyFlagsInformation for Win7
{
    ULONG ControlFlags[3];
};

#define KEY_CTRL_FL_W7_01__IS_VOLATILE                                 0x01
#define KEY_CTRL_FL_W7_01__SYM_LINK                                    0x02

LSTATUS IsSymLink(HKEY hKey, PCWSTR lpSubKey, BOOL& IsLink)
{
    LSTATUS r = RegOpenKeyEx(hKey, lpSubKey, REG_OPTION_OPEN_LINK, KEY_READ|KEY_WOW64_64KEY, &hKey);

    if (r == NOERROR)
    {
        ULONG Type, cb = 0, rcb = 0x80;

        KEY_CONTROL_FLAGS_INFO_W7 kcf;

        NTSTATUS status;

        if (0 <= (status = ZwQueryKey(hKey, KeyFlagsInformation, &kcf, sizeof(kcf), &cb)))
        {
            if (kcf.ControlFlags[1] & KEY_CTRL_FL_W7_01__SYM_LINK)
            {
                IsLink = TRUE;
                DbgPrint("key is link\n");

                PVOID stack = alloca(guz), buf = 0;

                do 
                {
                    if (cb < rcb)
                    {
                        cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                    }

                    r = RegQueryValueExW(hKey, L"SymbolicLinkValue", 0, &Type, (PBYTE)buf, &(rcb = cb));

                    if (r == NOERROR && Type == REG_LINK && !(rcb & (sizeof(WCHAR) - 1)))
                    {
                        DbgPrint("%.*S\n", rcb / sizeof(WCHAR), buf);
                    }

                } while (r == ERROR_MORE_DATA);
            }
        }
        else
        {
            r = RtlNtStatusToDosError(status);
        }

        RegCloseKey(hKey);
    }

    return r;
}

Does key have type?

No. type have values of key only

Can I use REG_LINK type for this purpose?

We can on a regular(not link) key create SymbolicLinkValue value with type REG_LINK, but key doesn't become a link after this. Key must be initially created with REG_OPTION_CREATE_LINK option. So by querying SymbolicLinkValue value we can't reliably check if this is a link, but if we know that this is a link - we can get the target of the link by querying SymbolicLinkValue

Upvotes: 4

Related Questions