8.5 Windows驱动开发:内核注册表增删改查

注册表是Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息,注册表是一个巨大的树形结构,无论在应用层还是内核层操作注册表都有独立的API函数可以使用,而在内核中读写注册表则需要使用内核装用API函数,如下将依次介绍并封装一些案例,实现对注册表的创建,删除,更新,查询等操作。

在Windows内核中,注册表是一种存储系统配置信息的机制,包括应用程序、硬件、驱动程序和操作系统的各种设置。内核提供了一些API函数,可以让驱动程序通过代码访问和修改注册表,以实现系统的配置和管理。下面简单介绍一下内核中的注册表增删改查操作:

注册表查询

  • 在内核中,可以使用ZwQueryValueKey或ZwEnumerateValueKey函数查询指定键的值。其中,ZwQueryValueKey函数可以查询指定键的值,而ZwEnumerateValueKey函数可以枚举指定键下的所有值。这两个函数都需要指定键的句柄和要查询的值的名称,查询结果将返回在指定的缓冲区中。

注册表修改

  • 在内核中,可以使用ZwSetValueKey函数修改指定键的值。该函数需要指定键的句柄、要修改的值的名称、值的类型和值的数据。在修改注册表时,需要注意权限和安全性问题,以避免潜在的安全问题。

注册表添加

  • 在内核中,可以使用ZwCreateKey函数创建一个新的键。该函数需要指定要创建键的父键的句柄、新键的名称、新键的属性等信息。如果成功创建了新键,则可以使用ZwSetValueKey函数向其添加值。

注册表删除

  • 在内核中,可以使用ZwDeleteValueKey函数删除指定键的值,或使用ZwDeleteKey函数删除指定键及其下面的所有子键和值。这两个函数都需要指定要删除的键的句柄或路径。在删除注册表时,同样需要注意权限和安全性问题,以避免潜在的安全问题。

需要注意的是,对注册表的操作可能会对系统的稳定性产生影响。因此,在实现这些技术时,需要遵循操作系统和安全软件的规定,以确保系统的安全和稳定。

8.5.1 ZwCreateKey

创建注册表Key键,内核函数ZwCreateKey可用于创建新的注册表项或打开现有注册表项。

ZwCreateKey是Windows内核中的一个函数,用于创建一个新的注册表键(registry key)。它通常被驱动程序使用来添加新的配置信息或者修改已有的配置信息。

以下是ZwCreateKey函数的一般形式:

NTSTATUS ZwCreateKey(_Out_ PHANDLE            KeyHandle,_In_  ACCESS_MASK        DesiredAccess,_In_  POBJECT_ATTRIBUTES ObjectAttributes,_Reserved_ ULONG         TitleIndex,_In_  PUNICODE_STRING    Class,_In_  ULONG              CreateOptions,_Out_ PULONG             Disposition
);

参数说明:

  • KeyHandle: 输出参数,指向新创建的注册表键的句柄(handle)。
  • DesiredAccess: 指定新创建的键所需的访问权限,比如KEY_QUERY_VALUE等,具体请参考MSDN文档。
  • ObjectAttributes: 指向一个OBJECT_ATTRIBUTES结构体的指针,该结构体包含了注册表键的一些属性信息,比如名称、路径等。
  • TitleIndex: 指定键的标题索引。
  • Class: 指向一个UNICODE_STRING结构体的指针,它用于指定新创建的键的类名。
  • CreateOptions: 指定创建键的选项,比如REG_OPTION_NON_VOLATILE等。
  • Disposition: 输出参数,指向一个ULONG类型的指针,返回创建的键的状态信息,比如REG_CREATED_NEW_KEY等。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwCreateKey函数之前,必须先初始化OBJECT_ATTRIBUTES结构体,以包含要创建的注册表键的完整路径。

在使用ZwCreateKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的类名、访问权限和创建选项等参数的设置,以确保所创建的键能够正确地满足应用程序的需求。

