注冊表是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\
目錄下分別創建LySharkKeysA
和LySharkKeysB
兩個空目錄,輸出效果如下圖;
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
刪除,效果圖如下所示;