一 概述

RING0 操作注册表和 RING3 的区别也不大,同样是“获得句柄->执行操作->关闭句柄”的模式,同样也只能使用内核 API 不能使用 WIN32API。不过内核里有一套 RTL 函数,把 Zw系列的注册表函数进行了封装。

接下来说说注册表的本质。注册表其实是文件,它存储在 c:\windows\system32\config
这个目录下(打开目录,看到那几个带锁图标的文件就是。为什么带锁?因为被 SYSTEM 进
程独占访问了)。注册表文件被称为 HIVE 文件,此格式是微软专用的,不公开,每个系统都不一定相同,但总体来说变化不大。当系统关机之前,或者调用 ZwFlushKey 时,把内存中的修改存入磁盘。另外,我们用 WINDOWS 自带的注册表编辑器看到的注册表有 5 个根项,其实 这 是 “ 幻 象 ”, 真 正 的 根 项 只 有 两 个 : HKEY_LOCAL_MACHINE 和 HKEY_USERS 。HKEY_CLASSES_ROOT 和 HKEY_CURRENT_CONFIG 其实都是 HKEY_LOCAL_MACHINE 的“下属”。
HKEY_CURRENT_USER 则是 HKEY_USERS 的“下属”,独立列出来只为了方便操作。

关于注册表的操作不多,无非就是:新建 KEY、重命名 KEY、删除 KEY、新建/设置 VALUE、读取 VALUE、删除 VALUE、枚举子 KEY 和 VALUE。

几个常见的、和注册表相关的Zw函数的功能:

二 示例代码

1.新建 KEY

void RegCreateKey(LPWSTR KeyName)
{
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING usKeyName;
NTSTATUS ntStatus;
HANDLE hRegister;
RtlInitUnicodeString(&usKeyName, KeyName);
InitializeObjectAttributes(&objectAttributes,
&usKeyName,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
ZwCreateKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes, 0, NULL,
REG_OPTION_NON_VOLATILE, NULL);
ZwClose(hRegister);
}

2.重命名 KEY(不建议用,如果可以的话最好是 删除然后创建)
(这里用到的关键 API『ZwRenameKey』没有导出,需要自己定位,大家可以先
用硬编码测试。在 WINDNG 里输入 x nt!ZwRenameKey 即可获得函数地址)