#include <ntifs.h>// 创建或者打开已存在注册表键
BOOLEAN MyCreateRegistryKeyA(UNICODE_STRING ustrRegistry)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };ULONG ulResult = 0;NTSTATUS status = STATUS_SUCCESS;// 创建或者打开已存在注册表键InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);// 创建Keystatus = ZwCreateKey(&hRegister,KEY_ALL_ACCESS,&objectAttributes,0,NULL,REG_OPTION_NON_VOLATILE,&ulResult);if (!NT_SUCCESS(status)){return FALSE;}if (REG_CREATED_NEW_KEY == ulResult){DbgPrint("[*] 注册表已被创建 \n");}else if (REG_OPENED_EXISTING_KEY == ulResult){DbgPrint("[*] 注册表打开 \n");}// 关闭注册表键句柄ZwClose(hRegister);return TRUE;
}// 创建键值对
BOOLEAN MyCreateRegistryKeyB(LPWSTR KeyName)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);// 初始化InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 创建KeyntStatus = ZwCreateKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);if (NT_SUCCESS(ntStatus)){DbgPrint("[*] 注册表已被创建 \n");ZwClose(hRegister);return TRUE;}else{DbgPrint("[*] 注册表创建失败 \n");return FALSE;}return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;// 创建注册表键UNICODE_STRING ustrRegistry;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");flag = MyCreateRegistryKeyA(ustrRegistry);if (flag == TRUE){DbgPrint("注册表键已创建 \n");}// 创建注册表键flag = MyCreateRegistryKeyB(L"\\Registry\\Machine\\Software\\LySharkKeysB");if (flag == TRUE){DbgPrint("注册表键已创建 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

运行如上代码即可在计算机\HKEY_LOCAL_MACHINE\SOFTWARE\目录下分别创建LySharkKeysALySharkKeysB两个空目录,输出效果如下图;

8.5.2 ZwDeleteKey

删除注册表Key键,内核函数ZwDeleteKey可从注册表中删除打开的项。

ZwDeleteKey是Windows内核中的一个函数,用于删除指定的注册表键(registry key)。它通常被驱动程序使用来删除不再需要的配置信息或者清理无用的键。

以下是ZwDeleteKey函数的一般形式:

NTSTATUS ZwDeleteKey(_In_ HANDLE            KeyHandle
);

参数说明:

  • KeyHandle:要删除的键的句柄(handle)。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwDeleteKey函数之前,需要先打开要删除的键,获取其句柄。

在使用ZwDeleteKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要删除的键是正确的,并且不会对系统造成不良影响。

另外,需要注意的是,ZwDeleteKey函数只能用于删除空的注册表键。如果要删除非空的键,需要先递归地删除该键下的所有子键和值。

#include <ntifs.h>// 删除注册表键
BOOLEAN MyDeleteRegistryKeyA(UNICODE_STRING ustrRegistry)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;// 打开注册表键InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 删除注册表键status = ZwDeleteKey(hRegister);if (!NT_SUCCESS(status)){ZwClose(hRegister);return FALSE;}// 关闭注册表键句柄ZwClose(hRegister);return TRUE;
}// 删除注册表键
BOOLEAN MyDeleteRegistryKeyB(LPWSTR KeyName)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);// 初始化InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打开KeyntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (NT_SUCCESS(ntStatus)){ntStatus = ZwDeleteKey(hRegister);ZwClose(hRegister);return TRUE;}else{return FALSE;}return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;// 删除注册表键UNICODE_STRING ustrRegistry;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");flag = MyDeleteRegistryKeyA(ustrRegistry);if (flag == TRUE){DbgPrint("[*] 已删除 \n");}// 删除注册表键flag = MyDeleteRegistryKeyB(L"\\Registry\\Machine\\Software\\LySharkKeysB");if (flag == TRUE){DbgPrint("[*] 已删除 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行如上程序,则可将ZwCreateKey创建的Key键删除,当尝试再次打开LySharkKeysB则会提示打开失败,输出效果如下所示;

8.5.3 ZwRenameKey

重命名注册表Key键,内核函数ZwRenameKey可修改特定注册表键名,此函数需要自行导出。

ZwRenameKey是Windows内核中的一个函数,用于重命名一个指定的注册表键。它通常被驱动程序使用来更改配置信息或者重命名键。

以下是ZwRenameKey函数的一般形式:

NTSTATUS ZwRenameKey(_In_ HANDLE            KeyHandle,_In_ PUNICODE_STRING   NewName
);

参数说明:

  • KeyHandle: 要重命名的键的句柄(handle)。
  • NewName: 新键名称的Unicode字符串。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwRenameKey函数之前,需要先打开要重命名的键,获取其句柄。

在使用ZwRenameKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要重命名的键是正确的,并且不会对系统造成不良影响。另外,需要确保新键名称是唯一的,且符合注册表键名称的规范。

需要注意的是,ZwRenameKey函数只能用于重命名单个键,如果需要批量重命名键,则需要自行实现递归操作。

