Windows内核:用内核APIo&HIVE文件格式管理注册表
字数 1835 2025-08-20 18:18:05
Windows内核注册表管理与HIVE文件解析
1. 注册表基础概念
注册表是Windows操作系统中的核心数据库,用于存储系统和应用程序的配置信息。它具有层次结构,包含键(Key)和值(Value)。
1.1 主要根键
- HKEY_LOCAL_MACHINE (HKLM)
- HKEY_CURRENT_USER (HKCU)
- HKEY_CLASSES_ROOT (HKCR)
- HKEY_USERS (HKU)
- HKEY_CURRENT_CONFIG (HKCC)
1.2 恶意软件常见注册表操作
- 持久化:通过Run键实现自启动
- HKLM\Software\Microsoft\Windows\CurrentVersion\Run
- HKCU\Software\Microsoft\Windows\CurrentVersion\Run
- 隐藏自身:修改Explorer设置隐藏文件/进程
- 修改系统配置:禁用任务管理器、安全中心等
- 应用程序劫持:修改文件关联
- 信息收集:窃取用户凭据和系统配置
2. 内核API注册表操作
2.1 常用内核API函数
2.1.1 创建/打开注册表项
NTSTATUS ZwCreateKey(
PHANDLE KeyHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
ULONG TitleIndex,
PUNICODE_STRING Class,
ULONG CreateOptions,
PULONG Disposition
);
NTSTATUS ZwOpenKey(
PHANDLE KeyHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
);
示例代码:
HANDLE hKey;
UNICODE_STRING regPath;
RtlInitUnicodeString(®Path, L"\\Registry\\Machine\\Software\\MyKey");
OBJECT_ATTRIBUTES objAttr;
InitializeObjectAttributes(&objAttr, ®Path, OBJ_CASE_INSENSITIVE, NULL, NULL);
NTSTATUS status = ZwCreateKey(&hKey, KEY_ALL_ACCESS, &objAttr, 0, NULL, 0, NULL);
2.1.2 删除注册表项/值
NTSTATUS ZwDeleteKey(HANDLE KeyHandle);
NTSTATUS ZwDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName);
2.1.3 设置注册表值
NTSTATUS ZwSetValueKey(
HANDLE KeyHandle,
PUNICODE_STRING ValueName,
ULONG TitleIndex,
ULONG Type,
PVOID Data,
ULONG DataSize
);
示例代码:
UNICODE_STRING valueName;
RtlInitUnicodeString(&valueName, L"MyValue");
DWORD data = 1;
NTSTATUS status = ZwSetValueKey(hKey, &valueName, 0, REG_DWORD, &data, sizeof(data));
2.1.4 查询注册表值
NTSTATUS ZwQueryValueKey(
HANDLE KeyHandle,
PUNICODE_STRING ValueName,
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
PVOID KeyValueInformation,
ULONG Length,
PULONG ResultLength
);
2.2 实现注册表持久化
完整示例代码:
#include <ntddk.h>
VOID ShowError(PUCHAR pszText, NTSTATUS ntStatus) {
DbgPrint("%s Error[0x%X]\n", pszText, ntStatus);
}
BOOLEAN SetRegistryAutoRun(PUNICODE_STRING ustrExecutablePath) {
HANDLE hKey = NULL;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING ustrKeyPath, ustrValueName;
NTSTATUS status;
RtlInitUnicodeString(&ustrKeyPath, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
InitializeObjectAttributes(&objectAttributes, &ustrKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objectAttributes);
if (!NT_SUCCESS(status)) {
ShowError("ZwOpenKey", status);
return FALSE;
}
RtlInitUnicodeString(&ustrValueName, L"MyPersistentApp");
status = ZwSetValueKey(hKey, &ustrValueName, 0, REG_SZ, ustrExecutablePath->Buffer, ustrExecutablePath->Length);
if (!NT_SUCCESS(status)) {
ZwClose(hKey);
ShowError("ZwSetValueKey", status);
return FALSE;
}
ZwClose(hKey);
DbgPrint("Successfully set auto-run entry.\n");
return TRUE;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) {
UNICODE_STRING ustrExecutablePath;
RtlInitUnicodeString(&ustrExecutablePath, L"C:\\Path\\To\\YourApp.exe");
SetRegistryAutoRun(&ustrExecutablePath);
return STATUS_SUCCESS;
}
3. HIVE文件格式解析
3.1 HIVE文件基础
HIVE文件是注册表在磁盘上的存储形式,位于%SystemRoot%\System32\Config目录下。每个HIVE文件代表一棵注册表树。
3.2 HIVE文件结构
3.2.1 Header结构
- Signature(0x0): "regf"标识
- 主/次序列号(0x4,0x8): 校验完整性
- 最后写入时间(0xC): 8字节Windows文件时间
- 主/次版本号(0x14,0x18)
- 文件类型(0x1C): 0x0标准类型,0x1事务日志
- 根键偏移量(0x24): RootCell的相对偏移
- 文件长度(0x28): 不包括Header的大小
- 文件名(0x30): Unicode字符串
3.2.2 HBIN块
- Signature(0x0): "hbin"标识
- 文件偏移(0x4): 相对于第一个HBIN块的偏移
- 数据大小(0x8): HBIN块大小(通常4096字节)
3.2.3 Cell单元
包含在HBIN块内,由以下记录组成:
- nk记录: 描述注册表项
- vk记录: 描述注册表值
- sk记录: 描述安全权限数据
3.3 记录类型详解
3.3.1 nk记录(注册表项)
- 签名(0x4): "nk"(0x6B6E)
- 最后修改时间(0x8): 8字节
- 父项偏移量(0x14): 0xFFFFFFFF表示无父项
- 子项数量(0x18)
- 子项列表偏移量(0x20)
- vk数量(0x28)
- vk列表偏移量(0x2C)
- sk索引(0x30)
- 名称长度(0x4C)
- 键名称(0x50): ASCII字符串
3.3.2 vk记录(注册表值)
- 签名(0x4): "vk"(0x6B76)
- 名称长度(0x6)
- 数据长度(0x8)
- 数据(0xC)
- 数据类型(0x10):
- REG_SZ(0x1)
- REG_EXPAND_SZ(0x2)
- REG_BINARY(0x3)
- REG_DWORD(0x4)
- REG_MULTI_SZ(0x7)
- 名称(0x18): ASCII字符串
3.3.3 sk记录(安全信息)
- Flink(0x8): 下一条sk记录偏移
- Blink(0xC): 上一条sk记录偏移
3.3.4 List记录
- lf/lh: 子项集合(lf按字母序,lh哈希表)
- li/ri: 子项存储(li简单,ri分块)
- db: 已删除项记录
3.4 HIVE文件解析实践
3.4.1 驱动框架
#include <ntddk.h>
VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint("HIVE解析驱动卸载!\n");
}
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = DriverUnload;
DbgPrint("HIVE解析驱动加载成功!\n");
return STATUS_SUCCESS;
}
3.4.2 文件读取功能
NTSTATUS ReadFile(_In_ PUNICODE_STRING FileName, _Out_ PVOID* Buffer, _Out_ ULONG* FileSize) {
HANDLE fileHandle;
IO_STATUS_BLOCK ioStatusBlock;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS status;
FILE_STANDARD_INFORMATION fileInfo;
InitializeObjectAttributes(&objectAttributes, FileName, OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateFile(&fileHandle, GENERIC_READ, &objectAttributes, &ioStatusBlock, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status)) {
DbgPrint("打开文件失败,状态码: 0x%08x\n", status);
return status;
}
status = ZwQueryInformationFile(fileHandle, &ioStatusBlock, &fileInfo, sizeof(fileInfo), FileStandardInformation);
if (!NT_SUCCESS(status)) {
ZwClose(fileHandle);
return status;
}
*FileSize = fileInfo.EndOfFile.LowPart;
*Buffer = ExAllocatePoolWithTag(NonPagedPool, *FileSize, 'Hive');
if (*Buffer == NULL) {
ZwClose(fileHandle);
return STATUS_INSUFFICIENT_RESOURCES;
}
status = ZwReadFile(fileHandle, NULL, NULL, NULL, &ioStatusBlock, *Buffer, *FileSize, NULL, NULL);
if (!NT_SUCCESS(status)) {
ExFreePoolWithTag(*Buffer, 'Hive');
ZwClose(fileHandle);
return status;
}
ZwClose(fileHandle);
return status;
}
3.4.3 HIVE头部解析
typedef struct _HIVE_HEADER {
CHAR Signature[4]; // "regf"
ULONG Sequence1; // 序列号
ULONG Sequence2; // 序列号
ULONG RootCellOffset; // RootCell的偏移
ULONG HiveBinsDataSize; // hbin数据的大小
ULONG ClusteringFactor;
// 其他字段...
} HIVE_HEADER, *PHIVE_HEADER;
NTSTATUS ParseHiveHeader(_In_ PVOID Buffer, _Out_ ULONG* RootCellOffset) {
PHIVE_HEADER hiveHeader = (PHIVE_HEADER)Buffer;
if (RtlCompareMemory(hiveHeader->Signature, "regf", 4) != 4) {
DbgPrint("HIVE文件签名错误!\n");
return STATUS_INVALID_PARAMETER;
}
*RootCellOffset = hiveHeader->RootCellOffset;
DbgPrint("RootCell Offset: 0x%08x\n", *RootCellOffset);
return STATUS_SUCCESS;
}
3.4.4 nk记录解析
NTSTATUS ParseNkRecord(_In_ PVOID Buffer, _In_ ULONG Offset) {
PNK_RECORD nkRecord = (PNK_RECORD)((PUCHAR)Buffer + Offset);
if (nkRecord->Signature != 0x6B6E) { // "nk"
DbgPrint("NK记录签名错误!\n");
return STATUS_INVALID_PARAMETER;
}
DbgPrint("NK记录解析成功!子键数量: %u, 键值数量: %u\n",
nkRecord->SubkeyCount, nkRecord->ValueCount);
return STATUS_SUCCESS;
}
4. 总结
本文详细介绍了Windows内核中注册表操作的两种方式:
- 通过内核API函数直接操作注册表
- 通过解析底层的HIVE文件格式间接操作注册表
对于安全研究而言,理解HIVE文件格式尤为重要,因为它比API操作更难被检测和监控。通过分析HIVE文件结构,可以深入理解注册表的存储机制,为注册表取证和安全分析提供基础。