注冊表是Windows中的一個重要的資料庫,用于存盤系統和應用程式的設定資訊,注冊表是一個巨大的樹形結構,無論在應用層還是內核層操作注冊表都有獨立的API函式可以使用,而在內核中讀寫注冊表則需要使用內核裝用API函式,如下將依次介紹并封裝一些案例,實作對注冊表的創建,洗掉,更新,查詢等操作,
在Windows內核中,注冊表是一種存盤系統配置資訊的機制,包括應用程式、硬體、驅動程式和作業系統的各種設定,內核提供了一些API函式,可以讓驅動程式通過代碼訪問和修改注冊表,以實作系統的配置和管理,下面簡單介紹一下內核中的注冊表增刪改查操作:
注冊表查詢
- 在內核中,可以使用ZwQueryValueKey或ZwEnumerateValueKey函式查詢指定鍵的值,其中,ZwQueryValueKey函式可以查詢指定鍵的值,而ZwEnumerateValueKey函式可以列舉指定鍵下的所有值,這兩個函式都需要指定鍵的句柄和要查詢的值的名稱,查詢結果將回傳在指定的緩沖區中,
注冊表修改
- 在內核中,可以使用ZwSetValueKey函式修改指定鍵的值,該函式需要指定鍵的句柄、要修改的值的名稱、值的型別和值的資料,在修改注冊表時,需要注意權限和安全性問題,以避免潛在的安全問題,
注冊表添加
- 在內核中,可以使用ZwCreateKey函式創建一個新的鍵,該函式需要指定要創建鍵的父鍵的句柄、新鍵的名稱、新鍵的屬性等資訊,如果成功創建了新鍵,則可以使用ZwSetValueKey函式向其添加值,
注冊表洗掉
- 在內核中,可以使用ZwDeleteValueKey函式洗掉指定鍵的值,或使用ZwDeleteKey函式洗掉指定鍵及其下面的所有子鍵和值,這兩個函式都需要指定要洗掉的鍵的句柄或路徑,在洗掉注冊表時,同樣需要注意權限和安全性問題,以避免潛在的安全問題,
需要注意的是,對注冊表的操作可能會對系統的穩定性產生影響,因此,在實作這些技術時,需要遵循作業系統和安全軟體的規定,以確保系統的安全和穩定,
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);
// 創建Key
status = 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);
// 創建Key
ntStatus = 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.com \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\目錄下分別創建LySharkKeysA和LySharkKeysB兩個空目錄,輸出效果如下圖;

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);
// 打開Key
ntStatus = 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.com \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則會提示打開失敗,輸出效果如下所示;

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.com \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,輸出效果如下所示;

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.com \n");
BOOLEAN flag = FALSE;
DWORD set_dw = 1024;
BOOLEAN is_true = TRUE;
WCHAR sz_char[256] = L"hello lyshark";
// 新建設定value
flag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth", REG_DWORD, &set_dw, sizeof(set_dw));
if (flag == TRUE)
{
DbgPrint("[*] 創建is_auth值成功 \n");
}
// 新建設定bool
flag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_trhe", REG_BINARY, &is_true, sizeof(is_true));
if (flag == TRUE)
{
DbgPrint("[*] 創建is_true值成功 \n");
}
// 新建設定char
flag = 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分別創建一個整數,布林值,字串型別,效果圖如下;

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);
// 打開注冊表Key
ntStatus = 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);
// 打開注冊表Key
status = 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=https://www.cnblogs.com/LyShark/archive/2023/06/21/%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.com \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欄位中的值,輸出效果如下圖所示;

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.com \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底部的所有子鍵值,輸出效果圖如下所示;

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);
// 初始化objectAttributes
InitializeObjectAttributes(&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.com \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底部的所有子鍵以及該子鍵的鍵值,輸出效果如下圖所示;

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.com \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洗掉,效果圖如下所示;

文章出處:https://www.cnblogs.com/LyShark/p/17158485.html
本博客所有文章除特別宣告外,均采用 BY-NC-SA 許可協議,轉載請注明出處!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/555792.html
標籤:其他
上一篇:驅動開發:內核注冊表增刪改查
下一篇:返回列表
