我需要从注册表(最好)或文件中读取设置。该驱动程序是一个内核驱动程序,启动类型设置为
SYSTEM
,因此所有服务和 WinAPI 不一定可用。
我正在尝试使用
RtlQueryRegistryValues
函数来从注册表中读取单个字符串值,但无论我做什么,我似乎都会得到相同的 0xC0000034
错误代码,并将其转换为 STATUS_OBJECT_NAME_NOT_FOUND
。
根据 MSDN 上提供的文档,当路径参数与有效密钥不匹配,或者设置了特定标志并且不满足该标志的特定条件时,从
STATUS_OBJECT_NAME_NOT_FOUND
返回 RtlQueryRegistryValues
。据我所知,注册表项实际上存在于我的测试机器中,并且我没有使用 RTL_QUERY_REGISTRY_REQUIRED
标志。
我尝试读取的注册表值位于
HKEY_LOCAL_MACHINE/SOFTWARE/company/ProjectName
下,我尝试读取默认值和名为 parameter
的 REG_SZ 值。对 RtlQueryRegistryValues
的调用是在加载驱动程序的 DriverEntry(...) 阶段执行的。
我不知道我做错了什么,而且由于我是内核驱动程序的新手,并且调试过程非常繁琐,我不确定我是否只是错误地引用了注册表值或注册表在系统启动的这个阶段是否可用。
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
函数,因此您无需对其进行硬编码。
另请参阅:设备和驱动程序的注册表树和密钥。
您可以使用传递到
RegistryPath
的 DriverEntry
,如下所示:
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
。
根据文档,它还需要设置
RTL_QUERY_REGISTRY_TYPECHECK
标志。
RTL_QUERY_REGISTRY_TYPECHECK
标志又需要设置DefaultType
和DefaultSize
(PKEY_VALUE_FULL_INFORMATION
)。至少这是我发现的,这不是根据文档。