内核下的注册表操作

注册表的相关概念

在这里插入图片描述

创建关闭注册表
ZwCreateKey

NTSYSAPI NTSTATUS ZwCreateKey(
  PHANDLE            KeyHandle,		//获得的注册表句柄
  ACCESS_MASK        DesiredAccess,	//访问权限,一般设置为KEY_ALL_ACCESS
  POBJECT_ATTRIBUTES ObjectAttributes,	//OBJECT_ATTRIBUTES数据结构指针
  ULONG              TitleIndex,	//很少用到,一般设置为0
  PUNICODE_STRING    Class,		//很少用到一般设置为NULL
  ULONG              CreateOptions,	//创建时的选项,
  PULONG             Disposition	//返回是创建成功,还是打开成功,返回值是REG_CREATED_NEW_KEY 就表明是创建了一个KEY Key  如果返回值是REG_OPENED_EXISTING_KEY,表明是打开一个已经存在的KEY

);

创建或者打开一个特定的注册表表项

#include <ntddk.h>

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("驱动卸载成功");
}

#define  MY_REG_SOFTWARE_KEY_NAME		L"\\Registry\\Machine\\Software\\Zhangfan"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
	//在C盘创建一个文件
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objAttr = { 0 };
	UNICODE_STRING RegPath;

	NTSTATUS status = 0;
	
	

	pDriverObject->DriverUnload = DriverUnload;

	RtlInitUnicodeString(&RegPath, MY_REG_SOFTWARE_KEY_NAME);
	//初始化对象属性 主要提供了一个要打开的文件名
	InitializeObjectAttributes(&objAttr,
							   &RegPath, 
							   OBJ_CASE_INSENSITIVE,	//比较对象名时不区分大小写
							   0,
							   0);
	
	ULONG IsCreate = 0;
	HANDLE hKey;
	status=ZwCreateKey(&hKey,
				KEY_ALL_ACCESS,
				&objAttr,
				0,
				0,
				REG_OPTION_NON_VOLATILE,  //系统重启后会保存这个KEY
				&IsCreate   
				);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("注册表创建表项失败\n");

		return status;
	}
	//判断是新建的注册表键 还是打开的注册表键
	if (IsCreate == REG_CREATED_NEW_KEY)
	{
		DbgPrint("新建了一个注册表表项\n");
	}
	else if (IsCreate==REG_OPENED_EXISTING_KEY)
	{
		DbgPrint("打开了一个注册表表项\n");
	}


	ZwClose(hKey);
	return STATUS_SUCCESS;
}

打开注册表

ZwCreateKey函数既可以创建注册表项,也可以打开注册表项。
为了简化打开的操作DKK提供了内核函数ZwOpenKey,如果ZwOpenKey指定的项不存在,不会创建这个项目,而是返回一个错误装啊提。

NTSYSAPI NTSTATUS ZwOpenKey(
  PHANDLE            KeyHandle,	//返回被打开的句柄
  ACCESS_MASK        DesiredAccess,	//打开的权限,一般设置为KEY_ALL_ACCESS
  POBJECT_ATTRIBUTES ObjectAttributes	//OBJECT_ATTRIBUTES数据结构,指示打开的状态。
);

添加,修改注册表键值

											键值的分类
分类描述
REG_BINARY键值用二进制存储
REG_SZ键值用宽字符串,字符串以\0结尾
REG_EXPAND_SZ键值用宽字符串,字符串以\0结尾,该字符串是扩展的字符
REG_MULTI_SZ键值存储多个字符串,每个字符串以\0结尾
REG_DWORD键值用4字节整形存储
REG_QWORD键值用8字节存储

通过函数ZwSetValueKey来修改注册表的键值。

NTSYSAPI NTSTATUS ZwSetValueKey(
  HANDLE          KeyHandle,  //注册表句柄
  PUNICODE_STRING ValueName,	//要新建或者修改的键名
  ULONG           TitleIndex,	//很少用,一般设置为0
  ULONG           Type,			//键值的类型
  PVOID           Data,			
  ULONG           DataSize		//记录键值数据的大小
);

