[英]Reading registry from windows kernel driver in C
I need to read settings from the registry (preferably) or from a file.我需要从注册表(最好)或文件中读取设置。 The driver is a kernel driver that is set to start with type of start set to SYSTEM
, so all services and WinAPIs are not necessarily available.该驱动程序是一个 kernel 驱动程序,它设置为启动类型设置为SYSTEM
,因此所有服务和 WinAPI 不一定可用。
I'm attempting to use the RtlQueryRegistryValues
function in order to read a single String value from the registry, but whatever I do I seem to get the same 0xC0000034
error code back which translate to STATUS_OBJECT_NAME_NOT_FOUND
.我正在尝试使用RtlQueryRegistryValues
function 从注册表中读取单个字符串值,但无论我做什么,我似乎都得到了相同的0xC0000034
错误代码,它转换为STATUS_OBJECT_NAME_NOT_FOUND
。
According to the documentation available at MSDN STATUS_OBJECT_NAME_NOT_FOUND
is returned from RtlQueryRegistryValues
when the path parameter does not match a valid key, or a specific flag is set and conditions specific to that flag is not met.根据 MSDN 上提供的文档,当路径参数与有效键不匹配,或者设置了特定标志并且不满足特定于该标志的条件时,从RtlQueryRegistryValues
返回STATUS_OBJECT_NAME_NOT_FOUND
。 As far as I can tell the registry keys are actually present in my test machine and I'm not using the RTL_QUERY_REGISTRY_REQUIRED
flag.据我所知,注册表项实际上存在于我的测试机器中,并且我没有使用RTL_QUERY_REGISTRY_REQUIRED
标志。
The registry values I'm attempting to read is located under HKEY_LOCAL_MACHINE/SOFTWARE/company/ProjectName
, I'm attempting to read both the default value and a REG_SZ value named parameter
.我试图读取的注册表值位于HKEY_LOCAL_MACHINE/SOFTWARE/company/ProjectName
下,我正在尝试读取默认值和名为parameter
的 REG_SZ 值。 The call to RtlQueryRegistryValues
is performed during the DriverEntry(...) stage of loading the driver.在加载驱动程序的 DriverEntry(...) 阶段执行对RtlQueryRegistryValues
的调用。
I can't figure out what it is that I'm doing wrong, and since I'm new to kernel drivers and the debugging process is quite tedious I'm not sure whether or not I just refer to the registry values incorrectly or if the registry is available at all during this stage of the system boot.我不知道我做错了什么,因为我是 kernel 驱动程序的新手,调试过程非常繁琐,我不确定我是否只是错误地引用了注册表值,或者是否在系统启动的这个阶段,注册表是完全可用的。
mydriver.c 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);
}
I'm not 100% sure but I suspect the registry hive for the Software subtree is just not loaded.我不是 100% 确定,但我怀疑软件子树的注册表配置单元没有加载。 Why are you trying to access it anyway?你为什么要尝试访问它? The proper place for driver config parameters is its own registry key ( \\Registry\\Machine\\System\\CurrentControlSet\\Services\\<DriverName>\\
) and the path to it is even passed to your DriverEntry
function so you don't need to hardcode it.驱动程序配置参数的正确位置是它自己的注册表项( \\Registry\\Machine\\System\\CurrentControlSet\\Services\\<DriverName>\\
),它的路径甚至会传递给您的DriverEntry
函数,因此您无需对其进行硬编码.
See also: Registry Trees and Keys for Devices and Drivers .另请参阅: 设备和驱动程序的注册表树和键。
You could use the RegistryPath
passed into DriverEntry
like so:您可以像这样使用传递给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;
}
In my example I'm reading an ULONG
but it could be anything, the idea is that the address of what you're trying to read is at the address pKeyInfo + pKeyInfo->DataOffset
.在我的示例中,我正在读取ULONG
但它可以是任何内容,想法是您尝试读取的地址位于地址pKeyInfo + pKeyInfo->DataOffset
。
Looks like the problem is with RTL_QUERY_REGISTRY_DIRECT.看起来问题出在 RTL_QUERY_REGISTRY_DIRECT 上。 According to documentation ( https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlqueryregistryvalues ) it requires RTL_QUERY_REGISTRY_TYPECHECK flag set as well.根据文档( https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlqueryregistryvalues ),它还需要设置 RTL_QUERY_REGISTRY_TYPECHECK 标志。 Flag RTL_QUERY_REGISTRY_TYPECHECK, in turn, requires DefaultType and DefaultSize (of PKEY_VALUE_FULL_INFORMATION) set.反过来,标志 RTL_QUERY_REGISTRY_TYPECHECK 需要设置 DefaultType 和 DefaultSize(属于 PKEY_VALUE_FULL_INFORMATION)。 At least that is what I've found which is not according to documentation.至少那是我发现的不符合文档的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.