[英]Reading registry from windows kernel driver in C
我需要從注冊表(最好)或文件中讀取設置。 該驅動程序是一個 kernel 驅動程序,它設置為啟動類型設置為SYSTEM
,因此所有服務和 WinAPI 不一定可用。
我正在嘗試使用RtlQueryRegistryValues
function 從注冊表中讀取單個字符串值,但無論我做什么,我似乎都得到了相同的0xC0000034
錯誤代碼,它轉換為STATUS_OBJECT_NAME_NOT_FOUND
。
根據 MSDN 上提供的文檔,當路徑參數與有效鍵不匹配,或者設置了特定標志並且不滿足特定於該標志的條件時,從RtlQueryRegistryValues
返回STATUS_OBJECT_NAME_NOT_FOUND
。 據我所知,注冊表項實際上存在於我的測試機器中,並且我沒有使用RTL_QUERY_REGISTRY_REQUIRED
標志。
我試圖讀取的注冊表值位於HKEY_LOCAL_MACHINE/SOFTWARE/company/ProjectName
下,我正在嘗試讀取默認值和名為parameter
的 REG_SZ 值。 在加載驅動程序的 DriverEntry(...) 階段執行對RtlQueryRegistryValues
的調用。
我不知道我做錯了什么,因為我是 kernel 驅動程序的新手,調試過程非常繁瑣,我不確定我是否只是錯誤地引用了注冊表值,或者是否在系統啟動的這個階段,注冊表是完全可用的。
mydriver.c
NTSTATUS DriverEntry(...) {
NTSTATUS regStatus = 0;
UNICODE_STRING data;
RTL_QUERY_REGISTRY_TABLE query[2];
WCHAR* regPath = L"\\Registry\\Machine\\SOFTWARE\\Company\\ProjectName";
RtlZeroMemory(query, sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
data.Buffer = NULL;
data.MaximumLength = 0;
data.Length = 0;
// query[0].Name = L"Parameter";
query[0].Name = L""; // L"" refers to the default value
query[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
query[0].EntryContext = &data;
regStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, regPath, query, NULL, NULL);
DebugPrint("regStatus: %lx\n", regStatus);
DebugPrint("data: %wZ\n", &data);
}
我不是 100% 確定,但我懷疑軟件子樹的注冊表配置單元沒有加載。 你為什么要嘗試訪問它? 驅動程序配置參數的正確位置是它自己的注冊表項( \\Registry\\Machine\\System\\CurrentControlSet\\Services\\<DriverName>\\
),它的路徑甚至會傳遞給您的DriverEntry
函數,因此您無需對其進行硬編碼.
另請參閱: 設備和驅動程序的注冊表樹和鍵。
您可以像這樣使用傳遞給DriverEntry
的RegistryPath
:
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
// ...
NTSTATUS ntStatus = STATUS_SUCCESS;
UNICODE_STRING valueName = RTL_CONSTANT_STRING(L"<YOUR_VALUE_NAME>");
HANDLE hRegistryKey;
PKEY_VALUE_FULL_INFORMATION pKeyInfo = nullptr;
// Create object attributes for registry key querying
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
do {
ntStatus = ZwOpenKey(&hRegistryKey, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(ntStatus)) {
KdPrint((DRIVER_PREFIX "Registry key open failed (0x%08X)\n", ntStatus));
break;
}
ULONG ulKeyInfoSize;
ULONG ulKeyInfoSizeNeeded = GetKeyInfoSize(hRegistryKey, &valueName);
if (ulKeyInfoSizeNeeded == 0) {
KdPrint((DRIVER_PREFIX "Value not found\n"));
break;
}
ulKeyInfoSize = ulKeyInfoSizeNeeded;
pKeyInfo = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, ulKeyInfoSize, DRIVER_TAG);
if (pKeyInfo == nullptr) {
KdPrint((DRIVER_PREFIX "Could not allocate memory for KeyValueInfo\n"));
break;
}
RtlZeroMemory(pKeyInfo, ulKeyInfoSize);
ntStatus = ZwQueryValueKey(hRegistryKey, &valueName, KeyValueFullInformation, pKeyInfo, ulKeyInfoSize, &ulKeyInfoSizeNeeded);
if (!NT_SUCCESS(ntStatus) || ulKeyInfoSize != ulKeyInfoSizeNeeded) {
KdPrint((DRIVER_PREFIX "Registry value querying failed (0x%08X)\n", ntStatus));
break;
}
// your data
ULONG someLong = *(ULONG*)((ULONG_PTR)pKeyInfo + pKeyInfo->DataOffset);
} while (false);
// cleanup
if (hRegistryKey) {
ZwClose(hRegistryKey);
}
if (pKeyInfo) {
ExFreePoolWithTag(pKeyInfo, DRIVER_TAG);
}
if (!NT_SUCCESS(ntStatus)) {
// Here you can set a default data if something failed it the way
}
// ...
}
ULONG GetKeyInfoSize(HANDLE hRegistryKey, PUNICODE_STRING pValueName) {
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG ulKeyInfoSizeNeeded;
ntStatus = ZwQueryValueKey(hRegistryKey, pValueName, KeyValueFullInformation, 0, 0, &ulKeyInfoSizeNeeded);
if (ntStatus == STATUS_BUFFER_TOO_SMALL || ntStatus == STATUS_BUFFER_OVERFLOW) {
// Expected don't worry - when ZwQueryValueKey fails with one of the above statuses, it returns the size needed
return ulKeyInfoSizeNeeded;
}
else {
KdPrint((DRIVER_PREFIX "Could not get key info size (0x%08X)\n", ntStatus));
}
return 0;
}
在我的示例中,我正在讀取ULONG
但它可以是任何內容,想法是您嘗試讀取的地址位於地址pKeyInfo + pKeyInfo->DataOffset
。
看起來問題出在 RTL_QUERY_REGISTRY_DIRECT 上。 根據文檔( https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlqueryregistryvalues ),它還需要設置 RTL_QUERY_REGISTRY_TYPECHECK 標志。 反過來,標志 RTL_QUERY_REGISTRY_TYPECHECK 需要設置 DefaultType 和 DefaultSize(屬於 PKEY_VALUE_FULL_INFORMATION)。 至少那是我發現的不符合文檔的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.