Поделиться через


Функция 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 Путь — это абсолютный путь к реестру.
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 можно изменить с помощью bitwise-ORing с одним из следующих флагов.

Flag Значение
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.

Флаги

Флаги для управления интерпретацией остальных членов структуры RTL_QUERY_REGISTRY_TABLE . Для этого элемента определены следующие биты флагов.

Значение Значение
RTL_QUERY_REGISTRY_SUBKEY Имя этой записи таблицы — это еще один путь к разделу реестра, и все следующие записи таблицы относятся к этому разделу, а не к ключу, заданному параметром Path. Это изменение фокуса продолжается до конца таблицы или до тех пор, пока не будет видна другая запись RTL_REGISTRY_SUBKEY или RTL_QUERY_REGISTRY_TOPKEY. Каждая такая запись должна указывать путь относительно пути , указанного в вызове RtlQueryRegistryValues.
RTL_QUERY_REGISTRY_TOPKEY Сбрасывает текущий дескриптор раздела реестра до исходного, заданного параметрами RelativeTo и Path . Это полезно для возврата к исходному узлу после убывания по подразделам с флагом RTL_QUERY_REGISTRY_SUBKEY.
RTL_QUERY_REGISTRY_REQUIRED Указывает, что это значение реестра должно существовать, если DefaultType = REG_NONE; В противном случае, если он не найден, RtlQueryRegistryValues немедленно завершает работу с кодом состояния STATUS_OBJECT_NAME_NOT_FOUND. Этот выход происходит, если член Name имеет значение NULL , а текущий ключ не имеет подразделов или если Name указывает несуществующий подраздел. (Если этот флаг не указан, то при отсутствии совпадений для имени, отличного от NULL, подпрограмма использует элемент DefaultValue в качестве значения. Если имя имеет значение NULL, а текущий ключ не имеет подразделов, подпрограмма просто пропускает запись таблицы.)
RTL_QUERY_REGISTRY_NOVALUE Указывает, что, несмотря на отсутствие имени для этой записи таблицы, все, что нужно вызывающему объекту, является обратным вызовом, то есть вызывающий объект не хочет перечислять все значения в текущем ключе. QueryRoutine вызывается со значением NULL для ValueData, REG_NONE для ValueType и нулевым значением для ValueLength.
RTL_QUERY_REGISTRY_NOEXPAND Для значения реестра типа REG_EXPAND_SZ или REG_MULTI_SZ этот флаг переопределяет поведение по умолчанию, которое заключается в предварительной обработке значения реестра перед вызовом подпрограммы QueryRoutine . По умолчанию RtlQueryRegistryValues расширяет ссылки на переменные среды в REG_EXPAND_SZ значениях и перечисляет каждую строку, завершающуюся значением NULL, в REG_MULTI_SZ значении в отдельном вызове QueryRoutine , чтобы строки представлялись в виде REG_SZ значений, имеющих одно и то же значение ValueName. Если этот флаг установлен, 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. Поддержка папки "Входящие" для RTL_QUERY_REGISTRY_TYPECHECK доступна начиная с Windows 8. В более ранних версиях Windows поддержка RTL_QUERY_REGISTRY_TYPECHECK предоставляется через клиентский компонент Центра обновления Windows. Дополнительные сведения см. в подразделе "Примечания".

Имя

Это имя значения, которое запрашивает вызывающий объект. Если name имеет значение NULL, функция QueryRoutine , указанная для этой записи таблицы, вызывается для всех значений, связанных с текущим разделом реестра. Если установлен флаг RTL_QUERY_REGISTRY_DIRECT, необходимо указать значение name, отличное от NULL.

EntryContext

Если установлен флаг RTL_QUERY_REGISTRY_DIRECT, это указатель на буфер для хранения результата операции запроса для этого ключа. В противном случае это значение передается как параметр EntryContextобъекта QueryRoutine.

DefaultType

Наименьший байт этого элемента указывает тип REG_XXX возвращаемых данных, если соответствующий ключ не найден и флаг RTL_QUERY_REGISTRY_REQUIRED не задан. Укажите REG_NONE без типа по умолчанию. Если установлен флаг RTL_QUERY_REGISTRY_TYPECHECK, наиболее значимый байт этого элемента указывает тип REG_XXX сохраненного значения реестра, ожидаемого вызывающим элементом. Биты от 8 до 23 этого элемента зарезервированы и должны быть равны нулю.

DefaultData

Указатель на значение по умолчанию, возвращаемое, если соответствующий ключ не найден и флаг RTL_QUERY_REGISTRY_REQUIRED не указан. Этот элемент игнорируется, если DefaultType = REG_NONE. В противном случае тип данных, на который указывает DefaultData, должен соответствовать типу значения реестра, заданному элементом DefaultType . Дополнительные сведения о типах значений реестра см. в определении параметра Type в KEY_VALUE_BASIC_INFORMATION.

DefaultLength

