2011年1月6日 星期四

[ Windows DDP ] Windows 內核函式 : 核心模式下的登錄表操作 (Part2)

枚舉子項 : 
在登錄表的操作, 還經常有另外兩種操作, 分別是枚舉子項和枚舉子鍵. 枚舉子項就是事先不知道該項中有多少個子項, 用某個函式將子項一一列舉出來. 而枚舉子鍵則是事先不知道該項中有多少個子鍵, 用某個函式將之子鍵一一列舉出來. 
DDK 提供了列舉子項的函式, 它是 ZwQueryKey 函式 和 ZwEnumerateKey. 先來看這兩個函式的宣告 : 

- Syntax :
  1. NTSTATUS ZwQueryKey(  
  2.   __in       HANDLE KeyHandle,  
  3.   __in       KEY_INFORMATION_CLASS KeyInformationClass,  
  4.   __out_opt  PVOID KeyInformation,  
  5.   __in       ULONG Length,  
  6.   __out      PULONG ResultLength  
  7. );  

參數說明 : 
* KeyHandle : 登錄表的控制碼
* KeyInformationClass : 查詢的類別, 一般選擇 KeyFullInformation.
* KeyInformation : 查詢的資料指標, 如果 KeyInformationClass 是 KeyFullInformation, 則該指標指向一個 KEY_FULL_INFORMATION 的資料結構.
* Length : 資料長度
* ResultLength : 返回的資料長度

- Syntax :
  1. NTSTATUS ZwEnumerateKey(  
  2.   __in       HANDLE KeyHandle,  
  3.   __in       ULONG Index,  
  4.   __in       KEY_INFORMATION_CLASS KeyInformationClass,  
  5.   __out_opt  PVOID KeyInformation,  
  6.   __in       ULONG Length,  
  7.   __out      PULONG ResultLength  
  8. );  

參數說明 : 
* 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 函式) : 枚舉子項目
  1. #pragma INITCODE  
  2. VOID EnumerateSubItemRegTest()  
  3. {  
  4.     UNICODE_STRING RegUnicodeString;  
  5.     HANDLE hRegister;  
  6.   
  7.     //初始化UNICODE_STRING字串  
  8.     RtlInitUnicodeString( &RegUnicodeString,   
  9.         MY_REG_SOFTWARE_KEY_NAME);  
  10.       
  11.     OBJECT_ATTRIBUTES objectAttributes;  
  12.     //初始化objectAttributes  
  13.     InitializeObjectAttributes(&objectAttributes,  
  14.                             &RegUnicodeString,  
  15.                             OBJ_CASE_INSENSITIVE,//對大小寫敏感  
  16.                             NULL,   
  17.                             NULL );  
  18.     //打開登錄表  
  19.     NTSTATUS ntStatus = ZwOpenKey( &hRegister,  
  20.                             KEY_ALL_ACCESS,  
  21.                             &objectAttributes);  
  22.   
  23.     if (NT_SUCCESS(ntStatus))  
  24.     {  
  25.         KdPrint(("Open register successfully\n"));  
  26.     }  
  27.   
  28.     ULONG ulSize;  
  29.     //第一次呼叫ZwQueryKey為了獲取KEY_FULL_INFORMATION資料的長度  
  30.     ZwQueryKey(hRegister,  
  31.         KeyFullInformation,  
  32.         NULL,  
  33.         0,  
  34.         &ulSize);  
  35.   
  36.     PKEY_FULL_INFORMATION pfi =   
  37.         (PKEY_FULL_INFORMATION)  
  38.         ExAllocatePool(PagedPool,ulSize);  
  39.   
  40.     //第二次呼叫ZwQueryKey為了獲取KEY_FULL_INFORMATION資料的資料  
  41.     ZwQueryKey(hRegister,  
  42.         KeyFullInformation,  
  43.         pfi,  
  44.         ulSize,  
  45.         &ulSize);  
  46.   
  47.     for (ULONG i=0;iSubKeys;i++)  
  48.     {  
  49.         //第一次呼叫ZwEnumerateKey為了獲取KEY_BASIC_INFORMATION資料的長度  
  50.         ZwEnumerateKey(hRegister,  
  51.                 i,  
  52.                 KeyBasicInformation,  
  53.                 NULL,  
  54.                 0,  
  55.                 &ulSize);  
  56.   
  57.         PKEY_BASIC_INFORMATION pbi =  
  58.             (PKEY_BASIC_INFORMATION)  
  59.             ExAllocatePool(PagedPool,ulSize);  
  60.   
  61.         //第二次呼叫ZwEnumerateKey為了獲取KEY_BASIC_INFORMATION資料的資料  
  62.         ZwEnumerateKey(hRegister,  
  63.                 i,  
  64.                 KeyBasicInformation,  
  65.                 pbi,  
  66.                 ulSize,  
  67.                 &ulSize);  
  68.   
  69.         UNICODE_STRING uniKeyName;  
  70.         uniKeyName.Length =   
  71.         uniKeyName.MaximumLength =  
  72.         (USHORT)pbi->NameLength;  
  73.   
  74.         uniKeyName.Buffer = pbi->Name;  
  75.   
  76.         KdPrint(("The %d sub item name:%wZ\n",i,&uniKeyName));  
  77.   
  78.         ExFreePool(pbi);  
  79.     }  
  80.   
  81.     ExFreePool(pfi);  
  82.     ZwClose(hRegister);  
  83. }  

