在驱动程序的开发中,经常会对注册表进行操作。注册表的主要组成如图3-1所示,注册表的五个主要组成部分如下。
上述函数中,参数InitializedAttributes指向需要初始化的OBJECT_ATTRIBUTES结构体;参数ObjectName 描述需要打开的注册表对象的名称,用Unicode字符串表示;参数Attributes为标识,若将其设置为OBJ_CASE_INSENSITIVE,则在用ObjectName与已存在的对象进行比较时就不区分大小写了;参数RootDirectory用于描述ObjectName参数的根目录,如果ObjectName是一个完全的名称,则设为NULL;参数SecurityDescriptor为一个安全描述,如果把它设为NULL,驱动程序将采用默认的安全设置。 2. 打开注册表 WDK提供了内核函数ZwOpenKey,用来打开一个已存在的注册表项。如果ZwOpenKey指定的项不存在,则其不会创建这个项,而是返回一个错误状态。该函数的原型如下:
上述函数中,参数KeyHandle返回被打开的句柄;参数DesiredAccess为打开的权限,一般设为KEY_ALL_ACCESS;参数ObjectAttributes是OBJECT_ATTRIBUTES数据结构,用于指示打开的状态。 如果打开成功,函数ZwOpenKey返回STATUS_SUCCESS,否则返回一个错误代码,错误代码可能为STATUS_INVALID_HANDLE或STATUS_ACCESS_DENIED。 3. 关闭注册表 已打开的注册表,如果不再使用,需要采用ZwClose函数关闭它,其原型如下: NTSTATUS ZwClose( IN HANDLE Handle ); 上述函数中,参数Handle为所要关闭的注册表句柄。 4. 查询注册表 驱动程序中有时需要对注册表的项进行查询,从而获取注册表的键值。WDK提供的ZwQueryValueKey函数可以完成这个任务,其原型如下:
上述函数中,参数KeyHandle为打开的注册表句柄;参数ValueName为要查询的键名;参数KeyValueInformationClass决定不同的查询类别;参数KeyValueInformation用于选择一种查询类别,可选择KeyValueBasicInformation、KeyValueFullInformation或KeyValuePartialInformation类型;参数Length为要查询数据的长度;参数ResultLength为实际查询返回的数据长度。 如果打开成功,函数返回STATUS_SUCCESS,否则返回一个错误代码。 使用ZwQueryValueKey函数查询注册表单时,需要用KeyValueInformationClass参数来选择一种查询方式,可以是KeyValueBasicInformation、KeyValueFullInformation或者KeyValuePartialInformation中的一种。它们分别代表查询基本信息、查询全部信息和查询部分信息,并且每种查询类型会用一种对应的数据结构来获得查询结果。 一般情况下,选择KeyValuePartialInformation参数就可以查询键值的数据了,它对应的查询数据结构是KEY_VALUE_PARTIAL_INFORMATION,具体定义如下:
注意KEY_VALUE_PARTIAL_INFORMATION数据结构的长度并未固定,所以首先要确定这个长度。 使用ZwQueryValueKey函数时,一般会按下列四个步骤进行操作: 用ZwQueryValueKey函数获取这个数据结构的长度。 分配如此长度的内存,用来查询。 再次调用ZwQueryValueKey函数,获取键值。 回收内存。 如果选择KeyValueFullInformation参数,它对应的是KEY_VALUE_FULL_INFORMATION查询数据结构体,具体定义如下:
5. 枚举子项 在注册表中,经常使用另外两种操作,分别是枚举子项和枚举子键。枚举子项就是事先不知道该项中有多少个子项目,用某个函数将子项一一列举出来。而枚举子键是指事先不知道该项中有多少个子键,用某个函数将子键一一列举出来。 WDK提供了列举子项的ZwQueryKey函数和ZwEnumerateKey函数。ZwQueryKey函数的作用主要是获得某注册表项究竟有多少个子项,而ZwEnumerateKey函数的作用主要是针对某个子项获取其具体信息。接下来看一看这两个函数的原型。 ZwQueryKey函数的原型如下:
上述函数中,参数KeyHandle为注册表项的句柄;参数KeyInformationClass为查询的类别,一般选择KeyFullInformation;参数KeyInformation为查询的数据指针,如果KeyInformationClass是KeyFullInformation,则该指针指向一个KEY_FULL_INFORMATION的数据结构;参数Length为数据长度;参数ResultLength为实际返回数据的长度。 如果函数执行成功,返回STATUS_SUCCESS,否则返回一个错误代码。 ZwEnumerateKey函数的原型如下:
上述函数中,参数KeyHandle为注册表项句柄;参数Index为从0开始的索引;参数KeyInformationClass为子项的信息类型;参数Length为子项信息的长度;参数ResultLength为返回子键信息的长度。 如果函数执行成功,返回STATUS_SUCCESS,否则返回一个错误代码。 在使用ZwQueryKey函数时,可以将参数KeyInformationClass指定为KeyFullInformation。这样,参数KeyInformation就可对应一个KEY_FULL_INFORMATION的数据结构了,该数据结构中的SubKeys指明了该项中有多少个子项。KEY_FULL_INFORMATION数据结构的长度可变,所以要调用两次ZwQueryKey,第一次获取KEY_FULL_INFORMATION结构的长度,第二次才是真正获取KEY_FULL_INFORMATION结构的数据。 在使用ZwEnumerateKey函数时,需要将参数KeyInformationClass设置为KeyBasicInformation,这样,参数KeyInformation就能对应KEY_BASIC_INFORMATION的数据结构了。KEY_BASIC_INFORMATION数据结构长度也是可变的,故同样需要调用ZwEnumerateKey两次,第一次获取KEY_BASIC_INFORMATION结构的长度,第二次获取KEY_BASIC_INFORMATION结构的数据。 6. 枚举子键 和枚举子项类似,通过ZwQueryKey和ZwEnumerateValueKey这两个函数的配合可以完成对子键的枚举。ZwEnumerateValueKey函数的使用方法和ZwEnumerateKey函数类似,其原型如下:

