Registry in kernelmode

Hello everybody.

I successfully retrieved an integer from the registry using this function :

![](/uploads/db2714/original/1X/888851867a69ff9377ddca8f1383692bdf3c0931.png "")

But, the problem is that i cant figure out how to recover an unicode string stored as a REG_SZ into the registry, what i tried so far is this :

`UNICODE_STRING reg_QueryString(HANDLE hKey, UNICODE_STRING keyName)
{

PKEY_VALUE_PARTIAL_INFORMATION pkey_partial_info = nullptr;

UNICODE_STRING buffer;

ULONG length = 0;

NTSTATUS status = ZwQueryValueKey(hKey, &keyName, KeyValuePartialInformation, nullptr, length, &length);

if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW)
{
	pkey_partial_info = reinterpret_cast<PKEY_VALUE_PARTIAL_INFORMATION>(ExAllocatePoolWithTag(NonPagedPool, length, 'VHPi'));

	if (pkey_partial_info)
	{
		status = ZwQueryValueKey(hKey, &keyName, KeyValuePartialInformation, pkey_partial_info, length, &length);

		PCWSTR CHR = *(PCWSTR*)pkey_partial_info->Data; // SHOULD Recover the string stored into data

		RtlInitUnicodeString(&buffer, CHR); //Init the unicode string using the wstring recovered before

		ExFreePoolWithTag(pkey_partial_info, 'VHPi');
		return buffer;

	}
}

}`

Do any one have any infos on how to do it. Any help would be appreciated. Thanks :slight_smile:

KEY_VALUE_PARTIAL_INFORMATION::Data is not a pointer to the data, it IS the data, so to get at the string you need to simply cast it

PCWSTR CHR = (PCWSTR) pkey_partial_info->Data;

but you have bigger problems.

  1. the string that is returned is not guaranteed to be null terminated, so you must use the DataLength field to initialize the UNICODE_STRING structure
  2. you are not making a deep copy of the buffer with RtlInitUnicodeString, you are just copying the pointer value. You are freeing the pointer in the next line (ExFreePoolWithTag), so the pointer value in buffer (buffer::Buffer) is no longer valid.

IS there a reason you are not using WDF to query the registry value ? it will take care of everything for you and manage all the validation, buffer lifetime, etc correctly.

Hey, the reason i dont use wdf is because im in KMDF and, being a beginner in kernelmode, i thought that we cant use WDF functions in KMDF. A quick look into msdn and i found that we can, amazing :slight_smile: Thanks for the infos man.

KMDF is WDF (two names for the same thing). Or perhaps you are misusing the term KMDF to mean purely a kernel mode driver independent of programming model

Also, i proceed to use my WDF to create a key, but it constantly give me a BSoD with SYSTEM_THREAD_EXCEPTION_NOT_HANDLED and c0000005 (STATUS_ACCESS_VIOLATION)

But it dont seems like im doing anything wrong on my side, there is the code i used :

`WDFKEY WDF_CreateKey() {

UNICODE_STRING keyName;
RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\SOFTWARE\\KernelRetry");
WDFKEY key;

auto status = WdfRegistryCreateKey(NULL, &keyName, KEY_READ || KEY_WRITE, REG_OPTION_VOLATILE, NULL, WDF_NO_OBJECT_ATTRIBUTES, &key);

if (status == STATUS_INVALID_DEVICE_REQUEST) {

	DbgPrintEx(0, 0, "STATUS_INVALID_DEVICE_REQUEST on Create Key \n");

}
else if (status == STATUS_INVALID_PARAMETER) {

	DbgPrintEx(0, 0, "STATUS_INVALID_PARAMETER on Create Key \n");

}
else if(status == STATUS_INSUFFICIENT_RESOURCES){

	DbgPrintEx(0, 0, "STATUS_INSUFFICIENT_RESOURCES on Create Key\n");

}
else if (status == STATUS_ACCESS_DENIED) {

	DbgPrintEx(0, 0, "STATUS_ACCESS_DENIED on CreateKey \n");

}
else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {

	DbgPrintEx(0, 0, "STATUS_OBJECT_NAME_NOT_FOUND on CreateKey \n");

}
else if (status == STATUS_ACCESS_VIOLATION) {

	DbgPrintEx(0, 0, "STATUS_ACCESS_VIOLATION on CreateKey\n");

}

return key;

}`

Am i doing something wrong here ? Thanks.

Are you aware of the difference between KEY_READ || KEY_WRITE and KEY_READ | KEY_WRITE?

Hello, yes, it was a mistype my bad. I wanted to use KEY_READ | KEY_WRITE.

use of auto scares me, but at what point does the exception actually occur?

Hello, yes, it was a mistype my bad. I wanted to use KEY_READ | KEY_WRITE.

Yes, I know. Does it work when you fix that? KEY_READ || KEY_WRITE would result in the value “1” which, it turns out, is “KEY_QUERY_VALUE”.

Hello thanks for your responses. It still crashing but i think it might come from my call of the function. When they are asking for the keyName im setting it to this → L"\Registry\Machine\SOFTWARE\KernelRetry" . Maybe thats the reason why its crashing ?

Assuming the code you posted actually is your code, I don’t see a problem there. You used double backslashes in the string literal. Have you analyzed the dump? Are you absolutely sure the crash is coming from that call, or are you just guessing?

use of auto scares me,

Actually, the code sample in question is a pretty interesting example of the situation when using .c and .cpp file extensions interchangingly may play a really nasty trick on you…

If you write such code in a file with .cpp extension and compile it as C++11 code, the variable type is going to be automatically inferred from WdfRegistryCreateKey()'s return type, i.e. is going to be assumed of NTSTATUS type, and, hence, the code will work exactly the way it is meant to. So far, so good.

However, if you do it in a .c file and compile it as C89 code, the target variable’s type is going to be implicitly assumed as ‘int’,
i.e. as a signed type. It is understandable that a signed int will never ever be evaluated to 0xC0000xyz - instead, it will evaluate to a negative number every time the most significant bit is set. Therefore, no statement in the subsequent ‘if’ blocks has a slightest chance of ever getting executed, no matter what WdfRegistryCreateKey() returns…

Anton Bassov

Hello, i tried to execute the exact same function, the exact same code on another kmdf project. It worked, no crash and the key has been created. But on my actual project if i call this function it make my project crash and i have actually no clue of why since the code is the exact same

use windbg to get a clue