Kernel and driver registry

Keywords: Programming Attribute

Article directory

Registry operation

  • Similar to the way of application programming, the registry is a huge tree structure. Generally, the operation is to open a subkey. There are several values under the subkey that can be obtained. Each value has a name.
  • Subkey is generally represented by a path, which is different from application programming in that its writing method is different. In application programming, a handle to the root subkey is required, while in driver programming, all paths are required.
  • The following is a comparison table of root key handle and kernel registry path:
Subkey in application programming Corresponding path writing in driving
HKEY_LOCAL_MACHINE \Registry\Machine
HKEY_USERS \Registry\User
HKEY_CLASSES_ROOT No corresponding path
HKEY_CURRENT_USER There is no simple corresponding path, but it can be found

Commonly used API

Function name Effect
ZwCreateKey Create or open a key
ZwOpenKey Open a key
ZwQueryValueKey Read Key
ZwSetValueKey Write key value
ZwDeleteKey Delete Key
ZwDeleteValueKey Delete key values
ZwQueryKey Read key information
  • ZwOpenKey function is most commonly used in driver programming. The function prototype is as follows
NTATATUS ZwOptnKey(
	OUT PHANDLE KeyHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes
);
  • The function also requires an object "attributes structure pointer to be entered.
  • DesireAccess can be any combination of the following permissions:
value describe
KEY_QUERY_VALUE Read value under key
KEY_SET_VALUE Set value under key
KEY_CREATE_SUB_KEY Generate subkeys
KEY_ENUMERATE_SUB_KEYS Enumerating subkeys
KEY_READ For a combined macro, you can directly use the corresponding key? Write, key? All? Access

Basic operation

  • For the registry, it mainly implements three operations: open, read and write

Open:

  • ZwOpenKey()

Read:

  • ZwQueryValueKey()
NTSTATUS ZwQueryValueKey(
    IN HANDLE KeyHandle,	//Registry key handle
    IN PUNICODE_STRING ValueName,//The name of the value to read
    IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,	//Type of information to query
    OUT PVOID KeyValueInformation,
    IN ULONG Length,	//Enter the length of the space
    OUT PULONG Resultlength	//Return the actual required length
);
  • KeyValueInformationClass is an enumeration type. There are three types of information to query:
information Explain
KeyValueBasicInformation Get basic information, including value name and type
KeyValueFullInformation Get complete information, including the value name, type, and data for the value
KeyValuePartialInformation Get local information, data with types and values (most commonly used)
  • Of course, it can also be one of the following enumeration values:
typedef enum _KEY_INFORMATION_CLASS {
    KeyBasicInformation,
    KeyNodeInformation,
    KeyFullInformation,
    KeyNameInformation,
    KeyCachedInformation,
    KeyFlagsInformation,
    KeyVirtualizationInformation,
    KeyHandleTagsInformation,
    KeyTrustInformation,
    KeyLayerInformation,
    MaxKeyInfoClass  // MaxKeyInfoClass should always be the last enum
} KEY_INFORMATION_CLASS;
  • KeyValueInformation: when the KeyValueInformationClass value is KeyValuePartialInformation +, the key'value'partial'information 'structure will be returned to the memory that the pointer points to. The structure prototype is as follows:
typedef struct _KEY_VALUE_PARTIAL_INFORMATION(
    ULONG TitileIndex;	//Please ignore this member
    ULONG Type;			//data type
    ULONG DataLength;	//Data length
    UCHAR Data[1];		//Variable length data
)KEY_VALUE_PARTIAL_INFORMATION,*PKEY_VALUE_PARTIAL_INFORMATION;
  • Return value: if the actual Length required is greater than Length, STATUS_BUFFER_OVERFLOW-0x80000005 or STATUS_BUFFER_TOO_SMALL will be returned, and STATUS_SUCCESS. c will be returned successfully

write

  • ZwSetValueKey
  • It is relatively simple. It is better to write directly to the registry. The function prototype is as follows:
NTSTATUS ZwSetValueKey(
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING ValueName,
    IN ULONG TitileIndex OPTIONAL,
    IN ULONG Type,
    IN PVOID Data,
    IN ULONG DataSize
);
//Parameter interpretation:
//1. The two parameters KeyHandle and ValueName are the same as those in ZwQueryValueKey.
//2. Data and DataSize: data is the start address of the data to be written, and DataSize is the length of the data to be written. Data type is PVOID null pointer, so data can point to any data
  • Type can have the following types, see MSDN for details:
value Meaning
REG_BINARY Binary data of any form
REG_DWORD A four byte value
REG_LINK Named symbolic link Unicode string
REG_NONE There is no specific type of data
REG_SZ Null terminated Unicode string
  • When using this function, if the key value already exists, it will be overwritten. If it does not exist, a new key will be created.

Use of registry in driver

  • Function to open key
