Windows驱动学习笔记第六章 在驱动中操作注册表
2010-06-11 09:27:56 作者:教育资源网 来源:教育资源网 浏览次数:0 网友评论 0 条
Windows驱动学习笔记第六章 在驱动中操作注册表
注册表是 Windows 的核心,日常的许多操作其实最终都是转化成了对注册表的操作,
我们经常需要利用注册表达到一些特殊的效果,例如实现自启动等。 6.1 6.1 6.1 6.1 创建、打开注册表
和文件操作类似,在操作注册表之前需要首先打开注册表, 过
函数 ZwCreateKey 完成。
与 ZwCreateFile 函数类似,它通过一个 OBJECT_ATTRIBUTES 获得需要创建或打开 的
路径信息,但在内核中这个路径与用户模式下不相同,如图 6-1 所示:
图 6-1 注册表中路径的写法
实际上,因为用户模式下的应用程序总是由某个 “ 当前用户 ” 打开的,因此在用户模 式
下可以直接访问 HKEY_CLASSES_ROOT 和 HKEY_CURRENT_USER ,但工作在内核模式
下的驱动程序不属于任何一个用户,因此不能直接访问这两个根键。
如果 ZwCreateKey 指定的项不存在,则会直接创建该项,同时由函数的 Disposition 参
数返回 REG_CREATED_NEW_KEY ;如果指定项已经存在了,则 Disposition 返回值
REG_OPENED_EXIS 。
DDK 同样提供了一个 ZwOpenKey 函数用以简化打开注册表的操作。同时 DDK 还提 供
一系列以 Rtl 开头的运行时函数,它们可以是对 Zw 系列函数的封装,可以有效地简化对 注
册表的操作过程。主要的一些函数列表分别如图 6-2 和图 6-3 所示:
图 6-2 注册表相关 Zw 系列函数
驱动学习笔记系列文章汇总
图 6-3 注册表相关 Rtl 系列函数
6.2 6.2 6.2 6.2 读写注册表
注册表是以二元形式存储的,即 “ 键名 ” 和 “ 键值 ” ,通过键名来设置键值,其中键值
分为多种情况,如图 6-4 所示:
图 6-4 键值的分类
我们可以通过 ZwSetValueKey 函数添加或修改注册表键值,通过 ZwQueryValueKey 函
数查询相关键值。这两个函数的使用与 ring3 没有多大差异,通过 DDK 的帮助文档可以很
容易知道它的用法,因此这里不再赘述。 6.3 6.3 6.3 6.3 枚举注册表
枚举注册表是一个非常实用的功能, 项
和枚举一个注册表项的所有子键。
枚举子项使用 ZwQueryKey (注意不是 ZwQueryValueKey )和 ZwEnumerateKey 配合 完
成,枚举子键使用 ZwQueryKey 和 ZwEnumerateValueKey 配合完成。
我们以枚举子项来说明思路, ZwQueryKey 获得某项究竟有多少个子项,然 后
利用 ZwEnumerateKey 来获取指定子项的详细信息,这个过程是通过一个子项索引( index )
来完成的。
在使用 ZwQueryKey 时,可以将参数 KeyInformationClass 指定为 KeyFullInformation ,
它对应 KEY_FULL_INFORMATION 结构中的 SubKeys 指明了该项中有多少子项。
6.4 6.4 6.4 6.4 演示程序
下面的程序演示了如何枚举一个项的所有子项,对于注册表键的读写就不用再费笔墨
了,读者可以自行写出测试程序。
NTSTATUS
RegEnumTest()
驱动学习笔记系列文章汇总
{
UNICODE_STRING ustrRegString;
UNICODE_STRING ustrKeyName;
HANDLE hRegister;
ULONG ulSize, i = 0;
OBJECT_ATTRIBUTES obj_attrib;
NTSTATUS status;
PKEY_FULL_INFORMATION pfi;
PKEY_BASIC_INFORMATION pbi;
// 初始化
RtlInitUnicodeString(&ustrRegString,L
InitializeObjectAttributes(&obj_attrib,
&ustrRegString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
// 打开注册表
status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &obj_attrib);
if (NT_SUCCESS(status))
{
KdPrint(("[Test] ZwOpenKey %wZ Success!", ustrRegString));
} // 第一次调用是为了获取需要的长度
ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);
pfi = (PKEY_FULL_INFORMATION)ExAlloca ulSize);
// 第二次调用是为了获取数据
ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);
for (i = 0; i < pfi->SubKeys; i++)
{
// 获取第 i 个子项的长度
ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);
pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool ulSize);
// 获取第 i 个子项的数据
ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);
ustrKeyName.Length = (USHORT)pbi->NameLength;
ustrKeyName.Buffer = pbi->Name;
KdPrint(("[Test] The %d SubItem Name : %wZ. ", i, &ustrKeyName));
// 释放内存
ExFreePool(pbi);
}
驱动学习笔记系列文章汇总
ExFreePool(pfi);
ZwClose(hRegister);
return STATUS_SUCCESS;
}
上述程序的测试效果如图 6-5 所示:
图 6-5 程序演示效果
驱动学习笔记系列文章汇总
我们经常需要利用注册表达到一些特殊的效果,例如实现自启动等。 6.1 6.1 6.1 6.1 创建、打开注册表
和文件操作类似,在操作注册表之前需要首先打开注册表, 过
函数 ZwCreateKey 完成。
与 ZwCreateFile 函数类似,它通过一个 OBJECT_ATTRIBUTES 获得需要创建或打开 的
路径信息,但在内核中这个路径与用户模式下不相同,如图 6-1 所示:
图 6-1 注册表中路径的写法
实际上,因为用户模式下的应用程序总是由某个 “ 当前用户 ” 打开的,因此在用户模 式
下可以直接访问 HKEY_CLASSES_ROOT 和 HKEY_CURRENT_USER ,但工作在内核模式
下的驱动程序不属于任何一个用户,因此不能直接访问这两个根键。
如果 ZwCreateKey 指定的项不存在,则会直接创建该项,同时由函数的 Disposition 参
数返回 REG_CREATED_NEW_KEY ;如果指定项已经存在了,则 Disposition 返回值
REG_OPENED_EXIS 。
DDK 同样提供了一个 ZwOpenKey 函数用以简化打开注册表的操作。同时 DDK 还提 供
一系列以 Rtl 开头的运行时函数,它们可以是对 Zw 系列函数的封装,可以有效地简化对 注
册表的操作过程。主要的一些函数列表分别如图 6-2 和图 6-3 所示:
图 6-2 注册表相关 Zw 系列函数
驱动学习笔记系列文章汇总
图 6-3 注册表相关 Rtl 系列函数
6.2 6.2 6.2 6.2 读写注册表
注册表是以二元形式存储的,即 “ 键名 ” 和 “ 键值 ” ,通过键名来设置键值,其中键值
分为多种情况,如图 6-4 所示:
图 6-4 键值的分类
我们可以通过 ZwSetValueKey 函数添加或修改注册表键值,通过 ZwQueryValueKey 函
数查询相关键值。这两个函数的使用与 ring3 没有多大差异,通过 DDK 的帮助文档可以很
容易知道它的用法,因此这里不再赘述。 6.3 6.3 6.3 6.3 枚举注册表
枚举注册表是一个非常实用的功能, 项
和枚举一个注册表项的所有子键。
枚举子项使用 ZwQueryKey (注意不是 ZwQueryValueKey )和 ZwEnumerateKey 配合 完
成,枚举子键使用 ZwQueryKey 和 ZwEnumerateValueKey 配合完成。
我们以枚举子项来说明思路, ZwQueryKey 获得某项究竟有多少个子项,然 后
利用 ZwEnumerateKey 来获取指定子项的详细信息,这个过程是通过一个子项索引( index )
来完成的。
在使用 ZwQueryKey 时,可以将参数 KeyInformationClass 指定为 KeyFullInformation ,
它对应 KEY_FULL_INFORMATION 结构中的 SubKeys 指明了该项中有多少子项。
6.4 6.4 6.4 6.4 演示程序
下面的程序演示了如何枚举一个项的所有子项,对于注册表键的读写就不用再费笔墨
了,读者可以自行写出测试程序。
NTSTATUS
RegEnumTest()
驱动学习笔记系列文章汇总
{
UNICODE_STRING ustrRegString;
UNICODE_STRING ustrKeyName;
HANDLE hRegister;
ULONG ulSize, i = 0;
OBJECT_ATTRIBUTES obj_attrib;
NTSTATUS status;
PKEY_FULL_INFORMATION pfi;
PKEY_BASIC_INFORMATION pbi;
// 初始化
RtlInitUnicodeString(&ustrRegString,L
InitializeObjectAttributes(&obj_attrib,
&ustrRegString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
// 打开注册表
status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &obj_attrib);
if (NT_SUCCESS(status))
{
KdPrint(("[Test] ZwOpenKey %wZ Success!", ustrRegString));
} // 第一次调用是为了获取需要的长度
ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);
pfi = (PKEY_FULL_INFORMATION)ExAlloca ulSize);
// 第二次调用是为了获取数据
ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);
for (i = 0; i < pfi->SubKeys; i++)
{
// 获取第 i 个子项的长度
ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);
pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool ulSize);
// 获取第 i 个子项的数据
ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);
ustrKeyName.Length = (USHORT)pbi->NameLength;
ustrKeyName.Buffer = pbi->Name;
KdPrint(("[Test] The %d SubItem Name : %wZ. ", i, &ustrKeyName));
// 释放内存
ExFreePool(pbi);
}
驱动学习笔记系列文章汇总
ExFreePool(pfi);
ZwClose(hRegister);
return STATUS_SUCCESS;
}
上述程序的测试效果如图 6-5 所示:
图 6-5 程序演示效果
驱动学习笔记系列文章汇总
前后热点
相关文章
[错误报告] [推荐] [收藏] [打印] [关闭] [返回顶部]

已有