#include <ntifs.h>// ZwRenameKey 需要自己导出
typedef NTSTATUS(__fastcall *ZWRENAMEKEY)(HANDLE KeyHandle, PUNICODE_STRING NewName);ZWRENAMEKEY MyZwRenameKey = NULL;// 根据函数名得到函数内存地址
PVOID GetFunctionAddr(PCWSTR FunctionName)
{UNICODE_STRING UniCodeFunctionName;RtlInitUnicodeString(&UniCodeFunctionName, FunctionName);return MmGetSystemRoutineAddress(&UniCodeFunctionName);
}// 重命名注册表Key
BOOLEAN RegRenameKey(LPWSTR OldKeyName, LPWSTR NewKeyName)
{OBJECT_ATTRIBUTES objectAttributes;HANDLE hRegister;NTSTATUS ntStatus;UNICODE_STRING usOldKeyName, usNewKeyName;RtlInitUnicodeString(&usOldKeyName, OldKeyName);RtlInitUnicodeString(&usNewKeyName, NewKeyName);InitializeObjectAttributes(&objectAttributes, &usOldKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 得到函数内存地址MyZwRenameKey = (ZWRENAMEKEY)GetFunctionAddr(L"ZwRenameKey");ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (NT_SUCCESS(ntStatus)){// 重命名Key键ntStatus = MyZwRenameKey(hRegister, &usNewKeyName);ZwFlushKey(hRegister);ZwClose(hRegister);return TRUE;}else{return FALSE;}return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;// 重命名键flag = RegRenameKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"SuperLyShark");if (flag == TRUE){DbgPrint("[*] 已被重命名 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行这段驱动程序,自动将LySharkKeysA改名为SuperLyShark,输出效果如下所示;

8.5.4 ZwSetValueKey

在键中创建Value值,在一个Key中增加一个新的值。

ZwSetValueKey是Windows内核中的一个函数,用于向指定的注册表键中写入值。它通常被驱动程序使用来修改或添加配置信息或者键值。

以下是ZwSetValueKey函数的一般形式:

NTSTATUS ZwSetValueKey(_In_ HANDLE            KeyHandle,_In_ PUNICODE_STRING   ValueName,_In_opt_ ULONG         TitleIndex,_In_ ULONG             Type,_In_opt_ PVOID         Data,_In_ ULONG             DataSize
);

参数说明:

  • KeyHandle: 要写入值的键的句柄(handle)。
  • ValueName: 要写入值的名称的Unicode字符串。
  • TitleIndex: 零基索引,用于在键的名称列表中查找与ValueName相对应的索引值。
  • Type: 要写入的值的类型。
  • Data: 要写入的数据的指针。
  • DataSize: 要写入的数据的长度。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwSetValueKey函数之前,需要先打开要写入值的键,获取其句柄。

在使用ZwSetValueKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要写入值的键是正确的,并且不会对系统造成不良影响。另外,需要确保写入的数据类型和长度正确,以避免造成不必要的问题。

需要注意的是,ZwSetValueKey函数只能用于向单个键写入单个值,如果需要批量写入值,则需要自行实现循环操作。

#include <ntifs.h>
#include <windef.h>// 在键中增加值
BOOLEAN RegSetValueKey(LPWSTR KeyName, LPWSTR ValueName, DWORD DataType, PVOID DataBuffer, DWORD DataLength)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName, usValueName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);RtlInitUnicodeString(&usValueName, ValueName);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);return TRUE;}else{return FALSE;}return FALSE;
}// 添加或者修改注册表键值
BOOLEAN MySetRegistryKeyValue(UNICODE_STRING ustrRegistry, UNICODE_STRING ustrKeyValueName, ULONG ulKeyValueType, PVOID pKeyValueData, ULONG ulKeyValueDataSize)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打开注册表键status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 添加或者修改键值status = ZwSetValueKey(hRegister, &ustrKeyValueName, 0, ulKeyValueType, pKeyValueData, ulKeyValueDataSize);if (!NT_SUCCESS(status)){ZwClose(hRegister);return FALSE;}// 关闭注册表键句柄ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;DWORD set_dw = 1024;BOOLEAN is_true = TRUE;WCHAR sz_char[256] = L"hello lyshark";// 新建设置valueflag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth", REG_DWORD, &set_dw, sizeof(set_dw));if (flag == TRUE){DbgPrint("[*] 创建is_auth值成功 \n");}// 新建设置boolflag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_trhe", REG_BINARY, &is_true, sizeof(is_true));if (flag == TRUE){DbgPrint("[*] 创建is_true值成功 \n");}// 新建设置charflag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"1001", REG_SZ, &sz_char, sizeof(sz_char));if (flag == TRUE){DbgPrint("[*] 创建char值成功 \n");}// 添加注册表键值UNICODE_STRING ustrRegistry;UNICODE_STRING ustrKeyValueName;WCHAR wstrKeyValueData[] = L"I am LyShark";RtlInitUnicodeString(&ustrKeyValueName, L"1002");RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");flag = MySetRegistryKeyValue(ustrRegistry, ustrKeyValueName, REG_SZ, wstrKeyValueData, sizeof(wstrKeyValueData));if (flag == TRUE){DbgPrint("[*] 创建char值成功 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行如上代码,即可在\\Registry\\Machine\\Software\\LySharkKeysA分别创建一个整数,布尔值,字符串类型,效果图如下;