//Function to get a key
NTSTATUS MyZwOpenKey(PHANDLE hKey, PUNICODE_STRING pKeyPath)
{
	//Initialize object? Attribute
	OBJECT_ATTRIBUTES objAttribute = { 0 };
	InitializeObjectAttributes(&objAttribute, pKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
	//Open key
	NTSTATUS status = STATUS_SUCCESS;
	status = ZwOpenKey(hKey, KEY_READ, &objAttribute);
	return status;
}
  • Read Key
NTSTATUS MyZwQueryValueKey(HANDLE hKey,PUNICODE_STRING pKeyName)
{
	//Define an info to test the size of key value
	KEY_VALUE_PARTIAL_INFORMATION firstInfo;
	//Define a pointer to the actual info structure, and then dynamically request the heap space
	PKEY_VALUE_PARTIAL_INFORMATION pInfo;
	ULONG length = 0;
	NTSTATUS status = STATUS_SUCCESS;
	//Start reading
	status = ZwQueryValueKey(hKey, pKeyName,KeyValuePartialInformation, &firstInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION),
		&length);
	if (!NT_SUCCESS(status)&&status!=STATUS_BUFFER_OVERFLOW&&status!=STATUS_BUFFER_TOO_SMALL)
	{
		return status;
	}
	//Read successfully, apply for space, read again
	pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, length, 'tag1');
	status = ZwQueryValueKey(hKey, pKeyName, KeyValuePartialInformation, pInfo, length, &length);
	if (!NT_SUCCESS(status))
	{
		return status;
	}
	UNICODE_STRING strInfo;
	RtlInitUnicodeString(&strInfo, pInfo->Data);
	//Output key name
	KdPrint(("The value of the key is:%wZ\n", &strInfo));
	ExFreePool(pInfo);
	return status;
}
  • Write key value
//Write key value
NTSTATUS MyZwSetValueKey(HANDLE hKey,PUNICODE_STRING pKeyName, PUNICODE_STRING pKeyValue)
{
	NTSTATUS status = STATUS_SUCCESS;
	status = ZwSetValueKey(hKey, pKeyName, 0, REG_SZ, pKeyValue->Buffer, pKeyValue->Length);
	return status;
}

Advanced operations - traverse registry

  • Enumerating subkeys using function ZwQueryKey ZwEnumerateKey
//Enumerate all children
VOID MyZwEnumAllKey(HANDLE hKey)
{
	NTSTATUS status = STATUS_SUCCESS;
	//Use function ZwQueryKey to get the number of children
	ULONG size = 0;
	ZwQueryKey(hKey,KeyFullInformation, NULL, 0, &size);
	PKEY_FULL_INFORMATION pInfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag2');
	ZwQueryKey(hKey, KeyFullInformation, pInfo, size, &size);
	__try {
		//Traversal by key field subKeys
		for (ULONG i = 0; i < pInfo->SubKeys; i++)
		{
			//ZwEnumerateKey to enumerate subitems
			ZwEnumerateKey(hKey, i, KeyBasicInformation, NULL, 0, &size);
			PKEY_BASIC_INFORMATION pBasicInfo = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag3');
			ZwEnumerateKey(hKey, i, KeyBasicInformation, pBasicInfo, size, &size);
			//Print traversal information
			UNICODE_STRING	keyName;
			//It can't be initialized directly, which will cause garbled code
			//RtlInitUnicodeString(&keyName, pBasicInfo->Name);
			keyName.Length = keyName.MaximumLength = pBasicInfo->NameLength;
			keyName.Buffer = pBasicInfo->Name;
			KdPrint(("The first %d Name of item : %wZ\n", i, &keyName));
			//Free heap space
			ExFreePool(pBasicInfo);
		}
		ExFreePool(pInfo);
	}
	__except (EXCEPTION_EXECUTE_HANDLER){}
}
  • Enumerating subkeys with ZwQueryKey and ZwEnumerateValueKey functions
//Enumerate all subkeys under corresponding item
VOID MyZwEnumAllValueKey(HANDLE hKey)
{
	ULONG size = 0;
	//Number of subkeys obtained
	ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &size);
	if (size<=0)
	{
		return;
	}
	PKEY_FULL_INFORMATION pInfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag4');
	ZwQueryKey(hKey, KeyFullInformation, pInfo, size, &size);
	__try {
		//Enumerate all subkeys
		for (ULONG i = 0; i < pInfo->Values; i++)
		{
			//Get size first
			ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, NULL, 0, &size);
			PKEY_VALUE_BASIC_INFORMATION pValueInfo = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, size, 'tag5');
			ZwEnumerateValueKey(hKey, i, KeyValueBasicInformation, pValueInfo, size, &size);
			//Print information
			UNICODE_STRING valueKeyName;
			valueKeyName.Length = valueKeyName.MaximumLength = pValueInfo->NameLength;
			valueKeyName.Buffer = pValueInfo->Name;
			KdPrint(("The first %d Subkey name is: %wZ \n", i, &valueKeyName));
			ExFreePool(pValueInfo);
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {}
	ExFreePool(pInfo);
}
Published 9 original articles, won praise 0, visited 58
Private letter follow

Posted by littlevisuals on Fri, 14 Feb 2020 01:53:35 -0800