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

指定 Path 是绝对注册表路径,还是相对于预定义路径,如下所示之一。

含义
RTL_REGISTRY_ABSOLUTE Path 是绝对注册表路径。
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\。Default.)
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 函数的地址。 如果此成员和 Name 成员均为 NULL,则它将标记表的末尾。

QueryRoutine 函数的声明如下:

NTSTATUS
QueryRoutine (
    IN PWSTR ValueName,
    IN ULONG ValueType,
    IN PVOID ValueData,
    IN ULONG ValueLength,
    IN PVOID Context,
    IN PVOID EntryContext
    );

有关详细信息,请参阅 QueryRoutine

Flags

用于控制如何解释 RTL_QUERY_REGISTRY_TABLE 结构的其余成员的标志。 为此成员定义了以下标志位。

含义
RTL_QUERY_REGISTRY_SUBKEY 此表项的名称是注册表项的另一个路径,所有下表条目都针对该键而不是 Path 参数指定的键。 焦点的这种变化将持续到表的末尾或看到另一个RTL_REGISTRY_SUBKEY或RTL_QUERY_REGISTRY_TOPKEY项为止。 每个此类条目都必须指定一个相对于调用 RtlQueryRegistryValues 中指定的路径的路径。
RTL_QUERY_REGISTRY_TOPKEY 将当前注册表项句柄重置为 由 RelativeToPath 参数指定的原始注册表项句柄。 这对于在使用 RTL_QUERY_REGISTRY_SUBKEY 标志降序到子项后返回到原始节点非常有用。
RTL_QUERY_REGISTRY_REQUIRED 指定 如果 DefaultType = REG_NONE,则此注册表值必须存在;否则,如果未找到, RtlQueryRegistryValues 会立即退出,状态代码为 STATUS_OBJECT_NAME_NOT_FOUND。 如果 Name 成员为 NULL 且当前键没有子项,或者 Name 指定不存在的子项,则会发生此退出。 (如果未指定此标志,则当找不到非 NULL名称的匹配项时,例程将使用 DefaultValue 成员作为值。当 NameNULL 且当前键没有子项时,例程只是跳过该表条目。)
RTL_QUERY_REGISTRY_NOVALUE 指定即使此表项没有 Name ,调用方需要的所有都是回调:即调用方不希望枚举当前键下的所有值。 对于 ValueData,使用 NULL 调用 QueryRoutine,为 ValueType REG_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的支持。 有关详细信息,请参阅“备注”。

名称

这是调用方查询的值的名称。 如果 NameNULL,则为此表项指定的 QueryRoutine 函数将针对与当前注册表项关联的所有值调用。 如果设置了RTL_QUERY_REGISTRY_DIRECT标志,则必须提供名称的非 NULL 值。

EntryContext

如果设置了RTL_QUERY_REGISTRY_DIRECT标志,则这是指向缓冲区的指针,用于存储此键的查询操作结果。 否则,此值将作为 QueryRoutineEntryContext 参数传递。

DefaultType

如果未找到匹配键且未指定RTL_QUERY_REGISTRY_REQUIRED标志,则此成员的最小有效字节指定要返回的数据的 REG_XXX 类型。 为无默认类型指定REG_NONE。 如果设置了RTL_QUERY_REGISTRY_TYPECHECK标志,则此成员的最大有效字节指定调用方预期的存储注册表值的 REG_XXX 类型。 此成员的位 8 到 23 是保留的,应为零。

DefaultData

指向未找到匹配键且未指定RTL_QUERY_REGISTRY_REQUIRED标志时返回的默认值的指针。 如果 DefaultType = REG_NONE,则忽略此成员。 否则, DefaultData 指向的数据类型应符合 DefaultType 成员指定的注册表值类型。 有关注册表值类型的详细信息,请参阅 KEY_VALUE_BASIC_INFORMATIONType 参数的定义。

DefaultLength

指定 DefaultData 成员的长度(以字节为单位)。 如果 DefaultType 是REG_SZ、REG_EXPAND_SZ或REG_MULTI_SZ,则调用方可以选择指定零,以指示 RtlQueryRegistryValues 应根据默认数据值计算长度。 如果 DefaultType = REG_NONE,则忽略此成员。