8.5.5 ZwQueryValueKey

查询某个Key键中的值,调用后可输出特定键中的值。

ZwQueryValueKey是Windows内核中的一个函数,用于从指定的注册表键中读取指定值的数据。它通常被驱动程序使用来获取配置信息或者键值。

以下是ZwQueryValueKey函数的一般形式:

NTSTATUS ZwQueryValueKey(_In_ HANDLE            KeyHandle,_In_ PUNICODE_STRING   ValueName,_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,_Out_opt_ PVOID        KeyValueInformation,_In_ ULONG             Length,_Out_ PULONG           ResultLength
);

参数说明:

  • KeyHandle: 要读取值的键的句柄(handle)。
  • ValueName: 要读取值的名称的Unicode字符串。
  • KeyValueInformationClass: 指定要获取的键值的信息类型。
  • KeyValueInformation: 存储读取的键值信息的缓冲区。
  • Length: KeyValueInformation缓冲区的大小。
  • ResultLength: 实际读取的键值信息的大小。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwQueryValueKey函数之前,需要先打开要读取值的键,获取其句柄。

在使用ZwQueryValueKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要读取值的键是正确的,并且不会对系统造成不良影响。另外,需要确保KeyValueInformation缓冲区的大小足够,以存储读取的键值信息。

需要注意的是,ZwQueryValueKey函数只能用于读取单个键的单个值,如果需要读取多个键的值,则需要自行实现循环操作。

#include <ntifs.h>
#include <windef.h>// 查询Key键中的Value值
BOOLEAN RegQueryValueKey(LPWSTR KeyName, LPWSTR ValueName, PKEY_VALUE_PARTIAL_INFORMATION *pkvpi)
{ULONG ulSize;NTSTATUS ntStatus;PKEY_VALUE_PARTIAL_INFORMATION pvpi;OBJECT_ATTRIBUTES objectAttributes;HANDLE hRegister;UNICODE_STRING usKeyName;UNICODE_STRING usValueName;RtlInitUnicodeString(&usKeyName, KeyName);RtlInitUnicodeString(&usValueName, ValueName);// 初始化InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打开注册表KeyntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 查询长度ntStatus = ZwQueryValueKey(hRegister, &usValueName, KeyValuePartialInformation, NULL, 0, &ulSize);if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0){return FALSE;}// 分配空间保存查询结果pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize);ntStatus = ZwQueryValueKey(hRegister, &usValueName, KeyValuePartialInformation, pvpi, ulSize, &ulSize);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 这里的pvpi未被释放,可在外部释放// 执行 ExFreePool(pvpi); 释放*pkvpi = pvpi;return TRUE;
}// 查询注册表键值
BOOLEAN MyQueryRegistryKeyValue(UNICODE_STRING ustrRegistry, UNICODE_STRING ustrKeyValueName)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;ULONG ulBufferSize = 0;PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInfo = NULL;// 初始化InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打开注册表Keystatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 先获取查询注册表键值所需缓冲区的大小status = ZwQueryValueKey(hRegister, &ustrKeyValueName, KeyValuePartialInformation, NULL, 0, &ulBufferSize);if (0 == ulBufferSize){ZwClose(hRegister);return FALSE;}// 申请缓冲区pKeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, ulBufferSize);// 查询注册表键值并获取查询结果status = ZwQueryValueKey(hRegister, &ustrKeyValueName, KeyValuePartialInformation, pKeyValuePartialInfo, ulBufferSize, &ulBufferSize);if (!NT_SUCCESS(status)){ExFreePool(pKeyValuePartialInfo);ZwClose(hRegister);return FALSE;}// 显示查询结果DbgPrint("KeyValueName=%wZ, KeyValueType=%d, KeyValueData=%S\n", &ustrKeyValueName, pKeyValuePartialInfo->Type, pKeyValuePartialInfo->Data);// 释放内存, 关闭句柄ExFreePool(pKeyValuePartialInfo);ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;DWORD get_dw = 0;PKEY_VALUE_PARTIAL_INFORMATION pkvi;// 查询设置flag = RegQueryValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth", &pkvi);if (flag == TRUE){// 拷贝查询结果RtlCopyMemory(&get_dw, pkvi->Data, pkvi->DataLength);// 输出结果DbgPrint("[*] 查询结果: %d \n", get_dw);ExFreePool(pkvi);}// 第二种查询方式UNICODE_STRING ustrRegistry;UNICODE_STRING ustrKeyValueName;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");RtlInitUnicodeString(&ustrKeyValueName, L"is_auth");MyQueryRegistryKeyValue(ustrRegistry, ustrKeyValueName);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行这段程序,将会查询\\Registry\\Machine\\Software\\LySharkKeysA下面的is_auth字段中的值,输出效果如下图所示;