Указывает длину элемента DefaultData в байтах. Если defaultType имеет значение REG_SZ, REG_EXPAND_SZ или REG_MULTI_SZ, вызывающие стороны могут при необходимости указать ноль, чтобы указать, что значение RtlQueryRegistryValues должно вычислять длину на основе значения данных по умолчанию. Если DefaultType = REG_NONE, этот элемент игнорируется.

[in, optional] Context

Задает значение, передаваемое в качестве параметра Context функции QueryRoutine при каждом вызове.

[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, код ошибки игнорируется.)

Комментарии

Вызывающий объект задает начальный путь к ключу и таблицу. Таблица содержит одну или несколько записей, описывающих значения ключей и имена подразделов, в которых заинтересован вызывающий объект. Таблица завершается записью с элементом QueryRoutineNULL и элементом NULLName. Таблица должна быть выделена из непагрегированного пула.

Драйверы в режиме ядра должны указывать флаг RTL_QUERY_REGISTRY_NOEXPAND, чтобы предотвратить вызов подпрограмм переменных среды. Эти подпрограммы являются небезопасными, поэтому драйверы в режиме ядра не должны их использовать.

Внимание!

Если вы используете флаг RTL_QUERY_REGISTRY_DIRECT, ненадежное приложение в пользовательском режиме может вызвать переполнение буфера. Переполнение буфера может произойти, если драйвер использует этот флаг для чтения значения реестра, которому присвоен неправильный тип. Во всех случаях драйвер, использующий флаг RTL_QUERY_REGISTRY_DIRECT, должен дополнительно использовать флаг RTL_QUERY_REGISTRY_TYPECHECK, чтобы предотвратить такие переполнения.

Если флаг RTL_QUERY_REGISTRY_TYPECHECK задан в записи таблицы, вызывающий объект должен указать ожидаемый тип REG_XXX в 8 наиболее значимых битах (MSB) 32-разрядного элемента DefaultType записи таблицы. Как показано в следующем примере кода, константу RTL_QUERY_REGISTRY_TYPECHECK_SHIFT, которая определена как 24, можно использовать в качестве количества сдвига, необходимого для размещения ожидаемого типа REG_XXX в 8 MSB элемента DefaultType .

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 ошибку проверка (KERNEL_SECURITY_CHECK_FAILURE).

Только системные кусты являются доверенными. Вызов RtlQueryRegistryValues, который обращается к системным кустам, не вызывает исключения или ошибки проверка, если флаг RTL_QUERY_REGISTRY_DIRECT установлен, а флаг RTL_QUERY_REGISTRY_TYPECHECK не задан. Однако рекомендуется всегда устанавливать флаг RTL_QUERY_REGISTRY_TYPECHECK, если установлен флаг RTL_QUERY_REGISTRY_DIRECT.

Аналогичным образом в версиях Windows до Windows 8 рекомендуется использовать вызов RtlQueryRegistryValues, задающий флаг RTL_QUERY_REGISTRY_DIRECT, должен дополнительно задать флаг RTL_QUERY_REGISTRY_TYPECHECK. Однако несоблюдение этой рекомендации не приводит к исключению или ошибке проверка.

Ниже приведен список системных кустов:

  • \REGISTRY\MACHINE\HARDWARE

  • \REGISTRY\MACHINE\SOFTWARE

  • \REGISTRY\MACHINE\SYSTEM

  • \REGISTRY\MACHINE\SECURITY

  • \REGISTRY\MACHINE\SAM

Поддержка флага RTL_QUERY_REGISTRY_TYPECHECK доступна в клиентский компонент Центра обновления Windows для Windows 7, Windows Vista, Windows Server 2003 и Windows XP. Дополнительные сведения об этом обновлении см. в статье Уязвимости в ядре Windows могут привести к несанкционированному повышению привилегий (2393802). В версиях этих операционных систем, не имеющих этого обновления, вызывающий объект может использовать флаг RTL_QUERY_REGISTRY_TYPECHECK. Однако этот флаг игнорируется подпрограммой RtlQueryRegistryValues .

Начиная с Windows Driver Kit (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 записи. Формат возвращаемых данных выглядит следующим образом.

Тип данных key Как возвращаются данные
Строка Юникода, заканчивающаяся null (например, REG_SZ, REG_EXPAND_SZ). EntryContext должен указывать на инициализированную структуру UNICODE_STRING . Если элемент BufferUNICODE_STRING имеет значение NULL, подпрограмма выделяет хранилище для строковых данных. В противном случае строковые данные сохраняются в буфере, на который указывает Buffer .
REG_MULTI_SZ Для этого типа данных ключа необходимо указать флаг RTL_QUERY_REGISTRY_NOEXPAND. EntryContext указывает на инициализированную структуру UNICODE_STRING . Подпрограмма сохраняет значение ключа в виде одного строкового значения. Каждый отдельный компонент в строке завершается нулевым значением. Если элемент BufferUNICODE_STRING имеет значение 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

См. также раздел

QueryRoutine

RtlZeroMemory

UNICODE_STRING

ZwEnumerateKey

ZwEnumerateValueKey

ZwSetValueKey