[in, optional] Context

指定每次调用 QueryRoutine 函数时作为 Context 参数传递的值。

[in, optional] Environment

指向在REG_EXPAND_SZ注册表值中展开变量值时使用的环境的指针,或 null 指针 (可选) 。

返回值

RtlQueryRegistryValues 返回 NTSTATUS 代码。 可能的返回值包括:

返回代码 说明
STATUS_SUCCESS 已成功处理整个查询表。
STATUS_INVALID_PARAMETER 使用无效表条目终止的查询表的处理。 如果指定的标志要求 QueryRoutineName 成员为非 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标志,并且存储的注册表值的类型与调用方预期的类型不匹配。

如果表条目的 QueryRoutine 函数返回 NTSTATUS 错误代码,并返回该错误代码作为结果,RtlQueryRegistryValues 也会终止对表的处理。 (有一个例外:如果 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 个有效位 (MSB) 指定预期的 REG_XXX 类型。 如以下代码示例所示,RTL_QUERY_REGISTRY_TYPECHECK_SHIFT常量(定义为 24)可用作将预期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 调用访问不受信任的配置单元,并且调用方为此调用设置了RTL_QUERY_REGISTRY_DIRECT标志,则调用方必须另外设置RTL_QUERY_REGISTRY_TYPECHECK标志。 从用户模式调用时违反此规则会导致异常。 从内核模式调用时违反此规则会导致0x139 bug 检查 (KERNEL_SECURITY_CHECK_FAILURE) 。

仅信任系统配置单元。 如果设置了RTL_QUERY_REGISTRY_DIRECT标志且未设置RTL_QUERY_REGISTRY_TYPECHECK标志,则访问系统配置单元的 RtlQueryRegistryValues 调用不会导致异常或 bug 检查。 但是,最佳做法是,如果设置了RTL_QUERY_REGISTRY_DIRECT标志,应始终设置RTL_QUERY_REGISTRY_TYPECHECK标志。

同样,在Windows 8之前的 Windows 版本中,作为最佳做法,设置RTL_QUERY_REGISTRY_DIRECT标志的 RtlQueryRegistryValues 调用还应另外设置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 函数向调用方报告值名称、类型、数据和数据长度(以字节为单位)。 如果条目的 Name 成员为 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_STRINGBuffer 成员为 NULL,则例程会为字符串数据分配存储。 否则,它将字符串数据存储在 Buffer 指向的缓冲区中。
REG_MULTI_SZ 必须为此键数据类型指定RTL_QUERY_REGISTRY_NOEXPAND标志。 EntryContext 指向已初始化 UNICODE_STRING 结构。 例程将键值存储为单个字符串值。 字符串中的每个单独组件都以零结尾。 如果 UNICODE_STRINGBuffer 成员为 NULL,则例程会为字符串数据分配存储。 否则,它将字符串数据存储在 Buffer 指向的缓冲区中。
非字符串数据的大小(以字节 <为单位)= sizeof (ULONG) 该值存储在 EntryContext 指定的内存位置中。
非字符串数据的大小(以字节为单位), >大小为 (ULONG) EntryContext 指向的缓冲区必须以有符号 LONG 值开头。 值的量级必须指定缓冲区的大小(以字节为单位)。 如果值的符号为负数, RtlQueryRegistryValues 将仅存储键值的数据。 否则,它将使用缓冲区中的第一个 ULONG 记录值长度(以字节为单位),使用第二个 ULONG 记录值类型,并使用缓冲区的其余部分来存储值数据。

如果在处理查询表的任何阶段发生错误, RtlQueryRegistryValues 将停止处理表并返回错误状态。

有关可能REG_XXX 值的说明,请参阅 ZwSetValueKey

要求

要求
目标平台 通用
标头 wdm.h(包括 Wdm.h、Ntddk.h、Ntifs.h)
Library Ntoskrnl.lib
DLL Ntoskrnl.exe
IRQL PASSIVE_LEVEL

另请参阅

QueryRoutine

RtlZeroMemory

UNICODE_STRING

ZwEnumerateKey

ZwEnumerateValueKey

ZwSetValueKey