使用ZwSetValueKey函数的时候,如果指定的键名不存在,则直接创建。如果指定键名已经存在,则对已有键值进行修改。当新建或者修改键值的时候,根据键值不同的类
别,Data指向不同的数据结构,并且用DataSize指明数据大小。例如,REG DWORD类
型,对应的数据大小就是4, REG_ QWORD数据类型,数据大小就是8,如果是REG_ SZ,
数据长度是字符串长度的:二倍加上两个字节。下面的代码演示了如何修改和设置键值。

#include <ntddk.h>

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("驱动卸载成功");
}

#define  MY_REG_SOFTWARE_KEY_NAME		L"\\Registry\\Machine\\Software\\Zhangfan"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
	//在C盘创建一个文件
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objAttr = { 0 };
	UNICODE_STRING RegPath;
	NTSTATUS status = 0;
	pDriverObject->DriverUnload = DriverUnload;

	RtlInitUnicodeString(&RegPath, MY_REG_SOFTWARE_KEY_NAME);
	//初始化对象属性 主要提供了一个要打开的文件名
	InitializeObjectAttributes(&objAttr,
							   &RegPath, 
							   OBJ_CASE_INSENSITIVE,	//比较对象名时不区分大小写
							   0,
							   0);
	
	ULONG IsCreate = 0;
	HANDLE hKey;
	status = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttr);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("打开注册表项失败\n");

		return status;
	}
	else
	{
		DbgPrint("打开注册表项成功\n");
	}
	UNICODE_STRING KeyName;
	RtlInitUnicodeString(&KeyName,L"UserName");

	//创建或者修改键值  REG_SZ类型为宽字符串 所以参数5 data要使用宽字符,长度为字符*2+2
	ZwSetValueKey(hKey, &KeyName, 0, REG_SZ, L"dale", 10);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("设置键值失败\n");
		ZwClose(hKey);
		return status;
	}
	else
	{
		DbgPrint("设置键值成功\n");
	}
	ZwClose(hKey);
	return STATUS_SUCCESS;
}

查询注册表

驱动程序中有时需要对注册表的项进行查询,从而获取注册表的键值。DDK提供的
ZwQueryValueKey函数可以完成这个任务,其声明如下:

NTSYSAPI NTSTATUS ZwQueryValueKey(
  HANDLE                      KeyHandle, //打开的注册表句柄
  PUNICODE_STRING             ValueName, //要查询的键名	
  KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,	//根据KeyValueInformation的不同选择不同的查询类别
  PVOID                       KeyValueInformation,//选择一种查询类别KeyValueBasicInformation、KeyValueFul]Information或KeyValuePartialInformation。

  ULONG                       Length,//要查数据的长度
  PULONG                      ResultLength//实际查询数据的长度
);

使用ZwQueryValueKey函数查询注册表时,需要用Key ValuefnformationClass选择
一种 查询方式。这可以是KeyValueBasicInformation、KeyValueFulInformation或者KeyValue
ParialInformation中的一种。 这分别代表查询基本信息,查询全部信息和查询部分信息,
每种查询类型会有对应的一-种数据结构获得查询结果。
一般情况下, 选择KeyValueParialInformation就可以查询键值的数据了,它对应的查
询数据结构是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分为4个步骤。
➊用ZwQueryValueKey获取这个数据结构的长度。
❷分配如此长度的内存,用来查询。
❸再次调用ZwQueryValueKey,获取键值。
❹回收内存。

#include <ntddk.h>

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("驱动卸载成功");
}

