64位内核开发第九讲,注册表编程.
作者:互联网
目录
一 注册表编程
二 注册表简介
2.1 ring3注册表
在内核中我们的注册表只有两个 key
内核 | 对应ring3 | |
---|---|---|
\\Registry\\Machine\\software |
HKEY_LOCAL_MACHINE | |
\\Registry\\User\\ |
HKEY_USERS |
其它的三个是从这些内核中映射出来的。
2.2 重启删除原理
重启删除,其实信息是放在注册表中的。
如下:
内核:
\Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
对应Ring3
计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
这个key里面有个值是 REG_MULTI_SZ类型,这个类型存储的是多个 \0结尾的路径。
使用 MoveFileEx(路径,NULL,MOVEFILE_DELAY_UNTIL_REBOOT)这个函数进行重启删除。
参数2不为空,就是替换,为NULL就是删除。 就是移动某个文件到某个目录下,如果某个目录存在就替换。
参数3: 参数3是很重要的。如果你替换的时候文件在使用则替换不了。给了这个参数。
那么在重启之后。会给你进行替换。也就是重启删除了。
这次重启删除则会放到上面那个注册表中。
三丶注册表API操作
3.1 Reg操作API
操作Key的函数
API | 作用 | |
---|---|---|
ZwCreateKey | 创建或者打开Key | |
ZwEnumerateKey | 枚举key | |
ZwQueryKey | 查询Key | |
ZwDeleteKey | 删除Key |
操作Valuekey的函数.也就是key下面的值.
API | 作用 | |
---|---|---|
ZwEnumerateValueKey | 枚举Valuekey 值 | |
ZwQueryValueKey | 查询valuekey值 | |
ZwSetValueKey | 设置ValueKey的值 | |
ZwDeleteValueKey | 删除Valuekey的值 |
四丶注册表操作例子
4.1 ZwCreateKey创建key
创建key需要注意参数. 分别为创建临时key跟创建永久key
读取共享文件夹下的路径.
计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\你共享文件夹的名字
找到文件共享名字.寻找值取出路径进行拼接.
对应内核:
registry\machine\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\你的共享文件夹名
UNC路径 = \\共享网络名字\共享文件夹的名字\xxx文件
代码如下
#include <ntddk.h>
#include <ntstrsafe.h>
DRIVER_UNLOAD DriverUnLoad;
//************************************
// Method: ntIBinaryCreateKey
// FullName: ntIBinaryCreateKey
// Access: public
// Returns: NTSTATUS
// Qualifier: 创建注册表键值
// Parameter: UNICODE_STRING uPathKeyName
//************************************
NTSTATUS ntIBinaryCreateKey(UNICODE_STRING uPathKeyName);
NTSTATUS ntIBinaryInit();
void DriverUnLoad (PDRIVER_OBJECT pDeviceObject)
{
KdPrint(("驱动已卸载"));
}
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT pDriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("驱动加载成功"));
pDriverObject->DriverUnload = DriverUnLoad;
return ntIBinaryInit();
}
NTSTATUS ntIBinaryInit()
{
NTSTATUS status = STATUS_ERROR_PROCESS_NOT_IN_JOB;
UNICODE_STRING uKeyPath;
RtlUnicodeStringInit(&uKeyPath,L"\\registry\\machine\\SoftWare\\IBinary");
status = ntIBinaryCreateKey(uKeyPath);
if (!NT_SUCCESS(status))
{
KdPrint(("创建Key失败"));
return status;
}
return status;
}
NTSTATUS ntIBinaryCreateKey(UNICODE_STRING uPathKeyName)
{
NTSTATUS status = STATUS_ERROR_PROCESS_NOT_IN_JOB;
OBJECT_ATTRIBUTES objAttri;
HANDLE hKeyHandle;
UNICODE_STRING uSubKey;
HANDLE hSubKey;
OBJECT_ATTRIBUTES objSubAttri;
ULONG isRegStatus; //注册表的状态,传出.
InitializeObjectAttributes(
&objAttri,
&uPathKeyName,
OBJ_CASE_INSENSITIVE, //句柄只能内核访问,而且只能一个打开.
NULL, NULL);
status = ZwCreateKey(&hKeyHandle,
KEY_ALL_ACCESS,
&objAttri,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
(PULONG)(&isRegStatus)
);
if (!NT_SUCCESS(status))
{
ZwClose(hKeyHandle);
return status;
}
//创建子Key
RtlUnicodeStringInit(&uSubKey, L"MyReg");
/*
InitializeObjectAttributes(p, n, a, r, s) {
\
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
*/
//InitializeObjectAttributes(&objAttri, &uSubKey, OBJ_CASE_INSENSITIVE, hKeyHandle, NULL);
//不使用宏,手工进行赋值.
objSubAttri.Length = sizeof(OBJECT_ATTRIBUTES);
objSubAttri.Attributes = OBJ_CASE_INSENSITIVE;
objSubAttri.ObjectName = &uSubKey;
objSubAttri.SecurityDescriptor = NULL;
objSubAttri.SecurityQualityOfService = NULL;
objSubAttri.RootDirectory = hKeyHandle; //注意这里.父目录设置为我们上面创建的key
status = ZwCreateKey(&hSubKey, //传出创建的Key
KEY_ALL_ACCESS, //权限
&objSubAttri, //路径
0,
NULL,
REG_OPTION_NON_VOLATILE, //创建的Key重启是否存在还是临时的
&isRegStatus); //保存key的状态,创建成功还是打开
if (!NT_SUCCESS(status))
{
ZwClose(hSubKey);
ZwClose(hKeyHandle);
return status;
}
ZwClose(hSubKey);
ZwClose(hKeyHandle);
KdPrint(("创建Key成功"));
return status;
}
ZwCreateKey 来创建Key. 创建子Key也是用这个函数.只不过你需要在初始化子类的路径的时候.传入父类的Key即可.
2.删除Key
删除Key很简单了.使用 ZwOpenKey打开key ZwDeleteKey删除key
NTSTATUS ntIBinaryDeleteKey(UNICODE_STRING uPathKeyName)
{
NTSTATUS ntStatus;
HANDLE hKey;
OBJECT_ATTRIBUTES ObjAttr;
ULONG isRegStatus;
ObjAttr.Length = sizeof(OBJECT_ATTRIBUTES);
ObjAttr.Attributes = OBJ_CASE_INSENSITIVE;
ObjAttr.ObjectName = &uPathKeyName;
ObjAttr.RootDirectory = NULL;
ObjAttr.SecurityDescriptor = NULL;
ObjAttr.SecurityQualityOfService = NULL;
__try
{
ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);//打开Key在进行删除
if (!NT_SUCCESS(ntStatus))
{
ZwClose(hKey);
return ntStatus;
}
ntStatus = ZwDeleteKey(hKey);
if (!NT_SUCCESS(ntStatus))
{
ZwClose(hKey);
return ntStatus;
}
KdPrint(("删除Key成功"));
}
__except (GetExceptionCode())
{
KdPrint(("删除Key出现异常"));
}
return ntStatus;
}
3.查询遍历Key
查询遍历Key也很简单.
1.使用函数 ZwOpenKey
打开你想遍历的Key
2.两次调用 ZwQueryKey
* ,第一次获取你想遍历Key的缓冲区大小.第二次.获得缓冲区大小了.为这个结构体申请内存.传入这个结构体.继续遍历.关于结构体可以查看MSDN介绍.
3.通过结构体成员.拿到子key数量.建立for循环遍历子key
4.遍历过程中.调用两次 ZwEnumerateKey
第一次调用.
拿到你遍历当前key的基本信息结构体的大小.然后为结构体申请内存.
第二次调用传入结构体.得到当前key的基本信息.这个基本信息是放在这个结构体中.
最后初始化UNICODE_STRING字符串.进行打印即可.
代码:
NTSTATUS ntIBinaryQueryKey(UNICODE_STRING uPathKeyName) //查询Key
{
NTSTATUS ntStatus;
HANDLE hKey;
OBJECT_ATTRIBUTES objAttri = { 0 };
PKEY_FULL_INFORMATION pkfinfo = NULL;
ULONG uSize = 0;
ULONG iteratorValue = 0; //遍历的变量
PKEY_BASIC_INFORMATION pBaseinfo = NULL;
UNICODE_STRING uDbgValue = { 0 };//遍历出来的信息保存到UNICODE_STRING结构体中
//首先打开Key,然后遍历Key
__try
{
InitializeObjectAttributes(
&objAttri,
&uPathKeyName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttri);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
//遍历Key.需要两次调用.第一次调用得出数据大小.第二次调用则是填充数据
ntStatus = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &uSize);
//得出KEY_FUN_INFOMATION 结构的大小.进行内存申请即可.
//查询MSDN得出,ZwQuery当数据不足会返回两个状态.所以判断一下即可.
//STATUS_BUFFER_OVERFLOW或STATUS_BUFFER_TOO_SMALL
if (ntStatus != STATUS_BUFFER_OVERFLOW && ntStatus != STATUS_BUFFER_TOO_SMALL)
{
ZwClose(hKey);
return ntStatus;
}
pkfinfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, uSize, 'niBI');
if (NULL == pkfinfo)
{
ZwClose(hKey);
return ntStatus;
}
//申请了KEY_FULL_INFOMATION结构数组大小.然后进行获取大小
ntStatus = ZwQueryKey(hKey, KeyFullInformation, pkfinfo, uSize, &uSize);
if (!NT_SUCCESS(ntStatus))
{
ExFreePoolWithTag(pkfinfo, 'niBI');
ZwClose(hKey);
return ntStatus;
}
for (iteratorValue = 0; iteratorValue < pkfinfo->SubKeys; iteratorValue++)
{
//遍历出Key就要进行枚举出Key的详细信息.使用ZwEnumerateKey即可.也是枚举一个结构.
ntStatus = ZwEnumerateKey(hKey,
0,
KeyBasicInformation,
NULL,
0,
&uSize);
if (ntStatus != STATUS_BUFFER_OVERFLOW && ntStatus != STATUS_BUFFER_TOO_SMALL)
{
ZwClose(hKey);
return ntStatus;
}
pBaseinfo = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(PagedPool, uSize, 'niBI');
if (NULL == pkfinfo)
{
ZwClose(hKey);
return ntStatus;
}
//继续申请一次得出需要的
ntStatus = ZwEnumerateKey(hKey,
0,
KeyBasicInformation,
pBaseinfo,
uSize,
&uSize);
if (!NT_SUCCESS(ntStatus))
{
if (NULL != pBaseinfo)
ExFreePoolWithTag(pBaseinfo, 'niBI');
if (NULL != pkfinfo)
ExFreePoolWithTag(pkfinfo, 'niBI');
ZwClose(hKey);
return ntStatus;
}
//得出信息则可以进行进一步操作了.
//初始化UNICODE结构.进行打印输出即可.
uDbgValue.Length = (USHORT)pBaseinfo->NameLength;
uDbgValue.MaximumLength = (USHORT)pBaseinfo->NameLength;
uDbgValue.Buffer = pBaseinfo->Name;
KdPrint(("得出的key 名字 = %wZ", &uDbgValue));
ExFreePool(pBaseinfo); //同上释放内存
}
//释放资源
if (NULL != pkfinfo)
ExFreePool(pkfinfo);
ZwClose(hKey);
}
__except (GetExceptionCode())
{
KdPrint(("出现异常,异常代码为: %ld", GetExceptionCode()));
}
return ntStatus;
}
结果
4.创建并且设置Value的值.
上面说的只是创建key.下面则是怎么设置对应的Value
代码也很简单.
原理如下下:
1.打开Key
2.使用函数 ZwSetValueKey
创建并且设置Value即可.
代码如下
NTSTATUS ntIBinarySetKeyValue(UNICODE_STRING uPathKeyName)
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES objAttri;
HANDLE hKey;
UNICODE_STRING uSetValueKeyName;
ULONG Value = 10;
InitializeObjectAttributes(&objAttri,
&uPathKeyName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttri);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
//设置KEY value的值
RtlUnicodeStringInit(&uSetValueKeyName, L"IBinaryFrist");
ntStatus = ZwSetValueKey(hKey,
&uSetValueKeyName,
0,
REG_DWORD,
&Value,
sizeof(ULONG));
if (!NT_SUCCESS(ntStatus))
{
ZwClose(hKey);
return ntStatus;
}
KdPrint(("设置Key成功"));
ZwClose(hKey);
return ntStatus;
}
代码演示.
标签:return,key,hKey,ntStatus,内核,Key,注册表,64,NULL 来源: https://www.cnblogs.com/iBinary/p/10990686.html