内核模式下的注册表操作
注册表里的几个概念:
1. 创建关闭注册表项
NTSTATUS
ZwCreateKey(
OUT PHANDLE KeyHandle,
IN ACCESS_MASK DesiredAccess, //访问权限,一般为KEY_ALL_ACCLESS
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG TitleIndex, //一般为NULL
IN PUNICODE_STRING Class OPTIONAL, //一般为NULL
IN ULONG CreateOptions, //一般为REG_OPTION_NON_VOLATILE
OUT PULONG Disposition OPTIONAL //返回是打开成功还是创建成功
);
如果ZwCreateKey指定的项目不存在,则直接创建这个项目,并利用Disposition 参数返回REG_CREATED_NEW_KEY。如果该项目已经存在,Disposition 参数返回REG_OPENED_EXISTING_KEY。
示例代码:
//新建注册表项为HKEY_LOCAL_MACHINE\SOFTWARE\Mzf
#define MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\Mzf"
#pragma INITCODE
VOID TetsKey()
{
UNICODE_STRING string1;
RtlInitUnicodeString(&string1, MY_REG_SOFTWARE_KEY_NAME);
OBJECT_ATTRIBUTES objAttribute;
InitializeObjectAttributes(&objAttribute, &string1, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE hKey;
ULONG Des;
NTSTATUS status = ZwCreateKey(&hKey, KEY_ALL_ACCESS, &objAttribute,
NULL, NULL, REG_OPTION_NON_VOLATILE, &Des);
if (NT_SUCCESS(status))
{
if (Des == REG_CREATED_NEW_KEY)
{
KdPrint(("新建注册表项!\n"));
}
else
{
KdPrint(("要创建的注册表项已经存在!\n"));
}
}
//打开或创建注册表子项
UNICODE_STRING string2;
RtlInitUnicodeString(&string2, L"SubKey");
OBJECT_ATTRIBUTES subObjAttribute;
//注意最后第二个参数,为父键的句柄
InitializeObjectAttributes( &subObjAttribute, &string2, OBJ_CASE_INSENSITIVE, hKey, NULL);
HANDLE hSubKey;
ULONG subDes;
status = ZwCreateKey(&hSubKey, KEY_ALL_ACCESS, &subObjAttribute,
NULL, NULL, REG_OPTION_NON_VOLATILE, &subDes);
if (NT_SUCCESS(status))
{
if (subDes == REG_CREATED_NEW_KEY)
{
KdPrint(("新建注册表子项!\n"));
}
else
{
KdPrint(("要创建的注册表子项已经存在!\n"));
}
}
//关闭注册表句柄
ZwClose(hKey);
ZwClose(hSubKey);
}
2. 打开注册表项
NTSTATUS
ZwOpenKey(
OUT PHANDLE KeyHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
3. 添加,修改注册表键值
注册表键值是以二元形式存储的,既“键名”和“键值”。通过键名设置键值,而键值可以分为以下几类:
分类 |
描述 |
REG_BINARY |
键使用二进制存储 |
REG_SZ |
键使用宽字符串,字符串以\0结尾 |
REG_EXPAND_SZ |
该字符是扩展的字符,其它同上 |
REG_MULTI_SZ |
键值存储多个字符串,每个字符串以\0隔开 |
REG_DWORD |
键值用4字节整型存储 |
REG_QWORD |
键值使用8字节存储 |
在添加和修改注册表键值的时候,要分类进行添加和修改。DDK提供了ZwSetValueKey函数来完成这个任务。
NTSTATUS
ZwSetValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName, //要新建或者修改的键名
IN ULONG TitleIndex OPTIONAL, //一般设为0
IN ULONG Type, //键值类型,上表中的一个
IN PVOID Data, //数据
IN ULONG DataSize //记录键值数据大小
);
在使用ZwSetValueKey函数的时候,如果指定的键名不存在,则直接创建。否则,对已有的键值进行修改。
示例代码:
#define MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\Mzf"
#pragma INITCODE
NTSTATUS TetsKey()
{
//初始化注册表项
UNICODE_STRING stringKey;
RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);
//初始化OBJECT_ATTRIBUTES结构
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, &stringKey,
OBJ_CASE_INSENSITIVE, NULL, NULL);
//打开注册表项
HANDLE hKey;
NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);
if (!NT_SUCCESS(status))
{
KdPrint(("打开注册表项失败!\n"));
return status;
}
//初始化valueName
UNICODE_STRING valueName;
RtlInitUnicodeString(&valueName, L"valueName REG_DWORD");
//设置REG_DWORD键值
ULONG ulValue = 100;
status = ZwSetValueKey(hKey, &valueName, 0, REG_DWORD, &ulValue, sizeof(ulValue));
if (!NT_SUCCESS(status))
{
KdPrint(("设置1键值失败!\n"));
return status;
}
//设置REG_SZ键值
RtlInitUnicodeString(&valueName, L"valueName REG_SZ");
WCHAR* str = L"Hello World";
status = ZwSetValueKey(hKey, &valueName, 0, REG_SZ, str, wcslen(str)*2 + 2);
if (!NT_SUCCESS(status))
{
KdPrint(("设置2键值失败!\n"));
return status;
}
//设置REG_BINARY键值
RtlInitUnicodeString(&valueName, L"valueName REG_BINARY");
UCHAR buffer[10];
RtlFillMemory(buffer, sizeof(buffer), 0xFF);
status = ZwSetValueKey(hKey, &valueName, 0, REG_BINARY, buffer, sizeof(buffer));
if (!NT_SUCCESS(status))
{
KdPrint(("设置3键值失败!\n"));
return status;
}
//关闭注册表句柄
ZwClose(hKey);
return status;
}
4. 查询注册表
NTSTATUS
ZwQueryValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName, //要查询的键名
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, //查询的类别
OUT PVOID KeyValueInformation, //返回查询的信息
IN ULONG Length, //要查数据的长度
OUT PULONG ResultLength //实际查询数据的长度
);
在使用上述函数对注册表键值进行查询时,需要指定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分为以下四个步骤:
(1) 用ZwQueryValueKey获取这个数据结构的长度。
(2)分配如此长度的内存,用来查询
(3)再次调用ZwQueryValueKey,获取键值
(4)回收内存。
示例代码:
#define MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\Mzf"
#pragma INITCODE
NTSTATUS TetsKey()
{
//初始化注册表项
UNICODE_STRING stringKey;
RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);
//初始化OBJECT_ATTRIBUTES结构
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, &stringKey,
OBJ_CASE_INSENSITIVE, NULL, NULL);
//打开注册表项
HANDLE hKey;
NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);
if (!NT_SUCCESS(status))
{
KdPrint(("打开注册表项失败!\n"));
return status;
}
//初始化valueName
UNICODE_STRING valueName;
RtlInitUnicodeString(&valueName, L"valueName REG_DWORD");
//获取实际查询的数据的大小
ULONG ulSize = 0;
status = ZwQueryValueKey(hKey, &valueName,
KeyValuePartialInformation, NULL, 0, &ulSize);
if (status == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0)
{
ZwClose(hKey);
KdPrint(("注册表键值不存在!\n"));
return status;
}
//分配实际查询所需的内存空间
PKEY_VALUE_PARTIAL_INFORMATION pkvpi =
(PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
//查询键值
status = ZwQueryValueKey(hKey, &valueName, KeyValuePartialInformation,
pkvpi, ulSize, &ulSize);
if(!NT_SUCCESS(status))
{
ZwClose(hKey);
KdPrint(("查询注册表键值失败!\n"));
return status;
}
//判断是否为REG_DWORD类型
if (pkvpi->Type == REG_DWORD && pkvpi->DataLength == sizeof(ULONG))
{
PULONG a = (PULONG)pkvpi->Data;
KdPrint(("%d\n", *a));
}
//关闭注册表句柄
ZwClose(hKey);
return status;
}
5. 枚举子项
DDK提供了两个函数,他们组合使用可以起到枚举子项的作用。
NTSTATUS
ZwQueryKey(
IN HANDLE KeyHandle,
IN KEY_INFORMATION_CLASS KeyInformationClass,
OUT PVOID KeyInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
NTSTATUS
ZwEnumerateKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_INFORMATION_CLASS KeyInformationClass,
OUT PVOID KeyInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
ZwQueryKey的作用主要是获得注册表项究竟有多少个子项,而ZwEnumerateKey的作用主要是针对第几个子项,获取该子项的具体信息。
在使用ZwQueryKey时,可以将参数KeyInformationClass指定为KeyFullInformation。这样参数KeyInformation就对应一个KEY_FULL_INFORMATION的数据结构。该结构中的SubKeys指明了项中有多少子项。
在使用ZwEnumerateKey时,需要将参数KeyInformationClass指定为KeyBasicInformation,已返回子项的基本信息。
注意:上面提到的这两个结构都是变长的,在使用时需要调用两次函数。第一次获得长度,第二次真正得到数据。
示例代码:
#define MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\Mzf"
#pragma INITCODE
NTSTATUS TetsKey()
{
//初始化注册表项
UNICODE_STRING stringKey;
RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);
//初始化OBJECT_ATTRIBUTES结构
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, &stringKey,
OBJ_CASE_INSENSITIVE, NULL, NULL);
//打开注册表项
HANDLE hKey;
NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);
if (!NT_SUCCESS(status))
{
KdPrint(("打开注册表项失败!\n"));
return status;
}
//第一次调用ZwQueryKey,为了获取KEY_FULL_INFORMATION数据的长度
ULONG ulSize = 0;
status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &ulSize);
//申请内存
PKEY_FULL_INFORMATION pkfi =
(PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
//第二次调用ZwQueryKey,为了获取KEY_FULL_INFORMATION数据
status = ZwQueryKey(hKey, KeyFullInformation, pkfi, ulSize, &ulSize);
for (ULONG i=0; i<pkfi->SubKeys; i++)
{
//第一次调用ZwEnumerateKey,为了获取KEY_BASIC_INFORMATION数据的长度
ZwEnumerateKey(hKey, i, KeyBasicInformation, NULL, 0, &ulSize);
//非配内存
PKEY_BASIC_INFORMATION pkbi =
(PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);
//第二次调用ZwEnumerateKey,为了获取KEY_BASIC_INFORMATION数据 ZwEnumerateKey(hKey, i, KeyBasicInformation, pkbi, ulSize, &ulSize);
UNICODE_STRING string;
string.Length = string.MaximumLength = (USHORT)pkbi->NameLength;
string.Buffer = (PWSTR)ExAllocatePool(PagedPool, string.Length);
RtlCopyMemory(string.Buffer, pkbi->Name, string.Length);
KdPrint(("第 %d 个子项: %wZ!\n", i, &string));
RtlFreeUnicodeString(&string);
枚举子键是通过ZwQueryKey和ZwEnumerateValueKey两个函数配合完成的。
#define MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\Mzf"
RtlInitUnicodeString(&stringKey, MY_REG_SOFTWARE_KEY_NAME);
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, &stringKey,
OBJ_CASE_INSENSITIVE, NULL, NULL);
NTSTATUS status = ZwOpenKey(&hKey, GENERIC_ALL, &ObjectAttributes);
status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &ulSize);
(PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
status = ZwQueryKey(hKey, KeyFullInformation, pkfi, ulSize, &ulSize);
for (ULONG i=0; i<pkfi->Values; i++)
ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, NULL, 0, &ulSize);
PKEY_VALUE_BASIC_INFORMATION pkbi =
(PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);
ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, pkbi, ulSize, &ulSize);
string.Length = string.MaximumLength = (USHORT)pkbi->NameLength;
string.Buffer = (PWSTR)ExAllocatePool(PagedPool, string.Length);
RtlCopyMemory(string.Buffer, pkbi->Name, string.Length);
KdPrint(("第 %d 个子项: %wZ!\n", i, &string));
RtlFreeUnicodeString(&string);
NTSTATUS
ZwDeleteKey(
IN HANDLE KeyHandle
);
需要指出,该函数只能删除没有子项的项目。如果项中有子项,则不能删除。这时候需要先将该项中的所有子项全部删除,再删除该项。
为了简化注册表的操作,DDK还提供了一系列以Rtl开头的运行时函数,这些函数把前面介绍的函数进行了封装。往往一条函数就能实现前面介绍的若干条函数的功能。
分类 |
描述 |
RtlCreateRegistryKey |
创建注册表 |
RtlCheckRegistryKey |
查看某注册表项是否存在 |
RtlWriteRegistryValue |
写注册表 |
RtlDeleteRegistryValue |
删除注册表的子键 |
内核模式下的注册表操作相关推荐
- 系统安全-Windows下的注册表操作
注册表 可以说是用于存储计算机所有设置及配置信息的数据库,我们在设置中做出的各种更改归根结底是修改了计算机中的注册表.具体定义如下: 注册表(Registry,繁体中文版Windows操作系统称之为登 ...
- RegistryCallback routine(CmRegisterCallback 注册表操作监控介绍)
RegistryCallback routine 过滤器驱动程序的常规RegistryCallback可以监视,阻止或修改一个注册表操作. 句法 C ++ NTSTATUS CmRegisterCal ...
- QSettings配置读写-win注册表操作-ini文件读写
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSettings配置读写-win注册表操作-ini文件读写 本文地址:http:// ...
- delphi 注册表操作(读取、添加、删除、修改)完全手册
32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息. 一.创建和释放TRegistry对象 1.创建TRegistry对象.为了操作注册表,要创建一个TRegistry对象: ...
- delphi 注册表操作之(读取、添加、删除、修改)
32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息. 一.创建和释放TRegistry对象 1.创建TRegistry对象.为了操作注册表,要创建一个TRegistry对象: ...
- oracle在非归档模式下,Oracle在非归档模式下不能更改表空间为备份模式
Oracle表空间设置为备份模式后,便可以联机对表空间下数据文件进行文件系统级别的copy备份操作,因为期间对表空间的修改都记录到数据库的重做日志文件中. 由此想到数据库如果是非归档模式,那么这个表空 ...
- Windows注册表操作基础代码
Windows注册表操作基础代码 Windows下对注册表进行操作使用的一段基础代码Reg.h: #pragma once #include<assert.h> #include< ...
- Windows核心编程_注册表操作和小练习程序关联
大家有没有见过就是当我们下载一个软件比如视频播放器 下载之后我们电脑上的视频文件图标都变成了这个视频播放器的图标,然后打开时也是默认调用此视频播放器来播放 下面就给大家介绍如何在Windows平台上实 ...
- oracle数据库中emp表,根据Oracle数据库scott模式下的emp表和dept表
Oracle数据库scott模式下的emp表和dept表的搜索练习,仅供参考 题目要求:根据Oracle数据库scott模式下的emp表和dept表,完成下列操作. (1) 查询20号部门的所有员工信 ...
最新文章
- struts2_11_实现自己的拦截器的定义
- java query类是什么类_java – 从包生成QueryDsl Q类
- python+scapy 抓包与解析
- 左神算法:将搜索二叉树转换成双向链表(Java版)
- Python 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、...
- 腾讯四位创始人向深圳大学捐3.5亿元:启动人才基金
- 详解斯坦纳点及斯坦纳树及模版归纳总结
- java 函数式编程应用_java8 函数式编程应用
- 前端框架Vue(15)——vue-cli 仿网易云音乐 Demo,环境搭建到开发 Vue 全家桶练手项目
- java 错误 找不到符号_java错误:找不到符号
- angr符号执行用例解析——0ctf_momo_3
- mysql日期转为周数
- 怎样清空微信全部聊天记录?轻松几步!如何操作清除微信聊天记录?
- 【小牛分享】jquery mobile网页demo实例代码下载
- pip包离线下载安装(亲测可用)
- 下载yahoo股票历史数据
- Java成神之路(二十六)Hibernate
- 以下不是python内置函数的是_python课堂整理16---内置函数
- 放弃android系列结局得出结论
- python selenium 等待元素出现_Selenium 3种等待方式
热门文章
- sqlserver中计算某个特殊字符在字符串中出现的位置
- 学习笔记-Redis设计与实现-跳跃表
- 《PHP精粹:编写高效PHP代码》——2.1节数据持久化和Web应用程序
- Caused by: java.lang.ClassNotFoundException: javax.persistence.Entity
- PIL 学习笔记(3)
- 什么是区块链技术?初学者指南
- Build RESTful client
- CentOS 7 安装harbor1.5.0
- 两行 CSS 代码实现图片任意颜色赋色技术
- Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志【转】