枚舉子鍵 : 
和枚舉子項類似, 枚舉子鍵是透過 ZwQueryKey  ZwEnumerateValueKey 兩個函式的配合完成的. ZwEnumerateValueKey 函式的使用和 ZwEnumberateKey 的函式使用類似. 下面例子演示如何在驅動程式中枚舉子鍵 : 
- Driver.cpp (EnumerateSubValueRegTest) : 枚舉子鍵
  1. #pragma INITCODE  
  2. VOID EnumerateSubValueRegTest()  
  3. {  
  4.     UNICODE_STRING RegUnicodeString;  
  5.     HANDLE hRegister;  
  6.   
  7.     //初始化UNICODE_STRING字串  
  8.     RtlInitUnicodeString( &RegUnicodeString,   
  9.         MY_REG_SOFTWARE_KEY_NAME);  
  10.       
  11.     OBJECT_ATTRIBUTES objectAttributes;  
  12.     //初始化objectAttributes  
  13.     InitializeObjectAttributes(&objectAttributes,  
  14.                             &RegUnicodeString,  
  15.                             OBJ_CASE_INSENSITIVE,//對大小寫敏感  
  16.                             NULL,   
  17.                             NULL );  
  18.     //打開登錄表  
  19.     NTSTATUS ntStatus = ZwOpenKey( &hRegister,  
  20.                             KEY_ALL_ACCESS,  
  21.                             &objectAttributes);  
  22.   
  23.     if (NT_SUCCESS(ntStatus))  
  24.     {  
  25.         KdPrint(("Open register successfully\n"));  
  26.     }  
  27.   
  28.     ULONG ulSize;  
  29.     ZwQueryKey(hRegister,  
  30.         KeyFullInformation,  
  31.         NULL,  
  32.         0,  
  33.         &ulSize);  
  34.   
  35.     PKEY_FULL_INFORMATION pfi =   
  36.         (PKEY_FULL_INFORMATION)  
  37.         ExAllocatePool(PagedPool,ulSize);  
  38.   
  39.     ZwQueryKey(hRegister,  
  40.         KeyFullInformation,  
  41.         pfi,  
  42.         ulSize,  
  43.         &ulSize);  
  44.   
  45.     for (ULONG i=0;iValues;i++)  
  46.     {  
  47.         ZwEnumerateValueKey(hRegister,  
  48.                 i,  
  49.                 KeyValueBasicInformation,  
  50.                 NULL,  
  51.                 0,  
  52.                 &ulSize);  
  53.   
  54.         PKEY_VALUE_BASIC_INFORMATION pvbi =  
  55.             (PKEY_VALUE_BASIC_INFORMATION)  
  56.             ExAllocatePool(PagedPool,ulSize);  
  57.   
  58.         ZwEnumerateValueKey(hRegister,  
  59.                 i,  
  60.                 KeyValueBasicInformation,  
  61.                 pvbi,  
  62.                 ulSize,  
  63.                 &ulSize);  
  64.   
  65.         UNICODE_STRING uniKeyName;  
  66.         uniKeyName.Length =   
  67.         uniKeyName.MaximumLength =  
  68.         (USHORT)pvbi->NameLength;  
  69.   
  70.         uniKeyName.Buffer = pvbi->Name;  
  71.   
  72.         KdPrint(("The %d sub value name:%wZ\n",i,&uniKeyName));  
  73.   
  74.         if (pvbi->Type==REG_SZ)  
  75.         {  
  76.             KdPrint(("The sub value type:REG_SZ\n"));  
  77.         }else if (pvbi->Type==REG_MULTI_SZ)  
  78.         {  
  79.             KdPrint(("The sub value type:REG_MULTI_SZ\n"));   
  80.   
  81.         }else if (pvbi->Type==REG_DWORD)  
  82.         {  
  83.             KdPrint(("The sub value type:REG_DWORD\n"));   
  84.         }else if (pvbi->Type==REG_BINARY)  
  85.         {  
  86.             KdPrint(("The sub value type:REG_BINARY\n"));   
  87.         }  
  88.   
  89.         ExFreePool(pvbi);  
  90.     }  
  91.   
  92.     ExFreePool(pfi);  
  93.     ZwClose(hRegister);  
  94. }  

