簡體   English   中英

從 C 中的 windows kernel 驅動程序讀取注冊表

[英]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函數,因此您無需對其進行硬編碼.

另請參閱: 設備和驅動程序的注冊表樹和鍵

您可以像這樣使用傳遞給DriverEntryRegistryPath

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM