在登錄表的操作, 還經常有另外兩種操作, 分別是枚舉子項和枚舉子鍵. 枚舉子項就是事先不知道該項中有多少個子項, 用某個函式將子項一一列舉出來. 而枚舉子鍵則是事先不知道該項中有多少個子鍵, 用某個函式將之子鍵一一列舉出來.
DDK 提供了列舉子項的函式, 它是 ZwQueryKey 函式 和 ZwEnumerateKey. 先來看這兩個函式的宣告 :
- Syntax :
- NTSTATUS ZwQueryKey(
- __in HANDLE KeyHandle,
- __in KEY_INFORMATION_CLASS KeyInformationClass,
- __out_opt PVOID KeyInformation,
- __in ULONG Length,
- __out PULONG ResultLength
- );
參數說明 :
* KeyHandle : 登錄表的控制碼
* KeyInformationClass : 查詢的類別, 一般選擇 KeyFullInformation.
* KeyInformation : 查詢的資料指標, 如果 KeyInformationClass 是 KeyFullInformation, 則該指標指向一個 KEY_FULL_INFORMATION 的資料結構.
* Length : 資料長度
* ResultLength : 返回的資料長度
- Syntax :
- NTSTATUS ZwEnumerateKey(
- __in HANDLE KeyHandle,
- __in ULONG Index,
- __in KEY_INFORMATION_CLASS KeyInformationClass,
- __out_opt PVOID KeyInformation,
- __in ULONG Length,
- __out PULONG ResultLength
- );
參數說明 :
* KeyHandle : 登錄表控制碼
* Index : 很少用, 一般為0.
* KeyInformationClass : 該子項的訊息.
* Length : 子項資訊長度
* ResultLength : 返回子鍵資訊的長度.
ZwQueryKey 的作用主要是獲得某登錄表項究竟有多少個子項, 而 ZwEnumerateKey 的作用主要是針對第幾個子項獲取該子項的具體資訊.
在使用 ZwQueryKey 時, 可以將參數 KeyInformationClass 指定為 KeyFullInformation. 這樣參數 KeyInformation 就對應一個 KEY_FULL_INFORMATION 的資料結構, 該資料結構中的 SubKeys 指明了項中有多少個子項.
在使用 ZwEnumerateKey 時, 需要將參數 KeyInformationClass 設置為 KeyBasicInformation, 這樣其參數 KeyInformation 就能對應 KEY_BASIC_INFORMATION 的資料結構.同理, KEY_BASIC_INFORMATION 也是不定長度的資料結構, 需要呼叫兩次 ZwEnumerateKey. 第一次獲取 KEY_BASIC_INFORMATION 的長度, 第二次獲取 KEY_BASIC_INFORMATION 的資料. 下面例子演示如何枚舉子項目 :
- Driver.cpp (EnumerateSubItemRegTest 函式) : 枚舉子項目
- #pragma INITCODE
- VOID EnumerateSubItemRegTest()
- {
- UNICODE_STRING RegUnicodeString;
- HANDLE hRegister;
- //初始化UNICODE_STRING字串
- RtlInitUnicodeString( &RegUnicodeString,
- MY_REG_SOFTWARE_KEY_NAME);
- OBJECT_ATTRIBUTES objectAttributes;
- //初始化objectAttributes
- InitializeObjectAttributes(&objectAttributes,
- &RegUnicodeString,
- OBJ_CASE_INSENSITIVE,//對大小寫敏感
- NULL,
- NULL );
- //打開登錄表
- NTSTATUS ntStatus = ZwOpenKey( &hRegister,
- KEY_ALL_ACCESS,
- &objectAttributes);
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Open register successfully\n"));
- }
- ULONG ulSize;
- //第一次呼叫ZwQueryKey為了獲取KEY_FULL_INFORMATION資料的長度
- ZwQueryKey(hRegister,
- KeyFullInformation,
- NULL,
- 0,
- &ulSize);
- PKEY_FULL_INFORMATION pfi =
- (PKEY_FULL_INFORMATION)
- ExAllocatePool(PagedPool,ulSize);
- //第二次呼叫ZwQueryKey為了獲取KEY_FULL_INFORMATION資料的資料
- ZwQueryKey(hRegister,
- KeyFullInformation,
- pfi,
- ulSize,
- &ulSize);
- for (ULONG i=0;i
SubKeys;i++) - {
- //第一次呼叫ZwEnumerateKey為了獲取KEY_BASIC_INFORMATION資料的長度
- ZwEnumerateKey(hRegister,
- i,
- KeyBasicInformation,
- NULL,
- 0,
- &ulSize);
- PKEY_BASIC_INFORMATION pbi =
- (PKEY_BASIC_INFORMATION)
- ExAllocatePool(PagedPool,ulSize);
- //第二次呼叫ZwEnumerateKey為了獲取KEY_BASIC_INFORMATION資料的資料
- ZwEnumerateKey(hRegister,
- i,
- KeyBasicInformation,
- pbi,
- ulSize,
- &ulSize);
- UNICODE_STRING uniKeyName;
- uniKeyName.Length =
- uniKeyName.MaximumLength =
- (USHORT)pbi->NameLength;
- uniKeyName.Buffer = pbi->Name;
- KdPrint(("The %d sub item name:%wZ\n",i,&uniKeyName));
- ExFreePool(pbi);
- }
- ExFreePool(pfi);
- ZwClose(hRegister);
- }
枚舉子鍵 :
和枚舉子項類似, 枚舉子鍵是透過 ZwQueryKey 和 ZwEnumerateValueKey 兩個函式的配合完成的. ZwEnumerateValueKey 函式的使用和 ZwEnumberateKey 的函式使用類似. 下面例子演示如何在驅動程式中枚舉子鍵 :
- Driver.cpp (EnumerateSubValueRegTest) : 枚舉子鍵
- #pragma INITCODE
- VOID EnumerateSubValueRegTest()
- {
- UNICODE_STRING RegUnicodeString;
- HANDLE hRegister;
- //初始化UNICODE_STRING字串
- RtlInitUnicodeString( &RegUnicodeString,
- MY_REG_SOFTWARE_KEY_NAME);
- OBJECT_ATTRIBUTES objectAttributes;
- //初始化objectAttributes
- InitializeObjectAttributes(&objectAttributes,
- &RegUnicodeString,
- OBJ_CASE_INSENSITIVE,//對大小寫敏感
- NULL,
- NULL );
- //打開登錄表
- NTSTATUS ntStatus = ZwOpenKey( &hRegister,
- KEY_ALL_ACCESS,
- &objectAttributes);
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Open register successfully\n"));
- }
- ULONG ulSize;
- ZwQueryKey(hRegister,
- KeyFullInformation,
- NULL,
- 0,
- &ulSize);
- PKEY_FULL_INFORMATION pfi =
- (PKEY_FULL_INFORMATION)
- ExAllocatePool(PagedPool,ulSize);
- ZwQueryKey(hRegister,
- KeyFullInformation,
- pfi,
- ulSize,
- &ulSize);
- for (ULONG i=0;i
Values;i++) - {
- ZwEnumerateValueKey(hRegister,
- i,
- KeyValueBasicInformation,
- NULL,
- 0,
- &ulSize);
- PKEY_VALUE_BASIC_INFORMATION pvbi =
- (PKEY_VALUE_BASIC_INFORMATION)
- ExAllocatePool(PagedPool,ulSize);
- ZwEnumerateValueKey(hRegister,
- i,
- KeyValueBasicInformation,
- pvbi,
- ulSize,
- &ulSize);
- UNICODE_STRING uniKeyName;
- uniKeyName.Length =
- uniKeyName.MaximumLength =
- (USHORT)pvbi->NameLength;
- uniKeyName.Buffer = pvbi->Name;
- KdPrint(("The %d sub value name:%wZ\n",i,&uniKeyName));
- if (pvbi->Type==REG_SZ)
- {
- KdPrint(("The sub value type:REG_SZ\n"));
- }else if (pvbi->Type==REG_MULTI_SZ)
- {
- KdPrint(("The sub value type:REG_MULTI_SZ\n"));
- }else if (pvbi->Type==REG_DWORD)
- {
- KdPrint(("The sub value type:REG_DWORD\n"));
- }else if (pvbi->Type==REG_BINARY)
- {
- KdPrint(("The sub value type:REG_BINARY\n"));
- }
- ExFreePool(pvbi);
- }
- ExFreePool(pfi);
- ZwClose(hRegister);
- }
刪除子項 :
DDK 同樣提供了刪除子項的內核函式, 它就是 ZwDeleteKey. 其宣告如下 :
- Syntax :
- NTSTATUS ZwDeleteKey(
- __in HANDLE KeyHandle
- );
參數說明 :
* KeyHandle : 打開的控制碼.
需要指出, 該函式只能刪除沒有子項的專案, 如果子項中還有子項, 則不能刪除. 這時候需要先將該項中的所有子項刪除後, 在刪除該項. 下面範例演式如何在驅動刪除子項 :
- Driver.cpp (DeleteItemRegTest 函式) : 示範刪除子項
- #pragma INITCODE
- VOID DeleteItemRegTest()
- {
- UNICODE_STRING RegUnicodeString;
- HANDLE hRegister;
- #define MY_REG_SOFTWARE_KEY_NAME1 L"\\Registry\\Machine\\Software\\Zhangfan\\SubItem"
- //初始化UNICODE_STRING字串
- RtlInitUnicodeString( &RegUnicodeString,
- MY_REG_SOFTWARE_KEY_NAME1);
- OBJECT_ATTRIBUTES objectAttributes;
- //初始化objectAttributes
- InitializeObjectAttributes(&objectAttributes,
- &RegUnicodeString,
- OBJ_CASE_INSENSITIVE,//對大小寫敏感
- NULL,
- NULL );
- //打開登錄表
- NTSTATUS ntStatus = ZwOpenKey( &hRegister,
- KEY_ALL_ACCESS,
- &objectAttributes);
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Open register successfully\n"));
- }
- ntStatus = ZwDeleteKey(hRegister);
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Delete the item successfully\n"));
- }else if(ntStatus == STATUS_ACCESS_DENIED)
- {
- KdPrint(("STATUS_ACCESS_DENIED\n"));
- }else if(ntStatus == STATUS_INVALID_HANDLE)
- {
- KdPrint(("STATUS_INVALID_HANDLE\n"));
- }else
- {
- KdPrint(("Maybe the item has sub item to delete\n"));
- }
- ZwClose(hRegister);
- }
其他 :
以上介紹了部分核心模式下操作登錄表的函式, 使用方法都比較繁瑣, 往往一個操作需要若干個函式共同配合. 為了簡化登錄表操作, DDK 還提供一系列以 Rtl 開頭的執行時函式, 這些函式把前面介紹的函式進行封裝, 往往一條函式就能實現前面介紹若干函式的功能 :
- RtlCreateRegistryKey : 新建登錄表
- RtlCheckRegistryKey : 查看某登錄表項是否存在
- RtlWriteRegistryValue : 寫入登錄表
- RtlDeleteRegistryValue : 刪除登錄表子鍵
上表列出了 Rtl 系列函式對登陸表操作功能, 下面程式碼演示了在驅動程式中如何使用這些函式, 可以看得出來其操作比 ZwXX 系列函式簡單得多 :
- Driver.cpp (RtlRegTest) : 使用 Rtl 系列函式操作登錄表
- #pragma INITCODE
- void RtlRegTest()
- {
- //新建子項目
- NTSTATUS ntStatus =
- RtlCreateRegistryKey(RTL_REGISTRY_SERVICES,L"HelloDDK\\Zhangfan");
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Create the item successfully\n"));
- }
- //檢查某項是否存在
- ntStatus =
- RtlCheckRegistryKey(RTL_REGISTRY_SERVICES,L"HelloDDK\\Zhangfan");
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("The item is exist\n"));
- }
- //寫入REG_DWORD的資料
- ULONG value1 = 100;
- ntStatus =
- RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
- L"HelloDDK\\Zhangfan",
- L"DWORD_Value",
- REG_DWORD,
- &value1,
- sizeof(value1));
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Write the DWORD value succuessfully\n"));
- }
- PWCHAR szString = L"Hello DDK";
- ntStatus =
- RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
- L"HelloDDK\\Zhangfan",
- L"SZ_Value",
- REG_SZ,
- szString,
- wcslen(szString)*2+2);
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Write the REG_SZ value succuessfully\n"));
- }
- RTL_QUERY_REGISTRY_TABLE paramTable[2];
- RtlZeroMemory(paramTable, sizeof(paramTable));
- ULONG defaultData=0;
- ULONG uQueryValue;
- paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- paramTable[0].Name = L"DWORD_Value";
- paramTable[0].EntryContext = &uQueryValue;
- paramTable[0].DefaultType = REG_DWORD;
- paramTable[0].DefaultData = &defaultData;
- paramTable[0].DefaultLength = sizeof(ULONG);
- //查詢REG_DWORD的資料
- ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
- L"HelloDDK\\Zhangfan",
- paramTable,
- NULL,
- NULL);
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("Query the item successfully\n"));
- KdPrint(("The item is :%d\n",uQueryValue));
- }
- //刪除子鍵
- ntStatus = RtlDeleteRegistryValue(RTL_REGISTRY_SERVICES,
- L"HelloDDK\\Zhangfan",
- L"DWORD_Value");
- if (NT_SUCCESS(ntStatus))
- {
- KdPrint(("delete the value successfully\n"));
- }
- }
沒有留言:
張貼留言