刪除子項 : 
DDK 同樣提供了刪除子項的內核函式, 它就是 ZwDeleteKey. 其宣告如下 : 
- Syntax :
  1. NTSTATUS ZwDeleteKey(  
  2.   __in  HANDLE KeyHandle  
  3. );  

參數說明 : 
* KeyHandle : 打開的控制碼.

需要指出, 該函式只能刪除沒有子項的專案, 如果子項中還有子項, 則不能刪除. 這時候需要先將該項中的所有子項刪除後, 在刪除該項. 下面範例演式如何在驅動刪除子項 : 
- Driver.cpp (DeleteItemRegTest 函式) : 示範刪除子項
  1. #pragma INITCODE  
  2. VOID DeleteItemRegTest()  
  3. {  
  4.     UNICODE_STRING RegUnicodeString;  
  5.     HANDLE hRegister;  
  6.   
  7. #define MY_REG_SOFTWARE_KEY_NAME1 L"\\Registry\\Machine\\Software\\Zhangfan\\SubItem"  
  8.     //初始化UNICODE_STRING字串  
  9.     RtlInitUnicodeString( &RegUnicodeString,   
  10.         MY_REG_SOFTWARE_KEY_NAME1);  
  11.       
  12.     OBJECT_ATTRIBUTES objectAttributes;  
  13.     //初始化objectAttributes  
  14.     InitializeObjectAttributes(&objectAttributes,  
  15.                             &RegUnicodeString,  
  16.                             OBJ_CASE_INSENSITIVE,//對大小寫敏感  
  17.                             NULL,   
  18.                             NULL );  
  19.     //打開登錄表  
  20.     NTSTATUS ntStatus = ZwOpenKey( &hRegister,  
  21.                             KEY_ALL_ACCESS,  
  22.                             &objectAttributes);  
  23.   
  24.     if (NT_SUCCESS(ntStatus))  
  25.     {  
  26.         KdPrint(("Open register successfully\n"));  
  27.     }  
  28.   
  29.     ntStatus = ZwDeleteKey(hRegister);  
  30.     if (NT_SUCCESS(ntStatus))  
  31.     {  
  32.         KdPrint(("Delete the item successfully\n"));  
  33.     }else if(ntStatus == STATUS_ACCESS_DENIED)  
  34.     {  
  35.         KdPrint(("STATUS_ACCESS_DENIED\n"));  
  36.   
  37.     }else if(ntStatus == STATUS_INVALID_HANDLE)  
  38.     {  
  39.         KdPrint(("STATUS_INVALID_HANDLE\n"));  
  40.     }else  
  41.     {  
  42.         KdPrint(("Maybe the item has sub item to delete\n"));  
  43.     }  
  44.   
  45.     ZwClose(hRegister);  
  46. }  

