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:
Read:
NTSTATUS ZwQueryValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG Resultlength
);
-
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
} 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;
ULONG Type;
ULONG DataLength;
UCHAR Data[1];
)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
);
- 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
NTSTATUS MyZwOpenKey(PHANDLE hKey, PUNICODE_STRING pKeyPath)
{
OBJECT_ATTRIBUTES objAttribute = { 0 };
InitializeObjectAttributes(&objAttribute, pKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
NTSTATUS status = STATUS_SUCCESS;
status = ZwOpenKey(hKey, KEY_READ, &objAttribute);
return status;
}
NTSTATUS MyZwQueryValueKey(HANDLE hKey,PUNICODE_STRING pKeyName)
{
KEY_VALUE_PARTIAL_INFORMATION firstInfo;
PKEY_VALUE_PARTIAL_INFORMATION pInfo;
ULONG length = 0;
NTSTATUS status = STATUS_SUCCESS;
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;
}
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);
KdPrint(("The value of the key is:%wZ\n", &strInfo));
ExFreePool(pInfo);
return status;
}
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
VOID MyZwEnumAllKey(HANDLE hKey)
{
NTSTATUS status = STATUS_SUCCESS;
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 {
for (ULONG i = 0; i < pInfo->SubKeys; i++)
{
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);
UNICODE_STRING keyName;
keyName.Length = keyName.MaximumLength = pBasicInfo->NameLength;
keyName.Buffer = pBasicInfo->Name;
KdPrint(("The first %d Name of item : %wZ\n", i, &keyName));
ExFreePool(pBasicInfo);
}
ExFreePool(pInfo);
}
__except (EXCEPTION_EXECUTE_HANDLER){}
}
- Enumerating subkeys with ZwQueryKey and ZwEnumerateValueKey functions
VOID MyZwEnumAllValueKey(HANDLE hKey)
{
ULONG size = 0;
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 {
for (ULONG i = 0; i < pInfo->Values; i++)
{
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);
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);
}