#define  MY_REG_SOFTWARE_KEY_NAME		L"\\Registry\\Machine\\Software\\Zhangfan"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
	//在C盘创建一个文件
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objAttr = { 0 };
	UNICODE_STRING RegPath;
	NTSTATUS status = 0;
	pDriverObject->DriverUnload = DriverUnload;

	RtlInitUnicodeString(&RegPath, MY_REG_SOFTWARE_KEY_NAME);
	//初始化对象属性 主要提供了一个要打开的文件名
	InitializeObjectAttributes(&objAttr,
							   &RegPath, 
							   OBJ_CASE_INSENSITIVE,	//比较对象名时不区分大小写
							   0,
							   0);
	
	ULONG IsCreate = 0;
	HANDLE hKey;
	status = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttr);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("打开注册表项失败\n");

		return status;
	}
	else
	{
		DbgPrint("打开注册表项成功\n");
	}

	UNICODE_STRING KeyName;
	ULONG RetSize=0;
	RtlInitUnicodeString(&KeyName,L"UserName");

	//第一次调用ZwQueryValueKey  来获取KeyValuePartialInformation类型的大小 然后分配一个buffer
	status=ZwQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, NULL, 0, &RetSize);
	//运行正确这个函数返回的是STATUS_BUFFER_TOO_SMALL  不能使用NT_SUCCESS来判断
	if (status == STATUS_OBJECT_NAME_NOT_FOUND | status == STATUS_INVALID_PARAMETER | RetSize==0)
	{
		DbgPrint("查询键值类型失败");
		ZwClose(hKey);
		return status;
	}
	
	//分配一块内存来接收返回的信息
	PKEY_VALUE_PARTIAL_INFORMATION pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, RetSize);
	if (!pvpi)
	{
		DbgPrint("内存分配失败");
		ZwClose(hKey);
		return status;
	}
	//查询信息,类型为PKEY_VALUE_PARTIAL_INFORMATION
	status = ZwQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, pvpi, RetSize, &RetSize);

	if (!NT_SUCCESS(status))
	{
		DbgPrint("查询键值失败\n");

		return status;
	}
	else
	{
		switch (pvpi->Type)
		{
			
		case REG_SZ:
			DbgPrint("查找的键的类型是:-- REG_SZ  -- \n");
			DbgPrint("查找的键的键值是%S\n",pvpi->Data);

			break;
		case REG_EXPAND_SZ:
			DbgPrint("查找的键的类型是:-- REG_EXPAND_SZ  -- \n");
			break;
		case REG_BINARY:
			DbgPrint("查找的键的类型是:-- REG_BINARY  -- \n");
			break;
		case REG_DWORD:
			DbgPrint("查找的键的类型是:-- REG_DWORD  -- \n");
			break;
		case REG_QWORD:
			DbgPrint("查找的键的类型是:-- REG_QWORD  -- \n");
			break;
		default:
			DbgPrint("未解析的键值类型 -- \n");
			break;
		}
		
	}
	
	ZwClose(hKey);
	return STATUS_SUCCESS;
}

枚举子项

可以通过函数ZwQueryKey 和ZwEnumerateKey函数来枚举子项。

NTSYSAPI NTSTATUS ZwQueryKey(
  HANDLE                KeyHandle,	//注册表项的句柄
  KEY_INFORMATION_CLASS KeyInformationClass, //查询的类别,一般选择KeyFullInformation
  PVOID                 KeyInformation,	//查询的数据指针,如果KeyInformationClass是KeyFullInformation,则该指针指向一个KEY_FULL_INFORMATION的数据结构.
  ULONG                 Length,//数据长度
  PULONG                ResultLength//返回的数据长度
);
NTSYSAPI NTSTATUS ZwEnumerateKey(
  HANDLE                KeyHandle,//注册表项的句柄
  ULONG                 Index,//很少用到,一般为0
  KEY_INFORMATION_CLASS KeyInformationClass,//该子项的信息
  PVOID                 KeyInformation,
  ULONG                 Length,//子项信息的长度
  PULONG                ResultLength //返回子健信息的长度
);
ZwQueryKey的作用主要是获得某注册表项究竟有多少个子项,而ZwEnumerateKey
的作用主要是针对第几个子项获取该子项的具体信息。

