内核与驱动_05_注册表

注册表操作

  • 与应用程序编程的方式类似,注册表是一个巨大的树形结构,操作一般都是打开某个子健,子健下有若干个值可以获得,每一个值有一个名字。
  • 子健一般用一个路径来表示,与应用程序编程不同的是这个路径的写法不一样,在应用编程中需要提供一个根子健的句柄,而驱动编程中则需要全部用路径表示。
  • 下述是一个根子健句柄与内核注册表路径对照表:
应用编程中的子健驱动中对应的路径写法
HKEY_LOCAL_MACHINE\Registry\Machine
HKEY_USERS\Registry\User
HKEY_CLASSES_ROOT没有对应的路径
HKEY_CURRENT_USER没有简单的对应路径,但是可以求得

常用API

函数名作用
ZwCreateKey创建或打开一个键
ZwOpenKey打开一个键
ZwQueryValueKey读取键值
ZwSetValueKey写入键值
ZwDeleteKey删除Key
ZwDeleteValueKey删除键值
ZwQueryKey读取键的信息
  • 在驱动编程中最常使用ZwOpenKey函数,函数原型如下
NTATATUS ZwOptnKey(
	OUT PHANDLE KeyHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes
);
  • 函数也是要求输入一个OBJECT_ATTRIBUTES结构体指针。
  • DesireAccess可以是下述权限的任意组合:
描述
KEY_QUERY_VALUE读取键下的值
KEY_SET_VALUE设置键下的值
KEY_CREATE_SUB_KEY生成子子键
KEY_ENUMERATE_SUB_KEYS枚举子键
KEY_READ一个组合好的宏,可以直接用对应的还有KEY_WRITE,KEY_ALL_ACCESS

基础操作

  • 对于注册表主要实现打开、读、写这三种操作

打开:

  • ZwOpenKey()

读:

  • 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	//返回实际需要的长度
);
  • KeyValueInformationClass是一个枚举类型,要查询的信息类型可以是以下三种:
信息说明
KeyValueBasicInformation获得基础信息,包含值名和类型
KeyValueFullInformation获得完整信息,包含值名、类型和值的数据
KeyValuePartialInformation获得局部信息,包含类型和值的数据(最常用)
  • 当然也可是以下的枚举值中的一种:
typedef enum _KEY_INFORMATION_CLASS {
    KeyBasicInformation,
    KeyNodeInformation,
    KeyFullInformation,
    KeyNameInformation,
    KeyCachedInformation,
    KeyFlagsInformation,
    KeyVirtualizationInformation,
    KeyHandleTagsInformation,
    KeyTrustInformation,
    KeyLayerInformation,
    MaxKeyInfoClass  // MaxKeyInfoClass should always be the last enum
} KEY_INFORMATION_CLASS;
  • KeyValueInformation:当KeyValueInformationClass值为KeyValuePartialInformation+时,KEY_VALUE_PARTIAL_INFORMATION`这个结构将被返回到这个指针所指向的内存中。结构原型如下:
typedef struct _KEY_VALUE_PARTIAL_INFORMATION(
    ULONG TitileIndex;	//请忽略这个成员
    ULONG Type;			//数据类型
    ULONG DataLength;	//数据长度
    UCHAR Data[1];		//可变长度的数据
)KEY_VALUE_PARTIAL_INFORMATION,*PKEY_VALUE_PARTIAL_INFORMATION;
  • 返回值:如果实际需要的长度比Length大,那么返回STATUS_BUFFER_OVERFLOW-0x80000005或者STATUS_BUFFER_TOO_SMALL,成功返回STATUS_SUCCESS. c

  • ZwSetValueKey
  • 较为简单,直接写入注册表就好,函数原型如下:
NTSTATUS ZwSetValueKey(
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING ValueName,
    IN ULONG TitileIndex OPTIONAL,
    IN ULONG Type,
    IN PVOID Data,
    IN ULONG DataSize
);
//参数解释:
//1. 其中KeyHandle、ValueName两个参数和ZwQueryValueKey中的参数相同。
//2. Data和DataSize:Data是写入的数据的开始地址,DataSize是要写入数据的长度。Data类型为PVOID空指针,所以Data可以指向任何的数据
  • Type可以有如下的类型,具体查看MSDN:
含义
REG_BINARY任何形式的二进制数据
REG_DWORD一个四字节的数值
REG_LINK命名符号链接的Unicode字符串
REG_NONE没有特定类型的数据
REG_SZ空终止的Unicode字符串
  • 使用此函数时,如果键值已存在,那么就覆盖,不存在时会新建一个键。

驱动中注册表使用

  • 打开键的函数
//函数用来获取一个键
NTSTATUS MyZwOpenKey(PHANDLE hKey, PUNICODE_STRING pKeyPath)
{
	//初始化OBJECT_STTRIBUTE
	OBJECT_ATTRIBUTES objAttribute = { 0 };
	InitializeObjectAttributes(&objAttribute, pKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
	//打开key
	NTSTATUS status = STATUS_SUCCESS;
	status = ZwOpenKey(hKey, KEY_READ, &objAttribute);
	return status;
}
  • 读取键值
NTSTATUS MyZwQueryValueKey(HANDLE hKey,PUNICODE_STRING pKeyName)
{
	//定义一个用来试探key值大小的info
	KEY_VALUE_PARTIAL_INFORMATION firstInfo;
	//再定义一个实际用到的info结构体指针,之后动态申请堆空间
	PKEY_VALUE_PARTIAL_INFORMATION pInfo;
	ULONG length = 0;
	NTSTATUS status = STATUS_SUCCESS;
	//开始读取
	status = ZwQueryValueKey(hKey, pKeyName,KeyValuePartialInformation, &firstInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION),
		&length);
	if (!NT_SUCCESS(status)&&status!=STATUS_BUFFER_OVERFLOW&&status!=STATUS_BUFFER_TOO_SMALL)
	{
		return status;
	}
	//读取成功,申请空间,再次读取
	pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, length, 'tag1');
	status = ZwQueryValueKey(hKey, pKeyName, KeyValuePartialInformation, pInfo, length, &length);
	if (!NT_SUCCESS(status))
	{
		return status;
	}
	UNICODE_STRING strInfo;
	RtlInitUnicodeString(&strInfo, pInfo->Data);
	//输出键名称
	KdPrint(("键的值为:%wZ\n", &strInfo));
	ExFreePool(pInfo);
	return status;
}
  • 写入键值
//写入键值
NTSTATUS MyZwSetValueKey(HANDLE hKey,PUNICODE_STRING pKeyName, PUNICODE_STRING pKeyValue)
{
	NTSTATUS status = STATUS_SUCCESS;
	status = ZwSetValueKey(hKey, pKeyName, 0, REG_SZ, pKeyValue->Buffer, pKeyValue->Length);
	return status;
}

高级操作-遍历注册表

  • 使用函数ZwQueryKey ZwEnumerateKey枚举子项
//枚举所有子项
VOID MyZwEnumAllKey(HANDLE hKey)
{
	NTSTATUS status = STATUS_SUCCESS;
	//使用函数ZwQueryKey获取子项数量
	ULONG size = 0;
	ZwQueryKey(hKey,KeyFullInformation, NULL, 0, &size);
	PKEY_FULL_INFORMATION pInfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag2');
	ZwQueryKey(hKey, KeyFullInformation, pInfo, size, &size);
	__try {
		//通过关键字段subKeys进行遍历
		for (ULONG i = 0; i < pInfo->SubKeys; i++)
		{
			//ZwEnumerateKey来枚举子项
			ZwEnumerateKey(hKey, i, KeyBasicInformation, NULL, 0, &size);
			PKEY_BASIC_INFORMATION pBasicInfo = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag3');
			ZwEnumerateKey(hKey, i, KeyBasicInformation, pBasicInfo, size, &size);
			//打印遍历出的信息
			UNICODE_STRING	keyName;
			//不能直接初始化,会产生乱码
			//RtlInitUnicodeString(&keyName, pBasicInfo->Name);
			keyName.Length = keyName.MaximumLength = pBasicInfo->NameLength;
			keyName.Buffer = pBasicInfo->Name;
			KdPrint(("第 %d 项的名称 : %wZ\n", i, &keyName));
			//释放堆空间
			ExFreePool(pBasicInfo);
		}
		ExFreePool(pInfo);
	}
	__except (EXCEPTION_EXECUTE_HANDLER){}
}
  • 使用函数ZwQueryKeyZwEnumerateValueKey枚举子健
//枚举对应项下的所有子健
VOID MyZwEnumAllValueKey(HANDLE hKey)
{
	ULONG size = 0;
	//获得子健的个数
	ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &size);
	if (size<=0)
	{
		return;
	}
	PKEY_FULL_INFORMATION pInfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag4');
	ZwQueryKey(hKey, KeyFullInformation, pInfo, size, &size);
	__try {
		//枚举所有子健
		for (ULONG i = 0; i < pInfo->Values; i++)
		{
			//先获取大小
			ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, NULL, 0, &size);
			PKEY_VALUE_BASIC_INFORMATION pValueInfo = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag5');
			ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, pValueInfo, size, &size);
			//打印信息
			UNICODE_STRING valueKeyName;
			valueKeyName.Length = valueKeyName.MaximumLength = pValueInfo->NameLength;
			valueKeyName.Buffer = pValueInfo->Name;
			KdPrint(("第 %d 个子健名称为: %wZ \n", i, &valueKeyName));
			ExFreePool(pValueInfo);
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {}
	ExFreePool(pInfo);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值