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);

    // 創建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 \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 \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.2 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.3 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";

    // 新建設置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分別創建一個整數,布爾值,字符串類型,效果圖如下;

8.5.4 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 \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.5 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.6 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 \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.7 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刪除,效果圖如下所示;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章