在使用ZwQueryKey时,可以将参数KeyInformationClass指定为KeyFullInformation。
这样参数KeyInformation就对应-一个 KEY_FULL_INFORMATION的数据结构,该数据结
构中的SubKeys指明了项中有多少个子项。

KEY_ FULL._JINFORMATION数据结构的大小是变长的,所以要调用两次
ZwQueryKey。第一次获取KEY_ FULL_INFORMATION数据的长度,第二次真正获取
KEY_ FULL_ JINFORMATION数据。

在使用ZwEnumerateKey 时,需要将参数KeyInformationClass 设置为KeyBasic
Information,这样其参数KeyInformation就能对应KEY_ BASIC _INFORMATION的数据结构。
同理,KEY_ _BASIC _INFORMATION也是变长的数据结构,需要两次调用ZwEnumerate
Key。第一次获取KEY_ BASIC _INFORMATION的长度,第二次获取KEY_ BASIC_
INFORMATION数据。

枚举指定项的子项代码

//枚举指定键下的所有子键
NTSTATUS EnumerateKey(PWCHAR RegKeyPath)
{
	PKEY_FULL_INFORMATION pfi = NULL;
	OBJECT_ATTRIBUTES ObjAttr = { 0 };
	UNICODE_STRING RegPath = {0};
	NTSTATUS Status = STATUS_UNSUCCESSFUL;
	
	RtlInitUnicodeString(&RegPath, RegKeyPath);
	//初始化对象属性 主要提供了一个要打开的文件名
	InitializeObjectAttributes(&ObjAttr,
		&RegPath,
		OBJ_CASE_INSENSITIVE,	//比较对象名时不区分大小写
		0,
		0);

	HANDLE KeyHandle=NULL;
	do
	{
		Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjAttr);
		if (!NT_SUCCESS(Status))
		{
			DbgPrint("打开注册表项失败\n");
			break;
		}
		
		UNICODE_STRING KeyName;
		ULONG RetSize = -1;

		//通过ZwQueryKey来获得KEY_FULL_INFORMATION数据的长度
		Status = ZwQueryKey(KeyHandle, KeyFullInformation, NULL, 0, &RetSize);
		if (RetSize == -1)
		{
			break;
		}
		pfi = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, RetSize,'key');
		if (!pfi)
		{
			break;
		}
		RtlZeroMemory(pfi, RetSize);
		//获得KEY_FULL_INFORMATION数据 
		Status = ZwQueryKey(KeyHandle, KeyFullInformation, pfi, RetSize, &RetSize);

		if (!NT_SUCCESS(Status))
		{
			break;
		}
		
		DbgPrint("子项个数是:%x\n", pfi->SubKeys);

		for (ULONG i = 0; i < pfi->SubKeys; i++)
		{
			PKEY_BASIC_INFORMATION pbi = NULL;
			//获得KEY_BASIC_INFORMATION结构的大小
			RetSize = -1;
			ZwEnumerateKey(KeyHandle, i, KeyBasicInformation, 0, 0, &RetSize);
			if (RetSize == -1)
			{
				break;
			}
			pbi = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(PagedPool, RetSize,'key');
			if (!pbi)
			{
				continue;
			}
			RtlZeroMemory(pbi, RetSize);
			//获取KEY_BASIC_INFORMATION数据
			Status = ZwEnumerateKey(KeyHandle, i, KeyBasicInformation, pbi, RetSize, &RetSize);
			if (!NT_SUCCESS(Status))
			{
				break;
			}

			//因为KEY_BASIC_INFORMATION这个结构是变长的,最后一个成员Name并不是以\0结尾的,所以只能把它转化成UNICODE来输出
			UNICODE_STRING SubKeyName;
			SubKeyName.Length = SubKeyName.MaximumLength = (USHORT)pbi->NameLength;
			SubKeyName.Buffer = pbi->Name;
			DbgPrint("子项名是:%wZ\n", &SubKeyName);

			WCHAR FullPath[260] = { 0 };
			WCHAR KeyName[260] = { 0 };
			wcscpy_s(FullPath,260,RegKeyPath);
			wcscat_s(FullPath, 260, L"\\");
			memcpy_s(KeyName,260, pbi->Name, pbi->NameLength);
			wcscat_s(FullPath, 260, KeyName);

			DbgPrint("全路径:%S\n", FullPath);
			EnumerateValueKey(FullPath);
			//释放掉申请的内存
			ExFreePool(pbi);

		}
	} while (FALSE);
	
	if (pfi)
	{
		ExFreePool(pfi);
		pfi = NULL;
	}
	if (KeyHandle)
	{
		ZwClose(KeyHandle);
		KeyHandle = NULL;
	}
	
	return Status;
}

