Windows Driver Model

ZwQueryValueKey()使用方式


相較於RtlQueryRegistryValues()的使用方式,Zw相關的Registry API使用方式會比較貼近User Application的寫法,都會有Open、Query、Close這三個步驟,但是,比較麻煩的是Query還有分Basic、Full、Partial三種取得資料的方式。

副程式:

NTSTATUS GetRegistryValue(PCWSTR pwcsValueName, ULONG *pReturnLength, UCHAR *pucReturnBuffer, PWSTR pRegistryPath)
{
  HANDLE hKey;
  ULONG ulLength=0;
  NTSTATUS status;
  OBJECT_ATTRIBUTES stObjAttr;
  WCHAR wszKeyBuffer[255]={0};
  UNICODE_STRING usKeyPath;
  UNICODE_STRING valueName;
  KEY_VALUE_PARTIAL_INFORMATION stKeyInfo;
  PKEY_VALUE_PARTIAL_INFORMATION pstKeyInfo;

  RtlInitUnicodeString(&valueName, pwcsValueName);
  usKeyPath.Buffer = wszKeyBuffer;
  usKeyPath.MaximumLength = sizeof(wszKeyBuffer);
  usKeyPath.Length = 0;
  status = RtlUnicodeStringPrintf(&usKeyPath, pRegistryPath);
  if(!NT_SUCCESS(status)){
    return status; 
  }

  InitializeObjectAttributes(&stObjAttr, &usKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
  status = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &stObjAttr);
  if(!NT_SUCCESS(status)){
    return status; 
  }

  ulLength = 0;
  status = ZwQueryValueKey(hKey, &valueName, KeyValuePartialInformation, &stKeyInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION), &ulLength);
  if(!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)){
    ZwClose(hKey);
    return status; 
  }

  pstKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, ulLength, '1gaT');
  if(pstKeyInfo == NULL){
    ZwClose(hKey);
    return status; 
  }

  status = ZwQueryValueKey(hKey, &valueName, KeyValuePartialInformation, pstKeyInfo, ulLength, &ulLength);
  if(NT_SUCCESS(status)){
    *pReturnLength = pstKeyInfo->DataLength;
    RtlCopyMemory(pucReturnBuffer, pstKeyInfo->Data, pstKeyInfo->DataLength);
  }
  ExFreePool(pstKeyInfo);
  ZwClose(hKey);
  return STATUS_SUCCESS;
}

上面這一段程式可以當成參考程式,使用者可以好好利用。該程式首先開啟Key位置,接著Query相關Value,目前司徒使用Partial的方式,其它兩種(Basic、Full)也都可以使用,而Query的方式也有另一種用途,那就是偵測實際需要的Buffer Size,如果使用者無法確定要讀取的Value需要多大的Buffer,可以使用司徒目前的做法,傳入0(ulLength)去取得需要的Buffer Size,然後再根據此Size動態配置記憶體,比較特別要注意的是,Query會自動將Value Type儲存在KEY_VALUE_PARTIAL_INFORMATION的變數中,因此,使用者就不需要再去查詢或固定Value的型態,當然,REG_DWORD、REG_BINARY、REG_SZ等型態都適用,當Query完之後,記得使用Close方式關閉。

呼叫範例:

ULONG ulLength;
UCHAR aucTemp[255]={0};

status = GetRegistryValue(L"Temp", &ulLength, &aucTemp, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\firstWDM\\Parameters\\");
if(status != STATUS_SUCCESS){
  DbgPrint("GetRegistryValue Failed: 0x%X\n", status);
}
else{
  DbgPrint("GetRegistryValue Length: %d\n", ulLength);
  DbgPrint("GetRegistryValue Value: Byte0:0x%X, Byte1:0x%X\n", aucTemp[0], aucTemp[1]);
}

上面的範例是取得Key(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\firstWDM\\Parameters\\")下的Temp數值(REG_BINARY)。


返回上一頁