zoukankan      html  css  js  c++  java
  • 8、Windows驱动开发技术详解笔记(4) 基本语法回顾

     4、注册表操作

    和文件操作类似,在操作注册表之前需要首先打开注册表,获得一个句柄,这可以通过函数ZwCreateKey 完成。与ZwCreateFile函数类似,它通过一个OBJECT_ATTRIBUTES 获得需要创建或打开的路径信息,但在内核中这个路径与用户模式下不相同,实际上,因为用户模式下的应用程序总是由某个当前用户打开的,因此在用户模式下可以直接访问HKEY_CLASSES_ROOT HKEY_CURRENT_USER,但工作在内核模式下的驱动程序不属于任何一个用户,因此不能直接访问这两个根键。

    如果ZwCreateKey 指定的项不存在,则会直接创建该项,同时由函数的Disposition参数返回REG_CREATED_NEW_KEY;如果指定项已经存在了,则 Disposition返回值REG_OPENED_EXISTING_KEYDDK同样提供了一个ZwOpenKey函数用以简化打开注册表的操作。同时DDK还提供一系列以Rtl 开头的运行时函数,它们可以是对Zw系列函数的封装,可以有效地简化对注册表的操作过程。

    wps_clip_image-6573

    wps_clip_image-25020

    Zw系统注册相关函数

    http://msdn.microsoft.com/en-us/library/ff566425%28VS.85%29.aspx

    wps_clip_image-10646

    Rtl系统注册相关函数

    http://msdn.microsoft.com/en-us/library/ff561822%28VS.85%29.aspx

    1)读写注册表

    注册表是以二元形式存储的,即键名键值,通过键名来设置键值,其中键值分为多种情况。

    wps_clip_image-11238

    表 注册键类型

    通过ZwSetValueKe y 函数添加或修改注册表键值,通过ZwQueryValueKe y

    数查询相关键值。

    2)枚举

    枚举注册表通常分两种情况:枚举一个注册表项的所有子项和枚举一个注册表项的所有子键。

    枚举子项使用ZwQueryKey(注意不是ZwQueryValueKey)和ZwEnumerateKe y配合完成,枚举子键使用ZwQueryKeyZwEnumerateValueKey配合完成。

    我们以枚举子项来说明思路,首先利用ZwQueryKey获得某项究竟有多少个子项,然后利用ZwEnumerateKe y来获取指定子项的详细信息,这个过程是通过一个子项索引(index)来完成的。在使用ZwQueryKey时,可以将参数KeyInformationClass指定为KeyFullInformation,它对应KEY_FULL_INFORMATION结构中的SubKeys指明了该项中有多少子项。

    3)一个例子如下

    代码
    1 /************************************************************************
    2
    3 * 函数名称:RegEnumTest
    4
    5 * 功能描述:测试读取注册表
    6
    7 * 参数列表:
    8
    9 * 返回 值:返回状态
    10
    11 *************************************************************************/
    12
    13 NTSTATUS
    14
    15 RegEnumTest()
    16
    17 {
    18
    19 UNICODE_STRING ustrRegString;
    20
    21 UNICODE_STRING ustrKeyName;
    22
    23 HANDLE hRegister;
    24
    25 ULONG ulSize, i = 0;
    26
    27 OBJECT_ATTRIBUTES obj_attrib;
    28
    29 NTSTATUS status;
    30
    31 PKEY_FULL_INFORMATION pfi;
    32
    33 PKEY_BASIC_INFORMATION pbi;
    34
    35  // 初始化
    36  
    37 RtlInitUnicodeString(&ustrRegString,L"\\Registry\\Machine\\SOFTWARE\\ODBC\\ODBC.INI");
    38
    39 InitializeObjectAttributes(&obj_attrib,
    40
    41  &ustrRegString,
    42
    43 OBJ_CASE_INSENSITIVE,
    44
    45 NULL,
    46
    47 NULL);
    48
    49  // 打开注册表
    50
    51 status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &obj_attrib);
    52
    53 if (NT_SUCCESS(status))
    54
    55 {
    56
    57 KdPrint(("[Test] ZwOpenKey %wZ Success!", ustrRegString));
    58
    59 }
    60
    61 // 第一次调用是为了获取需要的长度
    62
    63 ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);
    64
    65 pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
    66
    67 // 第二次调用是为了获取数据
    68
    69 ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);
    70
    71 for (i = 0; i < pfi->SubKeys; i++)
    72
    73 {
    74
    75 // 获取第i 个子项的长度
    76
    77 ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);
    78
    79 pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);
    80
    81 // 获取第i 个子项的数据
    82
    83 ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);
    84
    85 ustrKeyName.Length = (USHORT)pbi->NameLength;
    86
    87 ustrKeyName.Buffer = pbi->Name;
    88
    89 KdPrint(("[Test] The %d SubItem Name : %wZ.\n", i, &ustrKeyName));
    90
    91 // 释放内存
    92
    93 ExFreePool(pbi);
    94
    95 }
    96
    97 ExFreePool(pfi);
    98
    99 ZwClose(hRegister);
    100
    101 return STATUS_SUCCESS;
    102
    103 }

    4)读与写

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

    http://msdn.microsoft.com/en-us/library/ff567069%28VS.85%29.aspx

    其参数中:

    KeyValueInformationClass:本次查询所需要查询的信息类型。这有如下的三种可能。

    KeyValueBasicInformation:获得基础信息,包含值名和类型。

    KeyValueFullInformation:获得完整信息。包含值名、类型和值的数据。

    KeyValuePartialInformation:获得局部信息。包含类型和值数据。

    使用KeyValuePartialInformation最常见。

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

    示例代码:

    代码
    1 // 要读取的值的名字
    2
    3 UNICODE_STRING my_key_name =
    4
    5 RTL_CONSTANT_STRING(L”SystemRoot”);
    6
    7 // 用来试探大小的key_infor
    8
    9 KEY_VALUE_PARTIAL_INFORMATION key_infor;
    10
    11 // 最后实际用到的key_infor指针。内存分配在堆中
    12
    13 PKEY_VALUE_PARTIAL_INFORMATION ac_key_infor;
    14
    15 ULONG ac_length;
    16
    17 ……
    18
    19 // 前面已经打开了句柄my_key,下面如此来读取值:
    20
    21 status = ZwQueryValueKey(
    22
    23 my_key,
    24
    25 &my_key_name,
    26
    27 KeyValuePartialInformation,
    28
    29 &key_infor,
    30
    31 sizeof(KEY_VALUE_PARTIAL_INFORMATION),
    32
    33 &ac_length);
    34
    35 if(!NT_SUCCESS(status) &&
    36
    37 status != STATUS_BUFFER_OVERFLOW &&
    38
    39 status != STATUS_BUFFER_TOO_SMALL)
    40
    41 {
    42
    43 // 错误处理
    44
    45
    46
    47 }
    48
    49 // 如果没失败,那么分配足够的空间,再次读取
    50
    51 ac_key_infor = (PKEY_VALUE_PARTIAL_INFORMATION)
    52
    53 ExAllocatePoolWithTag(NonpagedPool,ac_length ,MEM_TAG);
    54
    55 if(ac_key_infor == NULL)
    56
    57 {
    58
    59 stauts = STATUS_INSUFFICIENT_RESOURCES;
    60
    61 // 错误处理
    62
    63
    64
    65 }
    66
    67 status = ZwQueryValueKey(
    68
    69 my_key,
    70
    71 &my_key_name,
    72
    73 KeyValuePartialInformation,
    74
    75 ac_key_infor,
    76
    77 ac_length,
    78
    79 &ac_length);
    80
    81 // 到此为止,如果status为STATUS_SUCCESS,则要读取的数据已经
    82
    83 // 在ac_key_infor->Data中。请转换为UNICODE_STRING
    84
    85 ……

    写:

    一般使用函数ZwSetValueKey

    http://msdn.microsoft.com/en-us/library/ff567109%28VS.85%29.aspx

    其中的TileIndex参数请始终填入0

    Data是要写入的数据的开始地址,而DataSize是要写入的数据的长度。由于Data是一个空指针,因此,Data可以指向任何数据。 ZwSetValueKey执行时:如果Value已经存在,则写入覆盖,否则新建一个。下面的例子写入一个名字为“Test”,而且值为“My Test Value”的字符串值。假设my_key是一个已经打开的子键的句柄。

    UNICODE_STRING name = RTL_CONSTANT_STRING(LTest);

    PWCHAR value = { LMy Test Value};

    // 数据长度要将字符串长度加上1,把最后一个空结束符

    status = ZwSetValueKey(my_key,

    &name,0,REG_SZ,value,(wcslen(value)+1)*sizeof(WCHAR));

    if(!NT_SUCCESS(status))

    {

    // 错误处理

    ……

    }

  • 相关阅读:
    收藏题(小试牛刀)
    博客园及相关学习地址收录
    迭代器和生成器
    字典访问的三种方法
    函数进阶(装饰器)
    函数进阶(闭包)
    wx小程序知识点(六)
    wx小程序知识点(五)
    wx小程序知识点(四)
    wx小程序知识点(三)
  • 原文地址:https://www.cnblogs.com/mydomain/p/1855124.html
Copyright © 2011-2022 走看看