8.5.6 ZwEnumerateKey

枚举某个主键底部的子键值,实现对指定主键中所有的子键的枚举。

ZwEnumerateKey是Windows内核中的一个函数,用于列举指定注册表键下的子键。它通常被驱动程序使用来获取键列表,以及子键的数量和名称等信息。

以下是ZwEnumerateKey函数的一般形式:

NTSTATUS ZwEnumerateKey(_In_ HANDLE                KeyHandle,_In_ ULONG                 Index,_In_ KEY_INFORMATION_CLASS KeyInformationClass,_Out_ PVOID                KeyInformation,_In_ ULONG                 Length,_Out_ PULONG               ResultLength
);

参数说明:

  • KeyHandle: 要列举子键的键的句柄(handle)。
  • Index: 指定要列举的子键的索引。
  • KeyInformationClass: 指定要获取的子键信息类型。
  • KeyInformation: 存储读取的子键信息的缓冲区。
  • Length: KeyInformation缓冲区的大小。
  • ResultLength: 实际读取的子键信息的大小。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwEnumerateKey函数之前,需要先打开要列举子键的键,获取其句柄。

在使用ZwEnumerateKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要列举子键的键是正确的,并且不会对系统造成不良影响。另外,需要确保KeyInformation缓冲区的大小足够,以存储读取的子键信息。

需要注意的是,ZwEnumerateKey函数只能用于列举单个键下的子键,如果需要列举多个键的子键,则需要自行实现循环操作。

