| 
 | 
	
 
 
4、注册表操作 
 
和文件操作类似,在操作注册表之前需要首先打开注册表,获得一个句柄,这可以通过函数ZwCreateKey 完成。与ZwCreateFile函数类似,它通过一个OBJECT_ATTRIBUTES 获得需要创建或打开的路径信息,但在内核中这个路径与用户模式下不相同,实际上,因为用户模式下的应用程序总是由某个“当前用户”打开的,因此在用户模式下可以直接访问HKEY_CLASSES_ROOT 和HKEY_CURRENT_USER,但工作在内核模式下的驱动程序不属于任何一个用户,因此不能直接访问这两个根键。 
如果ZwCreateKey 指定的项不存在,则会直接创建该项,同时由函数的Disposition参数返回REG_CREATED_NEW_KEY;如果指定项已经存在了,则 Disposition返回值REG_OPENED_EXISTING_KEY。DDK同样提供了一个ZwOpenKey函数用以简化打开注册表的操作。同时DDK还提供一系列以Rtl 开头的运行时函数,它们可以是对Zw系列函数的封装,可以有效地简化对注册表的操作过程。 
 
 
 
 
表 Zw系统注册相关函数 
http://msdn.microsoft.com/en-us/library/ff566425%28VS.85%29.aspx 
 
 
表 Rtl系统注册相关函数 
http://msdn.microsoft.com/en-us/library/ff561822%28VS.85%29.aspx 
1)读写注册表 
注册表是以二元形式存储的,即“键名”和“键值”,通过键名来设置键值,其中键值分为多种情况。 
 
 
表 注册键类型 
通过ZwSetValueKe y 函数添加或修改注册表键值,通过ZwQueryValueKe y 函 
数查询相关键值。 
2)枚举 
枚举注册表通常分两种情况:枚举一个注册表项的所有子项和枚举一个注册表项的所有子键。 
枚举子项使用ZwQueryKey(注意不是ZwQueryValueKey)和ZwEnumerateKe y配合完成,枚举子键使用ZwQueryKey和ZwEnumerateValueKey配合完成。 
我们以枚举子项来说明思路,首先利用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(L”Test”); 
PWCHAR value = { L”My Test Value” }; 
… 
// 数据长度要将字符串长度加上1,把最后一个空结束符 
status = ZwSetValueKey(my_key, 
&name,0,REG_SZ,value,(wcslen(value)+1)*sizeof(WCHAR)); 
if(!NT_SUCCESS(status)) 
{ 
// 错误处理 
…… 
} |   
 
 
 
 |