VOID InitializeObjectAttributes( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN HANDLE RootDirectory, IN PSECURITY_DESCRIPTOR SecurityDescriptor );
上述函数中,参数InitializedAttributes指向需要初始化的OBJECT_ATTRIBUTES结构体;参数ObjectName 描述需要打开的注册表对象的名称,用Unicode字符串表示;参数Attributes为标识,若将其设置为OBJ_CASE_INSENSITIVE,则在用ObjectName与已存在的对象进行比较时就不区分大小写了;参数RootDirectory用于描述ObjectName参数的根目录,如果ObjectName是一个完全的名称,则设为NULL;参数SecurityDescriptor为一个安全描述,如果把它设为NULL,驱动程序将采用默认的安全设置。 2. 打开注册表 WDK提供了内核函数ZwOpenKey,用来打开一个已存在的注册表项。如果ZwOpenKey指定的项不存在,则其不会创建这个项,而是返回一个错误状态。该函数的原型如下:
NTSTATUS ZwOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes );
上述函数中,参数KeyHandle返回被打开的句柄;参数DesiredAccess为打开的权限,一般设为KEY_ALL_ACCESS;参数ObjectAttributes是OBJECT_ATTRIBUTES数据结构,用于指示打开的状态。 如果打开成功,函数ZwOpenKey返回STATUS_SUCCESS,否则返回一个错误代码,错误代码可能为STATUS_INVALID_HANDLE或STATUS_ACCESS_DENIED。 3. 关闭注册表 已打开的注册表,如果不再使用,需要采用ZwClose函数关闭它,其原型如下: NTSTATUS ZwClose( IN HANDLE Handle ); 上述函数中,参数Handle为所要关闭的注册表句柄。 4. 查询注册表 驱动程序中有时需要对注册表的项进行查询,从而获取注册表的键值。WDK提供的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为打开的注册表句柄;参数ValueName为要查询的键名;参数KeyValueInformationClass决定不同的查询类别;参数KeyValueInformation用于选择一种查询类别,可选择KeyValueBasicInformation、KeyValueFullInformation或KeyValuePartialInformation类型;参数Length为要查询数据的长度;参数ResultLength为实际查询返回的数据长度。 如果打开成功,函数返回STATUS_SUCCESS,否则返回一个错误代码。 使用ZwQueryValueKey函数查询注册表单时,需要用KeyValueInformationClass参数来选择一种查询方式,可以是KeyValueBasicInformation、KeyValueFullInformation或者KeyValuePartialInformation中的一种。它们分别代表查询基本信息、查询全部信息和查询部分信息,并且每种查询类型会用一种对应的数据结构来获得查询结果。 一般情况下,选择KeyValuePartialInformation参数就可以查询键值的数据了,它对应的查询数据结构是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_INFORMATION;注意KEY_VALUE_PARTIAL_INFORMATION数据结构的长度并未固定,所以首先要确定这个长度。 使用ZwQueryValueKey函数时,一般会按下列四个步骤进行操作: 用ZwQueryValueKey函数获取这个数据结构的长度。 分配如此长度的内存,用来查询。 再次调用ZwQueryValueKey函数,获取键值。 回收内存。 如果选择KeyValueFullInformation参数,它对应的是KEY_VALUE_FULL_INFORMATION查询数据结构体,具体定义如下:
Typedef struct _KEY_VALUE_FULL_INFORMATION{
ULONG TitleIndex;
ULONG Type;
ULONG DataOffset;
ULONG DataLength;
ULONG NameLength;
WCHAR Name[1]; //
}KEY_VALUE_FULL_INFORMATION,*PKEY_VALUE_FULL_INFORMATION;5. 枚举子项 在注册表中,经常使用另外两种操作,分别是枚举子项和枚举子键。枚举子项就是事先不知道该项中有多少个子项目,用某个函数将子项一一列举出来。而枚举子键是指事先不知道该项中有多少个子键,用某个函数将子键一一列举出来。 WDK提供了列举子项的ZwQueryKey函数和ZwEnumerateKey函数。ZwQueryKey函数的作用主要是获得某注册表项究竟有多少个子项,而ZwEnumerateKey函数的作用主要是针对某个子项获取其具体信息。接下来看一看这两个函数的原型。 ZwQueryKey函数的原型如下:
NTSTATUS ZwQueryKey( IN HANDLE KeyHandle, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG Length, OUT PULONG ResultLength );
上述函数中,参数KeyHandle为注册表项的句柄;参数KeyInformationClass为查询的类别,一般选择KeyFullInformation;参数KeyInformation为查询的数据指针,如果KeyInformationClass是KeyFullInformation,则该指针指向一个KEY_FULL_INFORMATION的数据结构;参数Length为数据长度;参数ResultLength为实际返回数据的长度。 如果函数执行成功,返回STATUS_SUCCESS,否则返回一个错误代码。 ZwEnumerateKey函数的原型如下:
NTSTATUS ZwEnumerateKey( IN HANDLE KeyHandle, IN ULONG Index, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG Length, OUT PULONG ResultLength );
上述函数中,参数KeyHandle为注册表项句柄;参数Index为从0开始的索引;参数KeyInformationClass为子项的信息类型;参数Length为子项信息的长度;参数ResultLength为返回子键信息的长度。 如果函数执行成功,返回STATUS_SUCCESS,否则返回一个错误代码。 在使用ZwQueryKey函数时,可以将参数KeyInformationClass指定为KeyFullInformation。这样,参数KeyInformation就可对应一个KEY_FULL_INFORMATION的数据结构了,该数据结构中的SubKeys指明了该项中有多少个子项。KEY_FULL_INFORMATION数据结构的长度可变,所以要调用两次ZwQueryKey,第一次获取KEY_FULL_INFORMATION结构的长度,第二次才是真正获取KEY_FULL_INFORMATION结构的数据。 在使用ZwEnumerateKey函数时,需要将参数KeyInformationClass设置为KeyBasicInformation,这样,参数KeyInformation就能对应KEY_BASIC_INFORMATION的数据结构了。KEY_BASIC_INFORMATION数据结构长度也是可变的,故同样需要调用ZwEnumerateKey两次,第一次获取KEY_BASIC_INFORMATION结构的长度,第二次获取KEY_BASIC_INFORMATION结构的数据。 6. 枚举子键 和枚举子项类似,通过ZwQueryKey和ZwEnumerateValueKey这两个函数的配合可以完成对子键的枚举。ZwEnumerateValueKey函数的使用方法和ZwEnumerateKey函数类似,其原型如下:
NTSTATUS ZwEnumerateValueKey( IN HANDLE KeyHandle, IN ULONG Index, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, OUT PVOID KeyValueInformation, IN ULONG Length, OUT PULONG ResultLength );
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (0)
站点信息
- 文章2315
- 用户1336
- 访客11886327
每日一句
Love is seeing, and it is space.
爱是看见,也是空间。
爱是看见,也是空间。