#include <ntifs.h>
#include <windef.h>// 枚举子键
BOOLEAN EnumRegistrySubKey(WCHAR *MY_KEY_NAME)
{UNICODE_STRING RegUnicodeString;HANDLE hRegister;OBJECT_ATTRIBUTES objectAttributes;NTSTATUS ntStatus;ULONG ulSize, i;UNICODE_STRING uniKeyName;PKEY_FULL_INFORMATION pfi;// 初始化UNICODE_STRING字符串RtlInitUnicodeString(&RegUnicodeString, MY_KEY_NAME);// 初始化objectAttributes OBJ_CASE_INSENSITIVE(大小写敏感)InitializeObjectAttributes(&objectAttributes, &RegUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打开注册表ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 第一次调用获取KEY_FULL_INFORMATION数据的长度ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 第二次调用获取KEY_FULL_INFORMATION数据的数据ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);// 循环输出子键for (i = 0; i<pfi->SubKeys; i++){PKEY_BASIC_INFORMATION pbi;// 第一次调用获取KEY_BASIC_INFORMATION数据的长度ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 第二次调用获取KEY_BASIC_INFORMATION数据的数据ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);uniKeyName.Length = (USHORT)pbi->NameLength;uniKeyName.MaximumLength = (USHORT)pbi->NameLength;uniKeyName.Buffer = pbi->Name;DbgPrint("[LyShark] 序号: %d | 子Key名: %wZ \n", i, &uniKeyName);ExFreePool(pbi);}ExFreePool(pfi);ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");WCHAR MY_KEY_NAME[] = L"\\Registry\\Machine\\Software";BOOLEAN flag = EnumRegistrySubKey(MY_KEY_NAME);if (flag == TRUE){DbgPrint("[*] 枚举结束 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行如上代码片段,则会枚举\\Registry\\Machine\\Software底部的所有子键值,输出效果图如下所示;

8.5.7 ZwEnumerateValueKey

用于枚举子键下所有键值对的值,原理与上方枚举子键类似。

ZwEnumerateValueKey是Windows内核中的一个函数,用于列举指定注册表键下的所有值。它通常被驱动程序使用来获取键值列表,以及每个键值的名称、类型和数据等信息。

以下是ZwEnumerateValueKey函数的一般形式:

NTSTATUS ZwEnumerateValueKey(_In_ HANDLE                KeyHandle,_In_ ULONG                 Index,_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,_Out_ PVOID                KeyValueInformation,_In_ ULONG                 Length,_Out_ PULONG               ResultLength
);

参数说明:

  • KeyHandle: 要列举值的键的句柄(handle)。
  • Index: 指定要列举的值的索引。
  • KeyValueInformationClass: 指定要获取的值信息类型。
  • KeyValueInformation: 存储读取的值信息的缓冲区。
  • Length: KeyValueInformation缓冲区的大小。
  • ResultLength: 实际读取的值信息的大小。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwEnumerateValueKey函数之前,需要先打开要列举值的键,获取其句柄。

在使用ZwEnumerateValueKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要列举值的键是正确的,并且不会对系统造成不良影响。另外,需要确保KeyValueInformation缓冲区的大小足够,以存储读取的值信息。

需要注意的是,ZwEnumerateValueKey函数只能用于列举单个键下的所有值,如果需要列举多个键的所有值,则需要自行实现循环操作。

#include <ntifs.h>
#include <windef.h>// 枚举子键
BOOLEAN EnumegistrySubValue(WCHAR *MY_KEY_NAME)
{UNICODE_STRING RegUnicodeString;HANDLE hRegister;OBJECT_ATTRIBUTES objectAttributes;ULONG ulSize, i;UNICODE_STRING uniKeyName;PKEY_FULL_INFORMATION pfi;NTSTATUS ntStatus;// 初始化UNICODE_STRING字符串RtlInitUnicodeString(&RegUnicodeString, MY_KEY_NAME);// 初始化objectAttributesInitializeObjectAttributes(&objectAttributes, &RegUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打开注册表ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 查询VALUE的大小ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);for (i = 0; i<pfi->Values; i++){PKEY_VALUE_BASIC_INFORMATION pvbi;// 查询单个VALUE的大小ZwEnumerateValueKey(hRegister, i, KeyValueBasicInformation, NULL, 0, &ulSize);pvbi = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 查询单个VALUE的详情ZwEnumerateValueKey(hRegister, i, KeyValueBasicInformation, pvbi, ulSize, &ulSize);uniKeyName.Length = (USHORT)pvbi->NameLength;uniKeyName.MaximumLength = (USHORT)pvbi->NameLength;uniKeyName.Buffer = pvbi->Name;DbgPrint("[*] 子键: %d | 名称: %wZ | ", i, &uniKeyName);if (pvbi->Type == REG_SZ){DbgPrint("类型: REG_SZ \n");}else if (pvbi->Type == REG_MULTI_SZ){DbgPrint("类型: REG_MULTI_SZ \n");}else if (pvbi->Type == REG_DWORD){DbgPrint("类型: REG_DWORD \n");}else if (pvbi->Type == REG_BINARY){DbgPrint("类型: REG_BINARY \n");}ExFreePool(pvbi);}ExFreePool(pfi);ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");WCHAR MY_KEY_NAME[] = L"\\Registry\\Machine\\Software\\LySharkKeysA";BOOLEAN flag = EnumegistrySubValue(MY_KEY_NAME);if (flag == TRUE){DbgPrint("[*] 枚举结束 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行如上这段代码,则可枚举出\\Registry\\Machine\\Software\\LySharkKeysA底部的所有子键以及该子键的键值,输出效果如下图所示;

8.5.8 ZwDeleteValueKey

用于删除指定键里面键值对的某个值。如果使用函数RegDeleteKey则删除键包括里面的所有值。

ZwDeleteValueKey是Windows内核中的一个函数,用于删除指定注册表键下的一个值。它通常被驱动程序使用来删除指定键下的一个值,以及释放该值占用的空间。

以下是ZwDeleteValueKey函数的一般形式:

NTSTATUS ZwDeleteValueKey(_In_ HANDLE           KeyHandle,_In_ PUNICODE_STRING ValueName
);

参数说明:

  • KeyHandle: 要删除值的键的句柄(handle)。
  • ValueName: 要删除的值的名称,为Unicode字符串指针。

函数执行成功时,将返回STATUS_SUCCESS,否则返回相应的错误代码。需要注意的是,在使用ZwDeleteValueKey函数之前,需要先打开要删除值的键,获取其句柄。

在使用ZwDeleteValueKey函数时,需要注意权限和安全性问题,以避免潜在的安全问题。同时,需要仔细考虑键的名称和路径等信息,确保要删除的值是正确的,并且不会对系统造成不良影响。

需要注意的是,ZwDeleteValueKey函数只能用于删除单个键下的一个值,如果需要删除多个键的多个值,则需要自行实现循环操作。

#include <ntifs.h>
#include <windef.h>// 删除键中的值
BOOLEAN RegDeleteValueKey(LPWSTR KeyName, LPWSTR ValueName)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName, usValueName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);RtlInitUnicodeString(&usValueName, ValueName);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);return TRUE;}else{return FALSE;}return FALSE;
}// 删除注册表键值
BOOLEAN MyDeleteRegistryKeyValue(UNICODE_STRING ustrRegistry, UNICODE_STRING ustrKeyValueName)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;// 打开注册表键InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 删除注册表键status = ZwDeleteValueKey(hRegister, &ustrKeyValueName);if (!NT_SUCCESS(status)){ZwClose(hRegister);return FALSE;}// 关闭注册表键句柄ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");// 删除值BOOLEAN flag = RegDeleteValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth");if (flag == TRUE){DbgPrint("[*] 删除子键 \n");}UNICODE_STRING ustrRegistry;UNICODE_STRING ustrKeyValueName;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");RtlInitUnicodeString(&ustrKeyValueName, L"is_trhe");flag = MyDeleteRegistryKeyValue(ustrRegistry, ustrKeyValueName);if (flag == TRUE){DbgPrint("[*] 删除子键 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译并运行如上驱动程序,则会将\\Registry\\Machine\\Software\\LySharkKeysA里面的is_trhe以及is_auth删除,效果图如下所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/163629.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海外媒体推广发稿平台这8种方法助你一臂之力-华媒舍