枚举指定项下所有键值

//枚举指定键下的所有键名和键值
NTSTATUS EnumerateValueKey(PWCHAR RegKeyPath)
{
	NTSTATUS Status = STATUS_SUCCESS;
	PKEY_FULL_INFORMATION pkfi = NULL;
	ULONG ulLength = 0;

	OBJECT_ATTRIBUTES ObjAttr = { 0 };
	UNICODE_STRING RegPath;

	RtlInitUnicodeString(&RegPath, RegKeyPath);
	//初始化对象属性 主要提供了一个要打开的文件名
	InitializeObjectAttributes(&ObjAttr,
		&RegPath,
		OBJ_CASE_INSENSITIVE,	//比较对象名时不区分大小写
		0,
		0);

	HANDLE KeyHandle=NULL;
	do
	{
		Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjAttr);
		if (!NT_SUCCESS(Status))
		{
			DbgPrint("yxp 打开注册表项失败,0x%x\n", Status);
			break;
		}

		// 获取ValueKey个数
		Status = ZwQueryKey(KeyHandle, KeyFullInformation, pkfi, 0, &ulLength);
		// allocate key information buffer
		pkfi = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, ulLength, 'key');
		if (pkfi == NULL)
		{
			DbgPrint("yxp ZwQueryKey ExAllocatePoolWithTag failed %x\n", Status);
			break;
		}
		RtlZeroMemory(pkfi, ulLength);
		Status = ZwQueryKey(KeyHandle, KeyFullInformation, pkfi, ulLength, &ulLength);
		if (!NT_SUCCESS(Status))
		{
			DbgPrint("yxp ZwQueryKey 2 failed %x\n", Status);
			break;
		}
		// enumerater value key
		for (ULONG i = 0; i < pkfi->Values; i++)
		{
			PKEY_VALUE_FULL_INFORMATION pkvfi = NULL;
			Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation, pkvfi, 0, &ulLength);
			// allcate enumerate buffer
			pkvfi = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, ulLength, 'key');
			if (pkvfi == NULL)
			{
				DbgPrint("yxp ZwEnumerateKey ExAllocatePoolWithTag failed %x\n", Status);
				continue;
			}
			RtlZeroMemory(pkvfi, ulLength);
			Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation, pkvfi, ulLength, &ulLength);
			if (!NT_SUCCESS(Status))
			{
				DbgPrint("yxp ZwEnumerateKey failed %x\n", Status);
				ExFreePool(pkvfi);
				break;
			}
			// show value name
			UNICODE_STRING uValueKey = { 0 };
			UNICODE_STRING uValueData = { 0 };
			// value key
			uValueKey.Length = uValueKey.MaximumLength = (USHORT)pkvfi->NameLength;
			uValueKey.Buffer = pkvfi->Name;
			// value data
			uValueData.Length = uValueData.MaximumLength = (USHORT)pkvfi->DataLength;
			uValueData.Buffer = (PWCH)((PCH)pkvfi + pkvfi->DataOffset);

			if (pkvfi->Type == REG_SZ)
			{
				DbgPrint("yxp  ValueKey : %wZ  ValueData : %wZ\n", &uValueKey, &uValueData);
			}
			else
			{
				DbgPrint("yxp  ValueKey : %wZ  ValueData : %x\n", &uValueKey, *(PULONG)uValueData.Buffer);
			}

			ExFreePool(pkvfi);
		}
	} while (FALSE);
	
	if (pkfi != NULL)
	{
		ExFreePool(pkfi);
		pkfi = NULL;
	}
		
	if (KeyHandle)
	{
		ZwClose(KeyHandle);
		KeyHandle = NULL;
	}
	return Status;
}

