注册表的读

一般使用ZwQueryValueKey来读取注册表中键的值。要注意的是注册表中的值可能有多种数据类型。而且长度也是没有定数的。为此,在读取过程中,就可能要面对很多种可能的情况。ZwQueryValueKey这个函数的原型如下:

NTSTATUS ZwQueryValueKey(
    IN HANDLE  KeyHandle,
    IN PUNICODE_STRING  ValueName,
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length,
    OUT PULONG  ResultLength
    );
  • KeyHandle:这是用ZwCreateKey或者ZwOpenKey所打开的一个注册表键句柄。
  • ValueName:要读取的值的名字。
  • KeyValueInformationClass:本次查询所需要查询的信息类型。这有如下的三种可能。
  • KeyValueBasicInformation:获得基础信息,包含值名和类型。
  • KeyValueFullInformation:获得完整信息。包含值名、类型和值的数据。
  • KeyValuePartialInformation:获得局部信息。包含类型和值数据。

很容易看出实际上名字是已知的,获得基础信息是多此一举。同样获得完整信息也是浪费内存空间。因为调用ZwQueryValueKey的目的是为了得到类型和值数据。因此使用KeyValuePartialInformation最常见。当采用KeyValuePartialInformation的时候,一个类型为KEY_VALUE_PARTIAL_INFORMATION的结构将被返回到参数KeyValueInformation所指向的内存中。

KeyValueInformation:当KeyValueInformationClass被设置为KeyValuePartialInformation时,KEY_VALUE_PARTIAL_INFORMATION结构将被返回到这个指针所指内存中。下面是结构KEY_VALUE_PARTIAL_INFORMATION的原型。

typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
    ULONG  TitleIndex;            // 请忽略这个成员
    ULONG  Type;                // 数据类型
    ULONG  DataLength;            // 数据长度
    UCHAR  Data[1];              // 可变长度的数据
}KEY_VALUE_PARTIAL_INFORMATION,*PKEY_VALUE_PARTIAL_INFORMATIO;

上面的数据类型Type有很多种可能,但是最常见的几种如下:

  • REG_BINARY:十六进制数据。
  • REG_DWORD:四字节整数。
  • REG_SZ:以空结束的Unicode字符串。
  • Length:用户传入的输出空间KeyValueInformation的长度。
  • ResultLength:返回实际需要的长度。
  • 返回值:如果说实际需要的长度比Length要大,那么返回STATUS_BUFFER_OVERFLOW或者是STATUS_BUFFER_TOO_SMALL。如果成功读出了全部数据,那么返回STATUS_SUCCESS。其他的情况,返回一个错误码。

下面请读者考虑如何把上一小节的函数写完整。这其中比较常见的一个问题是在读取注册表键下的值之前,往往不知道这个值有多长。所以有些比较偷懒的程序员总是定义一个足够的大小的空间(比如512字节)。这样的坏处是浪费内存(一般都是在堆栈中定义,而内核编程中堆栈空间被耗尽又是另一个常见的蓝屏问题)。此外也无法避免值实际上大于该长度的情况。为此应该耐心的首先获取长度,然后不足时再动态分配内存进行读取。下面是示例代码:

// 要读取的值的名字
UNICODE_STRING my_key_name = RTL_CONSTANT_STRING(L”SystemRoot”);
// 用来试探大小的key_infor
KEY_VALUE_PARTIAL_INFORMATION key_infor;
// 最后实际用到的key_infor指针。内存分配在堆中
PKEY_VALUE_PARTIAL_INFORMATION ac_key_infor;
ULONG ac_length;
……
// 前面已经打开了句柄my_key,下面如此来读取值:
status = ZwQueryValueKey(
    my_key,
    &my_key_name, 
    KeyValuePartialInformation,
    &key_infor,
    sizeof(KEY_VALUE_PARTIAL_INFORMATION),
    &ac_length);
if(!NT_SUCCESS(status) && 
    status != STATUS_BUFFER_OVERFLOW &&
    status != STATUS_BUFFER_TOO_SMALL)
{
    // 错误处理
    …    
}
// 如果没失败,那么分配足够的空间,再次读取
ac_key_infor = (PKEY_VALUE_PARTIAL_INFORMATION)
    ExAllocatePoolWithTag(NonpagedPool,ac_length ,MEM_TAG);
if(ac_key_infor == NULL)
{
    stauts = STATUS_INSUFFICIENT_RESOURCES;
    // 错误处理
    …
}
status = ZwQueryValueKey(
    my_key,
    &my_key_name, 
    KeyValuePartialInformation,
    ac_key_infor,
    ac_length,
    &ac_length);
// 到此为止,如果status为STATUS_SUCCESS,则要读取的数据已经
// 在ac_key_infor->Data中。请利用前面学到的知识,转换为
// UNICODE_STRING
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

Powered by bytekits.com,汇天下文字,成非凡梦想!!!