在全球经济一体化和信息技术快速进步的背景下&#xff0c;海外市场的开拓对于企业的发展至关重要。要在海外市场上取得成果并非易事&#xff0c;因此我们需要借助一些方法来帮助我们取得成功。其中&#xff0c;海外媒体推广发稿平台是非常有效的工具之一。本文将介绍8种方法&am…

SSM家具个性定制管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 家具个性定制管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用…

低代码表单设计器:可视化+灵活+易操作,降本增效轻松实现!

在现代化办公环境中&#xff0c;拥有先进的低代码表单设计器&#xff0c;可以让企业降本又增效&#xff0c;节约企业成本的同时&#xff0c;也能高效利用企业内部资源&#xff0c;为实现数字化转型升级提供夯实根基。那么&#xff0c;低代码表单设计器拥有什么样的特点&#xf…

张弛语言课,喜剧为什么使人快乐?

在为喜剧类电视剧或电影进行配音时&#xff0c;配音员需要展现出对幽默元素的敏感把握、对剧中笑料的恰到好处的呈现&#xff0c;以及对节奏的精确控制。喜剧的魅力在于其欢乐和幽默&#xff0c;所以配音工作的目标是激发观众的笑感&#xff0c;同时保持故事的流畅性和角色的个…

捷诚管理信息系统 SQL注入漏洞

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 一、产品介绍 捷诚管理信息系统是一款功能全面&#xff0c;可以支持自…

地埋式积水监测仪厂家直销推荐,致力于积水监测

地埋式积水监测仪是一种高科技设备&#xff0c;能够实时监测地面积水深度&#xff0c;并及时发出预警信息&#xff0c;有效避免因积水而产生的安全隐患。这种智能监测仪可以安装在城市道路、立交桥、地下车库等易积水地势较低的地方&#xff0c;以确保及时监测特殊地段的积水&a…

数据库数据恢复—SQLserver数据库中勒索病毒被加密的数据恢复案例

SQLserver数据库数据恢复环境&故障&#xff1a; 一台服务器上的SQLserver数据库被勒索病毒加密&#xff0c;无法正常使用。该服务器上部署有多个SQLserver数据库&#xff0c;其中有2个数据库及备份文件被加密&#xff0c;文件名被篡改&#xff0c;数据库无法使用。 SQL se…

基于框架的线性回归

线性回归是机器学习中最简单和最常用的回归方法之一。它建立了自变量和因变量之间的线性关系&#xff0c;并通过拟合一条直线或超平面来预测和分析数据。 基于框架的线性回归是构建线性回归模型的一种常见方法&#xff0c;它利用现有的机器学习框架来实现线性回归模型的建立、…

企业邮箱即时提醒服务推荐

现在用企业邮箱比较多&#xff0c;但是不能即时提醒&#xff0c;总是误事&#xff0c;什么邮箱可以即时提醒呢&#xff1f;随着工作和生活节奏的加快&#xff0c;传统的电子邮件系统由于不能即时提醒&#xff0c;往往会导致重要邮件的漏接&#xff0c;从而引发一系列的麻烦和误…

