c++ - 检查注册表项是否链接到(或副本)另一个
问题描述
如何检查注册表项是否使用 winapi 链接到另一个注册表项?
例如,我需要找出哪个分支是原始的HKEY_LOCAL_MACHINE\SECURITY\SAM
or HKEY_LOCAL_MACHINE\SAM\SAM
,HKEY_CURRENT_USER
or HKEY_USERS\S-1-5-21
。
我对键和值的类型感到困惑。钥匙有类型吗?我可以REG_LINK
为此目的使用类型吗?
解决方案
首先,我们必须打开密钥本身,而不是潜在的符号链接密钥所引用的密钥(这是默认行为)。
为此,我们需要REG_OPTION_OPEN_LINK
在 callRegOpenKeyExW
或中使用选项ZwOpenKeyEx
。替代方式使用OBJ_OPENLINK
中的属性OBJECT_ATTRIBUTES
。并在通话中使用它ZwOpenKey[Ex]
打开密钥后,我们可以通过查询(从win7开始)未记录的KeyFlagsInformation
信息ZwQueryKey
。如果标志显示这是符号链接 - 我们可以查询SymbolicLinkValue
获取链接目标键的值。请注意,即使使用类型也存在此值REG_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;
}
钥匙有类型吗?
不。类型只有键值
我可以为此目的使用 REG_LINK 类型吗?
我们可以在通常(非链接)键上创建SymbolicLinkValue
具有类型的值,REG_LINK
但在此之后键没有成为链接。密钥必须最初使用REG_OPTION_CREATE_LINK
选项创建。所以通过查询SymbolicLinkValue
值我们不能可靠地检查这是否是链接,但如果我们知道这是链接 - 我们可以通过查询获得链接的目标SymbolicLinkValue