RtlQueryRegistryValues 函数 (wdm.h)
RtlQueryRegistryValues 例程允许调用方通过单个调用从注册表子树查询多个值。
语法
NTSYSAPI NTSTATUS RtlQueryRegistryValues(
[in] ULONG RelativeTo,
[in] PCWSTR Path,
[in, out] PRTL_QUERY_REGISTRY_TABLE QueryTable,
[in, optional] PVOID Context,
[in, optional] PVOID Environment
);
参数
[in] RelativeTo
指定 路径 是绝对注册表路径还是相对于预定义路径,如下所示。
价值 | 意义 |
---|---|
RTL_REGISTRY_ABSOLUTE | 路径是绝对注册表路径。 |
RTL_REGISTRY_CONTROL | 路径相对于 \Registry\Machine\System\CurrentControlSet\Control。 |
RTL_REGISTRY_DEVICEMAP | 路径相对于 \Registry\Machine\Hardware\DeviceMap。 |
RTL_REGISTRY_SERVICES | 路径相对于 \Registry\Machine\System\CurrentControlSet\Services。 |
RTL_REGISTRY_USER | 路径相对于 \Registry\User\CurrentUser。 (对于系统进程,这是 \User\。默认.) |
RTL_REGISTRY_WINDOWS_NT | 路径相对于 \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion。 |
RelativeTo 值可以通过按位 ORing 来修改它,并使用以下标志之一。
旗 | 意义 |
---|---|
RTL_REGISTRY_OPTIONAL | 指定此参数引用的键和 Path 参数是可选的。 |
RTL_REGISTRY_HANDLE | 指定 Path 参数实际上是要使用的注册表句柄。 |
[in] Path
指向绝对注册表路径或相对于 RelativeTo 参数指定的已知位置的路径的指针。 请注意,此类路径中的键名称必须已知给调用方,包括路径中的最后一个键。 如果指定了RTL_REGISTRY_HANDLE标志,则此参数是一个注册表句柄,用于直接查询已打开的密钥。
[in, out] QueryTable
指向调用方感兴趣的一个或多个值名称和子项名称的表的指针。 每个表项都包含调用方提供的 QueryRoutine 函数的地址,该函数将针对注册表中存在的每个值名称调用。 该表必须以 NULL 表项终止,该表是具有 NULLQueryRoutine 成员的表项,以及 NULLName 成员。 查询表条目的结构定义如下:
typedef struct _RTL_QUERY_REGISTRY_TABLE {
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
ULONG Flags;
PWSTR Name;
PVOID EntryContext;
ULONG DefaultType;
PVOID DefaultData;
ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
如果调用方为 QueryTable 参数指向的查询表分配存储,则调用方负责在 RtlQueryRegistryValues 调用返回后释放此存储。
QueryRoutine
使用注册表值的名称、类型、数据和数据长度调用的 QueryRoutine 函数的地址。 如果此成员和 名称 成员都 NULL,则它将标记表的末尾。
QueryRoutine 函数声明如下:
NTSTATUS
QueryRoutine (
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
);
有关详细信息,请参阅 QueryRoutine。
标志
用于控制如何解释 RTL_QUERY_REGISTRY_TABLE 结构的剩余成员的标志。 为此成员定义了以下标志位。
价值 | 意义 |
---|---|
RTL_QUERY_REGISTRY_SUBKEY | 此表项的 名称 是注册表项的另一个路径,下表条目都适用于该键,而不是由 Path 参数指定的键。 焦点更改将持续到表的末尾或看到另一个RTL_REGISTRY_SUBKEY或RTL_QUERY_REGISTRY_TOPKEY条目。 每个此类条目必须指定一个相对于调用 RtlQueryRegistryValues中指定的 Path 的路径。 |
RTL_QUERY_REGISTRY_TOPKEY | 将当前注册表项句柄重置为由 RelativeTo 和 Path 参数指定的原始注册表项句柄。 这在使用 RTL_QUERY_REGISTRY_SUBKEY 标志降到子项后返回到原始节点非常有用。 |
RTL_QUERY_REGISTRY_REQUIRED | 指定如果 defaultType = REG_NONE,则必须存在此注册表值;否则,如果未找到,RtlQueryRegistryValues 立即退出状态代码STATUS_OBJECT_NAME_NOT_FOUND。 如果 名称 成员 NULL 且当前键没有子项,或者如果 Name 指定不存在的子项,则会出现此退出。 (如果未指定此标志,则如果未为非NULLName找到匹配项,则例程将使用 DefaultValue 成员作为值。当 名称NULL 且当前键没有子项时,例程只会跳过该表项。 |
RTL_QUERY_REGISTRY_NOVALUE | 指定即使此表项没有 名称,所有调用方都希望是回调:也就是说,调用方不想枚举当前键下的所有值。 QueryRoutine 使用 ValueData的 NULL 进行调用,ValueTypeREG_NONE,ValueLength为零。 |
RTL_QUERY_REGISTRY_NOEXPAND | 对于REG_EXPAND_SZ或REG_MULTI_SZ类型的注册表值,此标志将替代默认行为,即在调用 QueryRoutine 例程之前预处理注册表值。 默认情况下,RtlQueryRegistryValues 扩展REG_EXPAND_SZ值中的环境变量引用,并在单独的 QueryRoutine 调用中枚举REG_MULTI_SZ值中的每个以 null 结尾的字符串,以便字符串显示为具有相同 ValueName的REG_SZ值。 如果设置了此标志,QueryRoutine 从注册表接收原始REG_EXPAND_SZ或REG_MULTI_SZ值。 有关这些值的数据格式的详细信息,请参阅 KEY_VALUE_BASIC_INFORMATION。 |
RTL_QUERY_REGISTRY_DIRECT | 不使用 QueryRoutine 成员(并且必须 NULL),EntryContext 指向缓冲区来存储值。 如果调用方设置此标志,调用方应额外设置RTL_QUERY_REGISTRY_TYPECHECK标志,以防止缓冲区溢出。 有关详细信息,请参阅“备注”部分。 |
RTL_QUERY_REGISTRY_TYPECHECK | 将此标志与RTL_QUERY_REGISTRY_DIRECT标志一起使用,验证存储注册表值的 REG_XXX 类型是否与调用方预期的类型匹配。 如果类型不匹配,调用将失败。 有关详细信息,请参阅“备注”部分。 |
RTL_QUERY_REGISTRY_DELETE | 此标志用于在查询值键后将其删除。 |
从 Windows 2000 开始,为上表中的所有标志位提供收件箱支持,但RTL_QUERY_REGISTRY_TYPECHECK除外。 从 Windows 8 开始,对RTL_QUERY_REGISTRY_TYPECHECK的收件箱支持可用。 对于早期版本的 Windows,通过 Windows 更新提供对RTL_QUERY_REGISTRY_TYPECHECK的支持。 有关详细信息,请参阅“备注”。
名字
这是调用方查询的值的名称。 如果 名称NULL,则为此表项指定的 QueryRoutine 函数将针对与当前注册表项关联的所有值调用。 如果设置了RTL_QUERY_REGISTRY_DIRECT标志,则必须提供 名称 的非NULL 值。
EntryContext
如果设置了RTL_QUERY_REGISTRY_DIRECT标志,则这是指向缓冲区的指针,用于存储此键的查询操作的结果。 否则,此值作为 QueryRoutine的 EntryContext 参数传递。
DefaultType
如果找不到匹配键且未指定RTL_QUERY_REGISTRY_REQUIRED标志,则此成员的最小有效字节指定要返回的数据REG_XXX 类型。 为无默认类型指定REG_NONE。 如果设置了RTL_QUERY_REGISTRY_TYPECHECK标志,则此成员最重要的字节指定调用方期望的存储注册表值的 REG_XXX 类型。 此成员的位 8 到 23 是保留的,应为零。
DefaultData
如果未找到匹配键且未指定RTL_QUERY_REGISTRY_REQUIRED标志,则指向要返回的默认值的指针。 如果 defaultType
DefaultLength
指定 defaultData 成员
[in, optional] Context
指定每次调用查询Routine 时作为 QueryRoutine 函数的 Context 参数传递的值。
[in, optional] Environment
指向在REG_EXPAND_SZ注册表值中展开变量值时使用的环境的指针,或 NULL 指针(可选)。
返回值
RtlQueryRegistryValues 返回 NTSTATUS 代码。 可能的返回值包括:
返回代码 | 描述 |
---|---|
STATUS_SUCCESS | 已成功处理整个查询表。 |
STATUS_INVALID_PARAMETER | 处理以无效表条目结尾的查询表。 如果指定的标志要求 QueryRoutine 或 Name 成员为非NULL,但提供了 NULL 值,则表项可能无效。 |
STATUS_OBJECT_NAME_NOT_FOUND | Path 参数与有效键不匹配,或者查询表的处理以具有RTL_QUERY_REGISTRY_REQUIRED标志集且找不到匹配键的条目终止。 如果 Name 成员 NULL 且当前键没有子项,或者如果 Name 指定不存在的子项,则会出现这种情况。 |
STATUS_BUFFER_TOO_SMALL | 设置RTL_QUERY_REGISTRY_DIRECT标志,EntryContext 指定的缓冲区太小,无法保存键值数据。 |
STATUS_OBJECT_TYPE_MISMATCH | 设置RTL_QUERY_REGISTRY_TYPECHECK标志,并且存储的注册表值的类型与调用方预期的类型不匹配。 |
RtlQueryRegistryValues 如果表项的 QueryRoutine 函数返回 NTSTATUS 错误代码,并返回该错误代码作为其结果,则也会终止对表的处理。 (有一个例外:如果 QueryRoutine 返回STATUS_BUFFER_TOO_SMALL,则忽略错误代码。
言论
调用方指定初始键路径和表。 该表包含一个或多个条目,用于描述调用方感兴趣的键值和子项名称。 该表由 NULLQueryRoutine 成员和 NULLName 成员的条目终止。 表必须从非分页池分配。
内核模式驱动程序必须指定RTL_QUERY_REGISTRY_NOEXPAND标志,以防止调用环境变量例程。 这些例程不安全,因此内核模式驱动程序不应使用它们。
谨慎
如果使用RTL_QUERY_REGISTRY_DIRECT标志,则不受信任的用户模式应用程序可能会导致缓冲区溢出。 如果驱动程序使用此标志读取分配了错误的类型的注册表值,则可能会出现缓冲区溢出。 在所有情况下,使用RTL_QUERY_REGISTRY_DIRECT标志的驱动程序应使用RTL_QUERY_REGISTRY_TYPECHECK标志来防止此类溢出。
如果在表项中设置了RTL_QUERY_REGISTRY_TYPECHECK标志,则调用方必须在表项的 32 位 DefaultType 成员的 8 位中指定预期的 REG_XXX 类型。 如以下代码示例所示,定义为 24 的 RTL_QUERY_REGISTRY_TYPECHECK_SHIFT 常量可用作将预期的 REG_XXX 类型放置在 DefaultType 成员的 8 个 MSB 中所需的移位计数。
RTL_QUERY_REGISTRY_TABLE QueryRegTable[2];
...
QueryRegTable[0].DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
...
QueryRegTable[1].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
...
从 Windows 8 开始,如果 RtlQueryRegistryValues 调用访问不受信任的 hive,并且调用方为此调用设置RTL_QUERY_REGISTRY_DIRECT标志,则调用方必须额外设置RTL_QUERY_REGISTRY_TYPECHECK标志。 来自用户模式的调用违反此规则会导致异常。 来自内核模式的调用违反此规则会导致0x139 bug 检查(KERNEL_SECURITY_CHECK_FAILURE)。
仅信任系统配置单元。 访问系统配置单元的 RtlQueryRegistryValues 调用不会导致异常或 bug 检查是否已设置RTL_QUERY_REGISTRY_DIRECT标志,并且未设置RTL_QUERY_REGISTRY_TYPECHECK标志。 但是,最佳做法是,如果设置了RTL_QUERY_REGISTRY_DIRECT标志,应始终设置RTL_QUERY_REGISTRY_TYPECHECK标志。
同样,在 Windows 8 之前的 Windows 版本中,最佳做法是,RtlQueryRegistryValues 调用来设置RTL_QUERY_REGISTRY_DIRECT标志应额外设置RTL_QUERY_REGISTRY_TYPECHECK标志。 但是,如果不遵循此建议,则不会导致异常或 bug 检查。
下面是系统配置单元的列表:
\REGISTRY\MACHINE\HARDWARE
\REGISTRY\MACHINE\SOFTWARE
\REGISTRY\MACHINE\SYSTEM
\REGISTRY\MACHINE\SECURITY
\REGISTRY\MACHINE\SAM
可通过适用于 Windows 7、Windows Vista、Windows Server 2003 和 Windows XP 的 Windows 更新获取对RTL_QUERY_REGISTRY_TYPECHECK标志的支持。 有关此更新的详细信息,请参阅 Windows 内核中的 漏洞可能允许提升权限(2393802)。 在没有此更新的这些操作系统版本中,调用方可以使用RTL_QUERY_REGISTRY_TYPECHECK标志。 但是,RtlQueryRegistryValues 例程忽略此标志。
从 Windows 驱动程序工具包 (WDK) 8 开始,RTL_QUERY_REGISTRY_TYPECHECK标志在 Wdm.h 头文件中定义,如下所示:
#define RTL_QUERY_REGISTRY_TYPECHECK 0x00000100
如果条目未指定RTL_QUERY_REGISTRY_DIRECT标志,RtlQueryRegistryValues 使用指定的 QueryRoutine 函数向调用方报告值名称、类型、数据和数据长度(以字节为单位)。 如果条目的 名称 成员 NULL,RtlQueryRegistryValues 报告键的每个直接子项。 如果键类型为REG_MULTI_SZ且未指定RTL_QUERY_REGISTRY_NOEXPAND标志,则例程调用 QueryRoutine 针对每个字符串单独调用;否则,例程将其报告为单个值。 如果条目指定RTL_QUERY_REGISTRY_DIRECT标志,RtlQueryRegistryValues 将键的值存储在条目 的 entryContext 成员指向的缓冲区中。 返回的数据的格式如下所示。
键数据类型 | 如何返回数据 |
---|---|
以 null 结尾的 Unicode 字符串(例如REG_SZ、REG_EXPAND_SZ)。 | EntryContext 必须指向初始化的 UNICODE_STRING 结构。 如果 UNICODE_STRING 的 Buffer 成员 NULL,则例程将为字符串数据分配存储。 否则,它将字符串数据存储在 Buffer 指向的缓冲区中。 |
REG_MULTI_SZ | 必须为此键数据类型指定RTL_QUERY_REGISTRY_NOEXPAND标志。 EntryContext 指向初始化的 UNICODE_STRING 结构。 例程将键值存储为单个字符串值。 字符串中的每个单个组件都以零结尾。 如果 UNICODE_STRING 的 Buffer 成员 NULL,则例程将为字符串数据分配存储。 否则,它将字符串数据存储在 Buffer 指向的缓冲区中。 |
大小(以字节为单位)的非字符串数据 <= sizeof(ULONG) | 该值存储在 EntryContext指定的内存位置。 |
具有大小的非字符串数据(以字节为单位)>sizeof(ULONG) | EntryContext 指向的缓冲区必须以带符号 LONG 值开头。 值的大小必须指定缓冲区的大小(以字节为单位)。 如果值的符号为负值,RtlQueryRegistryValues 将仅存储键值的数据。 否则,它将使用缓冲区中的第一个 ULONG 来记录值长度,以字节为单位,第二个 ULONG 来记录值类型,其余的缓冲区用于存储值数据。 |
如果在查询表的任何处理阶段发生错误,RtlQueryRegistryValues 停止处理表并返回错误状态。
有关可能的 REG_XXX 值的说明,请参阅 ZwSetValueKey。
要求
要求 | 价值 |
---|---|
目标平台 | 普遍 |
标头 | wdm.h (包括 Wdm.h、Ntddk.h、Ntifs.h) |
库 | Ntoskrnl.lib |
DLL | Ntoskrnl.exe |
IRQL | PASSIVE_LEVEL |