Python基础【三】--数据类型-Number【2023.11.23】

1.数值类型 Number数据类型只要包括三个分别是&#xff1a;整型&#xff08;int&#xff09;、浮点型&#xff08;float&#xff09;、复数&#xff08;complex&#xff09; 整型&#xff1a;包括正整数、负整数。如&#xff1a;1024、-1024。整型有四种进制表示&#xff0c;分…

QGIS之二十五两个面图层数据中选择图形完全一致的数据

效果 步骤 1、准备数据 2、按位置选择 在Qgis工具箱中搜索"按位置选择"工具 选择要素和比较要素根据实际选择 运行 3、结果

解决错误0x80071ac3的问题,错误代码0x80071ac3的原因

在使用电脑的过程中可能会出现错误0x80071ac3的代码问题&#xff0c;一旦出现这样的问题解决起来可能会有点麻烦&#xff0c;其实这个错误是和磁盘的问题相关&#xff0c;可以将电脑重启尝试能否解决错误0x80071ac3问题&#xff0c;如果依然不能解决问题的话&#xff0c;那么大…

XC3320 离线式、无电感交流输入线性稳压器 可替代KP3310 固定5V输出电压

XC3320 是一款紧凑型无电感设计的离线式线性稳压器。XC3320 可获得 5V输出电压。XC3320 是一种简单可靠的获得偏置供电的离线式电源解决方案。XC3320 集成了 650V 功率 MOSFET&#xff0c;启动控制电路,VDD 电压控制电路,AC 交流信号同步检测电路&#xff0c;低压差稳压器等。该…

Linux免密登录——A登录B密钥设置(SSH SCP)

密钥登录 密钥登录比帐号密码方式更安全、更方便&#xff0c;并提供了更多的自动化和批处理选项。 安全性&#xff1a;使用非对称加密算法&#xff0c;公钥存在服务器&#xff0c;私钥存在本地计算机&#xff0c;私钥不在网络传输&#xff0c;降低被黑客截获风险。强密码&#…

Windows使用WSL编译自己的JDK

Windows使用WSL编译自己的JDK 一、获取源码二、构建编译环境三、进行编译验证编译结果 四、配置环境变量五、使用CLion进行调试 参考资料&#xff1a;《深入理解java虚拟机》 笔者使用的操作系统为windows&#xff0c;但是windows编译自己的jdk还是比较麻烦的&#xff0c;所以我…

张弛语言课奇幻剧配音,一场特殊的体验

在为奇幻剧进行配音时&#xff0c;配音艺术家要将自己投入到一个充斥着魔法、幻想生物和超自然现象的虚构世界中。奇幻剧侧重于构建一个超越现实的幻境&#xff0c;因此配音工作要求既要呈现角色的个性化特征&#xff0c;也要与剧中的奇幻氛围相得益彰。以下是进行奇幻剧配音的…

太神奇了!视频监控技术居然还能操作

随着科技的迅猛发展&#xff0c;视频监控系统在各个领域中的应用变得越来越广泛。从保护公共安全到提高工作效率&#xff0c;视频监控为我们提供了一种强大而多功能的工具。 视频监控技术已经成为我们日常生活和工作中不可或缺的一部分。通过视频监控&#xff0c;我们能够实时监…

shell循环语句 for while until

目录 什么是循环语句 概念 for循环 格式 while循环 格式 until 循环 格式 实验 for &#xff08;1&#xff09;计算1到100的和 ​编辑 &#xff08;2&#xff09;100以内的偶数 &#xff08;从0开始到100结束&#xff0c;每次加2步 打印的都是偶数&#xff09; &…

完美解决:在Ubuntu18.04下ROS Melodic基于python3的cv_bridge的一点子歪门邪道

由于在Ubuntu18.04下ROS Melodic是运行在python 2.7环境下&#xff0c;而我的程序需要运行在anaconda创建的python 3.x环境里&#xff0c;这就需要用到cv_bridge这个库&#xff0c;而不出意外的&#xff0c;各种报错&#xff0c;比如&#xff1a; from cv_bridge.boost.cv_bri…

贝锐向日葵:独家算法如何支撑不断地产品创新?

作为国民级的专业远程控制品牌&#xff0c;贝锐旗下的“向日葵远程控制”一直在远程控制领域不断积累创新。 近年来&#xff0c;远程控制软件本身开始成为企业的主流远程业务工具以及个人场景下的日常必备软件&#xff0c;向日葵远程控制也在不断地完善并创新产品。 比如在前…