目录编程
在内核中咱们的注册表只有两个 keyapi
内核 | 对应ring3 | |
---|---|---|
\\Registry\\Machine\\software |
HKEY_LOCAL_MACHINE | |
\\Registry\\User\\ |
HKEY_USERS |
其它的三个是从这些内核中映射出来的。数组
重启删除,其实信息是放在注册表中的。网络
以下:
内核:
\Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
函数
对应Ring3
计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
这个key里面有个值是 REG_MULTI_SZ类型,这个类型存储的是多个 \0结尾的路径。code
使用 MoveFileEx(路径,NULL,MOVEFILE_DELAY_UNTIL_REBOOT)这个函数进行重启删除。
参数2不为空,就是替换,为NULL就是删除。 就是移动某个文件到某个目录下,若是某个目录存在就替换。orm
参数3: 参数3是很重要的。若是你替换的时候文件在使用则替换不了。给了这个参数。
那么在重启以后。会给你进行替换。也就是重启删除了。blog
此次重启删除则会放到上面那个注册表中。ip
操做Key的函数内存
API | 做用 | |
---|---|---|
ZwCreateKey | 建立或者打开Key | |
ZwEnumerateKey | 枚举key | |
ZwQueryKey | 查询Key | |
ZwDeleteKey | 删除Key |
操做Valuekey的函数.也就是key下面的值.
API | 做用 | |
---|---|---|
ZwEnumerateValueKey | 枚举Valuekey 值 | |
ZwQueryValueKey | 查询valuekey值 | |
ZwSetValueKey | 设置ValueKey的值 | |
ZwDeleteValueKey | 删除Valuekey的值 |
建立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便可.
删除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; }
查询遍历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; }
结果
上面说的只是建立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; }
代码演示.