打开注册表的句柄后,就可以对该项进行设置和修改了。注册表是以二元形式存储的,即“键名”和“键值”。通过键名设置键值,而键值可以划分几个类,如下表所示。
表1 键值的分类
在添加和修改注册表键值的时候,要分类进行添加和修改,DDK提供了 ZwSetValueKey 函数来完成这个任务,其函数声明是:
NTSTATUS ZwSetValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName,
IN ULONG TitleIndex,
IN ULONG Type,
IN PVOID Data,
IN ULONG DataSize
);
// KeyHandle: 注册表句柄
// ValueName:要新建或者修改的键名
// TitleIndex: 很少用,一般设为0
// Type: 在表1中选择一种类型
// Data: 记录键值数据
// DataSize: 记录键值数据的大小
// 返回值: 返回新建或者修改的结果
使用 ZwSetValueKey 函数的时候,如果指定的键名不存在,则直接创建,如果指定键名已经存在。则对已有键值进行修改。当新建或者修改键值的时候,根据表1不同的类别,Data指向不同的数据结构,并且用DataSize指明数据大小。例如,REG_DWORD类型,对应的数据大小就是4,REG_QWORD数据类型,数据大小就是8,如果是REG_SZ,数据长度是字符串长度的二倍加上两个字节。下面的代码演示了如何修改和设置键值。
UNICODE_STRING RegUnicodeStr;
HANDLE hRegister;
// 初始化 UNICODE_STRING 字符串
RtlInitUnicodeString(&RegUnicodeStr,
MY_REG_SOFTWARE_KEY_NAME);
OBJECT_ATTRIBUTES objectAttributes;
// 初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeStr,
OBJ_CASE_INSENSITIVE, // 对大小写敏感
NULL,
NULL
);
// 打开注册表项
NTSTATUS ntStatus = ZwOpenKey(&hRegister,
KEY_ALL_ACCESS,
&objectAttributes);
// 判断操作是否成功
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully. \n"));
}
UNICODE_STRING ValueName;
// 初始化 ValueName
RtlInitUnicodeString(&ValueName,
L"REG_DWORD value");
// 设置 REG_DWORD 子健
ULONG ulValue = 1000;
ZwSetValueKey(hRegister,
&ValueName,
0,
REG_DWORD,
&ulValue,
sizeof(ulValue));
// 初始化 ValueName
RtlInitUnicodeString(&ValueName, L"REG_SZ value");
WCHAR* strValue = L"Hello world";
// 设置 REG_SZ 子健
ZwSetValueKey(hRegister,
&ValueName,
0,
REG_SZ,
strValue,
wcslen(strValue) * 2 + 2
);
// 初始化 ValueName
RtlInitUnicodeString(&ValueName, L"REG_BINARY value");
UCHAR buffer[10];
RtlFillMemory(buffer, sizeof(buffer), 0xFF);
// 设置REG_MULTI_SZ 子健
ZwSetValueKey(hRegister,
&ValueName,
0,
REG_BINARY,
buffer,
sizeof(buffer)
);
// 关闭句柄
ZwClose(hRegister);