typedef NTSTATUS(__fastcall *ZWRENAMEKEY)(IN HANDLE KeyHandle,IN PUNICODE_STRING ReplacementName);
//修改这个地址!!
ZWRENAMEKEY ZwRenameKey = 0xFFFFF80012345678;
void RegRenameKey(UNICODE_STRING usOldKeyName, UNICODE_STRING usNewKeyName)
{
OBJECT_ATTRIBUTES objectAttributes;
HANDLE hRegister;
NTSTATUS ntStatus;
InitializeObjectAttributes(&objectAttributes,
&usOldKeyName,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
if (NT_SUCCESS(ntStatus))
{
ntStatus = ZwRenameKey(hRegister, &usNewKeyName);
ZwFlushKey(hRegister);
ZwClose(hRegister);
}
}

3.删除 KEY

void RegDeleteKey(LPWSTR KeyName)
{
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING usKeyName;
NTSTATUS ntStatus;
HANDLE hRegister;
RtlInitUnicodeString(&usKeyName, KeyName);
InitializeObjectAttributes(&objectAttributes,
&usKeyName,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
if (NT_SUCCESS(ntStatus))
{
ntStatus = ZwDeleteKey(hRegister);
ZwClose(hRegister);
}}

4.新建/设置 VALUE

void RegSetValueKey(LPWSTR REG_KEY_NAME, LPWSTR REG_VALUE_NAME, DWORD
DataType, PVOID DataBuffer, DWORD DataLength)
{
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING usKeyName, usValueName;
NTSTATUS ntStatus;
HANDLE hRegister;
ULONG Type;
RtlInitUnicodeString(&usKeyName, REG_KEY_NAME);
RtlInitUnicodeString(&usValueName, REG_VALUE_NAME);
InitializeObjectAttributes(&objectAttributes,
&usKeyName,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
if (NT_SUCCESS(ntStatus))
{
ntStatus = ZwSetValueKey(hRegister, &usValueName, 0, DataType,
DataBuffer, DataLength);
ZwFlushKey(hRegister);
ZwClose(hRegister);
}
}

5.读取 VALUE

typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG DataLength;
UCHAR Data[1];
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
NTSTATUS RegQueryValue(UNICODE_STRING usKeyName, PUNICODE_STRING pValueName,
PKEY_VALUE_PARTIAL_INFORMATION *pkvpi)
{
ULONG ulSize;
NTSTATUS ntStatus;
PKEY_VALUE_PARTIAL_INFORMATION pvpi;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE hRegister;
InitializeObjectAttributes(&objectAttributes,
&usKeyName,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
if (!ntStatus)
{
return ntStatus;
}
ntStatus = ZwQueryValueKey(hRegister,
pValueName,
KeyValuePartialInformation,
NULL,
0,
&ulSize);
if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0)
{
return STATUS_UNSUCCESSFUL;
}
pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
ntStatus = ZwQueryValueKey(hRegister,
pValueName,
KeyValuePartialInformation,
pvpi,
ulSize,
&ulSize);
if (!NT_SUCCESS(ntStatus))
{
return STATUS_UNSUCCESSFUL;
}
*pkvpi = pvpi;  //这里的 pvpi 是没有释放的,用完要释放 ExFreePool(pvpi);
return STATUS_SUCCESS;
}

6.删除 VALUE

void RegDeleteValueKey(LPWSTR REG_KEY_NAME, LPWSTR REG_VALUE_NAME)
{
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING usKeyName, usValueName;
NTSTATUS ntStatus;
HANDLE hRegister;
RtlInitUnicodeString(&usKeyName, REG_KEY_NAME);
RtlInitUnicodeString(&usValueName, REG_VALUE_NAME);
InitializeObjectAttributes(&objectAttributes,
&usKeyName,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
if (NT_SUCCESS(ntStatus))
{
ntStatus = ZwDeleteValueKey(hRegister, &usValueName);
ZwFlushKey(hRegister);
ZwClose(hRegister);
}
}

7.枚举子 KEY

VOID EnumerateSubItemRegTest()
{
#define  MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\xxxxxxxx"
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;
//初始化 UNICODE_STRING 字符串
RtlInitUnicodeString(&RegUnicodeString, MY_REG_SOFTWARE_KEY_NAME);
OBJECT_ATTRIBUTES objectAttributes;
//初始化 objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
//打开注册表
NTSTATUS ntStatus = ZwOpenKey(&hRegister,
KEY_ALL_ACCESS,
&objectAttributes);
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully\n"));
}
ULONG ulSize;
//第一次调用 ZwQueryKey 为了获取 KEY_FULL_INFORMATION 数据的长度
ZwQueryKey(hRegister,
KeyFullInformation,
NULL,
0,
&ulSize);
PKEY_FULL_INFORMATION pfi =
(PKEY_FULL_INFORMATION)
ExAllocatePool(PagedPool, ulSize);
//第二次调用 ZwQueryKey 为了获取 KEY_FULL_INFORMATION 数据的数据
ZwQueryKey(hRegister,
KeyFullInformation,
pfi,
ulSize,
&ulSize);
for (ULONG i = 0; i<pfi->SubKeys; i++)
{
//第一次调用 ZwEnumerateKey 为了获取 KEY_BASIC_INFORMATION 数据的长度
ZwEnumerateKey(hRegister,
i,
KeyBasicInformation,
NULL,
0,
&ulSize);
PKEY_BASIC_INFORMATION pbi =
(PKEY_BASIC_INFORMATION)
ExAllocatePool(PagedPool, ulSize);
//第二次调用 ZwEnumerateKey 为了获取 KEY_BASIC_INFORMATION 数据的数据
ZwEnumerateKey(hRegister,
i,
KeyBasicInformation,
pbi,
ulSize,
&ulSize);
UNICODE_STRING uniKeyName;
uniKeyName.Length =
uniKeyName.MaximumLength =
(USHORT)pbi->NameLength;
uniKeyName.Buffer = pbi->Name;
KdPrint(("The %d sub item name:%wZ\n", i, &uniKeyName));
ExFreePool(pbi);
}
ExFreePool(pfi);
ZwClose(hRegister);
}

8.枚举子 VALUE

VOID EnumerateSubValueRegTest()
{
#define  MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\xxxxxxxx"
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;
//初始化 UNICODE_STRING 字符串
RtlInitUnicodeString(&RegUnicodeString, MY_REG_SOFTWARE_KEY_NAME);
OBJECT_ATTRIBUTES objectAttributes;
//初始化 objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,//对大小写敏感
NULL,
NULL);
//打开注册表
NTSTATUS ntStatus = ZwOpenKey(&hRegister,
KEY_ALL_ACCESS,
&objectAttributes);
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully\n"));
}
ULONG ulSize;
//查询 VALUE 的大小
ZwQueryKey(hRegister,
KeyFullInformation,
NULL,
0,
&ulSize);
PKEY_FULL_INFORMATION pfi =
(PKEY_FULL_INFORMATION)
ExAllocatePool(PagedPool, ulSize);
ZwQueryKey(hRegister,
KeyFullInformation,
pfi,
ulSize,
&ulSize);
for (ULONG i = 0; i<pfi->Values; i++)
{
//查询单个 VALUE 的大小
ZwEnumerateValueKey(hRegister,
i,
KeyValueBasicInformation,
NULL,
0,
&ulSize);
PKEY_VALUE_BASIC_INFORMATION pvbi =
(PKEY_VALUE_BASIC_INFORMATION)
ExAllocatePool(PagedPool, ulSize);
//查询单个 VALUE 的详情
ZwEnumerateValueKey(hRegister,
i,
KeyValueBasicInformation,
pvbi,
ulSize,
&ulSize);
UNICODE_STRING uniKeyName;
uniKeyName.Length =
uniKeyName.MaximumLength =
(USHORT)pvbi->NameLength;
uniKeyName.Buffer = pvbi->Name;
KdPrint(("The %d sub value name:%wZ\n", i, &uniKeyName));
if (pvbi->Type == REG_SZ)
{
KdPrint(("The sub value type:REG_SZ\n"));
}
else if (pvbi->Type == REG_MULTI_SZ)
{
KdPrint(("The sub value type:REG_MULTI_SZ\n"));
}
else if (pvbi->Type == REG_DWORD)
{
KdPrint(("The sub value type:REG_DWORD\n"));
}
else if (pvbi->Type == REG_BINARY)
{
KdPrint(("The sub value type:REG_BINARY\n"));
}
ExFreePool(pvbi);
}
ExFreePool(pfi);
ZwClose(hRegister);
}

Win 驱动编程 - 内核里操作注册表相关推荐

  1. Win64 驱动内核编程-6.内核里操作注册表

    内核里操作注册表 RING0 操作注册表和 RING3 的区别也不大,同样是"获得句柄->执行操作->关闭句柄"的模式,同样也只能使用内核 API 不能使用 WIN32 ...

  2. Win64 驱动内核编程-5.内核里操作文件

    内核里操作文件 RING0 操作文件和 RING3 操作文件在流程上没什么大的区别,也是"获得文件句柄->读/写/删/改->关闭文件句柄"的模式.当然了,只能用内核 A ...

  3. Win64 驱动内核编程-4.内核里操作字符串

    内核里操作字符串 字符串本质上就是一段内存,之所以和内存使用分开讲,是因为内核里的字符串太有花 样了,细数下来竟然有 4 种字符串!这四种字符串,分别是:CHAR*.WCHAR*.ANSI_STRIN ...

  4. delphi 操作注册表详解

    32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息.   一.创建和释放TRegistry对象   1.创建TRegistry对象.为了操作注册表,要创建一个TRegistr ...

  5. C#操作注册表全攻略

    相信每个人对注册表并不陌生,在运行里面输入"regedit"就可以打开注册表编辑器了.这东西对Windows系统来说可是比较重要的,也是病毒常常会光顾的地方,比如病毒和恶意软件常常 ...

  6. Atitit.操作注册表 树形数据库 注册表的历史 java版本类库总结

    Atitit.操作注册表 树形数据库 注册表的历史 java版本类库总结 1. 注册表是树形数据库 1 2. 注册表的由来 1 3. Java  操作注册表 2 3.1. 使用Preferences  ...

  7. [转]C#操作注册表

    原文链接:http://www.cnblogs.com/txw1958/archive/2012/08/01/csharp-regidit.html 下面我们就来用.NET下托管语言C#注册表操作,主 ...

  8. C#操作注册表REG_DWORD类型键异常(RegistryValueKind.DWord异常)解决方案

    在用C#操作注册表时,如果注册表键的类型是REG_DWORD,有可能遇到溢出BUG.网上这方面的资料很少,在这共享一下. C#可以用RegistryKey类的SetValue方法来设置键值,例如: 看 ...

  9. csharp操作注册表

    写这个博客的原因主要CSharp操作注册表有一个很容易被坑的地方,那就是32位的机器和64位的机器修改注册表的方式不太一样,下面通过一段打开音频设备的代码来看一下32位的和64位的究竟有什么不一样: ...

最新文章

  1. regexp 好汉字符串_如何在JavaScript中使用RegExp确认字符串的结尾
  2. iis6.0解析漏洞
  3. to make target ‘../../lib/aaaaa.so‘, needed by ‘ xxx ‘
  4. java代码逻辑讲解_java逻辑控制语句实例详解
  5. C语言函数最多有有多少个参数,C中子函数最多有几个形参
  6. 珠海 第十届亚洲机器人锦标赛_2016年第十届亚洲机器人锦标赛在广东珠海成功举办...
  7. 链表的逆置,归并,拆分以及其他函数集合
  8. LightOJ 1353 - Paths in a Tree DFS
  9. GD32F103 配置timer0输出PWM
  10. Linux下的虚拟光驱和虚拟软驱
  11. 从零开始学习html(十)CSS格式化排版——下
  12. 信息安全快讯丨一起为亚运健儿加油!
  13. 关于“长尾理论”(The Long Tail)
  14. java 笔触类_下列属于笔触类型的绘图工具有那些?
  15. ODrive AP调试记录
  16. PAT乙级 1070 结绳
  17. 基于QT平台调试rtklib教程
  18. 两本参考书,垒四百块砖的日子
  19. 如何以产品经理角度进行产品分析?
  20. socks代理服务器协议的说明

热门文章

  1. 吴恩达机器学习作业思路整理
  2. 题目:三个售票员 卖出 30张票 || 多线程编程的企业级套路+模板||synchronized与Lock的区别
  3. v-if 和 v-else-if 和 v-else 的使用
  4. SpringMVC的概念
  5. MySQL 数据库sql语句用关键字作为where条件进行筛选实例演示,mysql建表、查询字段为关键字解决方法
  6. Java 技术篇-mac操作系统JRE、JDK环境的配置演示
  7. 调试笔记--keil 断点调试小技巧
  8. [YTU]_2441( C++习题 复数类--重载运算符2+)
  9. 循环相关函数range、enumerate、zip
  10. Pycharm如何关掉jupyter notebook server