其他 : 
以上介紹了部分核心模式下操作登錄表的函式, 使用方法都比較繁瑣, 往往一個操作需要若干個函式共同配合. 為了簡化登錄表操作, DDK 還提供一系列以 Rtl 開頭的執行時函式, 這些函式把前面介紹的函式進行封裝, 往往一條函式就能實現前面介紹若干函式的功能 : 
RtlCreateRegistryKey : 新建登錄表
RtlCheckRegistryKey : 查看某登錄表項是否存在
RtlWriteRegistryValue : 寫入登錄表
RtlDeleteRegistryValue : 刪除登錄表子鍵

上表列出了 Rtl 系列函式對登陸表操作功能, 下面程式碼演示了在驅動程式中如何使用這些函式, 可以看得出來其操作比 ZwXX 系列函式簡單得多 : 
- Driver.cpp (RtlRegTest) : 使用 Rtl 系列函式操作登錄表
  1. #pragma INITCODE  
  2. void RtlRegTest()  
  3. {  
  4.     //新建子項目  
  5.     NTSTATUS ntStatus =  
  6.         RtlCreateRegistryKey(RTL_REGISTRY_SERVICES,L"HelloDDK\\Zhangfan");  
  7.     if (NT_SUCCESS(ntStatus))  
  8.     {  
  9.         KdPrint(("Create the item successfully\n"));  
  10.     }  
  11.   
  12.     //檢查某項是否存在  
  13.     ntStatus =  
  14.         RtlCheckRegistryKey(RTL_REGISTRY_SERVICES,L"HelloDDK\\Zhangfan");  
  15.     if (NT_SUCCESS(ntStatus))  
  16.     {  
  17.         KdPrint(("The item is exist\n"));  
  18.     }  
  19.   
  20.     //寫入REG_DWORD的資料  
  21.     ULONG value1 = 100;  
  22.     ntStatus =   
  23.         RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,  
  24.                             L"HelloDDK\\Zhangfan",  
  25.                             L"DWORD_Value",  
  26.                             REG_DWORD,  
  27.                             &value1,  
  28.                             sizeof(value1));  
  29.     if (NT_SUCCESS(ntStatus))  
  30.     {  
  31.         KdPrint(("Write the DWORD value succuessfully\n"));  
  32.     }  
  33.   
  34.     PWCHAR szString = L"Hello DDK";  
  35.     ntStatus =   
  36.         RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,  
  37.                             L"HelloDDK\\Zhangfan",  
  38.                             L"SZ_Value",  
  39.                             REG_SZ,  
  40.                             szString,  
  41.                             wcslen(szString)*2+2);  
  42.   
  43.     if (NT_SUCCESS(ntStatus))  
  44.     {  
  45.         KdPrint(("Write the REG_SZ value succuessfully\n"));  
  46.     }  
  47.   
  48.     RTL_QUERY_REGISTRY_TABLE paramTable[2];  
  49.     RtlZeroMemory(paramTable, sizeof(paramTable));  
  50.   
  51.     ULONG defaultData=0;  
  52.     ULONG uQueryValue;  
  53.     paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;  
  54.     paramTable[0].Name = L"DWORD_Value";  
  55.     paramTable[0].EntryContext = &uQueryValue;  
  56.     paramTable[0].DefaultType = REG_DWORD;  
  57.     paramTable[0].DefaultData = &defaultData;  
  58.     paramTable[0].DefaultLength = sizeof(ULONG);  
  59.   
  60.     //查詢REG_DWORD的資料  
  61.     ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,  
  62.                         L"HelloDDK\\Zhangfan",  
  63.                         paramTable,  
  64.                         NULL,  
  65.                         NULL);  
  66.     if (NT_SUCCESS(ntStatus))  
  67.     {  
  68.         KdPrint(("Query the item successfully\n"));  
  69.         KdPrint(("The item is :%d\n",uQueryValue));  
  70.     }  
  71.       
  72.     //刪除子鍵  
  73.     ntStatus = RtlDeleteRegistryValue(RTL_REGISTRY_SERVICES,  
  74.                     L"HelloDDK\\Zhangfan",  
  75.                     L"DWORD_Value");  
  76.     if (NT_SUCCESS(ntStatus))  
  77.     {  
  78.         KdPrint(("delete the value successfully\n"));  
  79.     }  
  80. }  

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...