删除子项

NTSTATUS
ZwDeleteKey (
IN HANDLE KeyHandle
);

需要指出,该函数只能删除没有子项的项目。如果项中还有子项,则不能删除。这时
候需要先将该项中的所有子项全部删除后,再删除该项。下 面的例子演示了如何在驱动程
序中删除子项。

简化的注册表操作

以上的注册表操作都非常繁琐,DDK提供了一些更加简化的操作函数、

分类描述
RtlCreateRegistryKey创建注册表
RtlCheckRegistryKey查看某注册表项是否存在
RtlWriteRegistryKey写注册表
RtlDeleteRegistryKey删除注册表的子键
#include <ntddk.h>

#define  MY_REG_SOFTWARE_KEY_NAME		L"DaleReg1013"
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("驱动卸载成功");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{
	
	DbgPrint("加载路径:%S\n", pRegPath->Buffer);
	pDriverObject->DriverUnload = DriverUnload;

	//判断指定注册表项存不存在  不存在就创建该项
	NTSTATUS	status = RtlCheckRegistryKey(RTL_REGISTRY_SERVICES, MY_REG_SOFTWARE_KEY_NAME);
	if (status == STATUS_SUCCESS)
	{
		DbgPrint("注册表项%S已存在\n", MY_REG_SOFTWARE_KEY_NAME);
	}
	else
	{
		//创建注册表项    RTL_REGISTRY_SERVICES 就指定要创建的注册表项的路径是  \Registry\Machine\System\CurrentControlSet\Services
		status = RtlCreateRegistryKey(RTL_REGISTRY_SERVICES, MY_REG_SOFTWARE_KEY_NAME);
	}

	
	if (!NT_SUCCESS(status))
	{
		DbgPrint("创建注册表项失败\n");
		return status;
	}
	else
	{
		DbgPrint("创建注册表项成功\n");
		
	}
	//判断指定注册表项存不存在 已经创建 肯定存在

	
	status=RtlWriteRegistryValue(RTL_REGISTRY_SERVICES, MY_REG_SOFTWARE_KEY_NAME,L"USERNAME",REG_SZ,L"dale",10);
	if (!NT_SUCCESS(status))
	{
		
		DbgPrint("新建注册表键失败\n");
		return status;

	}
	else
	{
		DbgPrint("新建注册表键成功\n");
	}
	ULONG a = 100;
	//再次调用 就可以修改指定键名的键值
	status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES, MY_REG_SOFTWARE_KEY_NAME, L"USERNAME", REG_DWORD,&a, 4);
	if (!NT_SUCCESS(status))
	{

		DbgPrint("修改注册表键值失败\n");
		return status;

	}
	else
	{
		DbgPrint("修改注册表键值成功\n");
	}

	//删除注册表的子键
	RtlDeleteRegistryValue(RTL_REGISTRY_SERVICES, MY_REG_SOFTWARE_KEY_NAME, L"USERNAME");
	if (!NT_SUCCESS(status))
	{

		DbgPrint("删除指定子键失败\n");
		return status;

	}
	else
	{
		DbgPrint("删除指定子键成功\n");
	}
	return STATUS_SUCCESS;
}


多字符串类型

REG_MULTI_SZ类型
在注册表中多字符串成对成对的解析,第一个为源文件路径,第二个就是目标文件路径,如果目标文件路径为空 就是删除源文件例如:以下的多字符串
c:\1.txt
d:\dale\1.txt //有这个值就表明是系统重启后移动文件
c:\2.txt
//没有值说明是系统重启后删除源文件
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值