驅動開發:核心登入檔增刪改查

2023-06-21 12:03:30

登入檔是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\目錄下分別建立LySharkKeysALySharkKeysB兩個空目錄,輸出效果如下圖;

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=%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刪除,效果圖如下所示;