2009年10月9日 星期五

DDK 登錄表操作

//新建登錄表
NTSTATUS ZwCreateKey(
OUT PHANDLE KeyHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG TitleIndex,
IN PUNICODE_STRING Class OPTIONAL,
IN ULONG CreateOptions,
OUT PULONG Disposition OPTIONAL
);

範例
#define MY_REG_SOFTWARE_KEY_NAME L"\\Registry\\Machine\\Software\\Inaba"
#pragma INITCODE
VOID CreateRegTest()
{
//新建或打開某登錄表項目
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;

//初始化UNICODE_STRING字串
RtlInitUnicodeString( &RegUnicodeString,
MY_REG_SOFTWARE_KEY_NAME);

OBJECT_ATTRIBUTES objectAttributes;
//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,//對大小寫敏感
NULL,
NULL );
ULONG ulResult;
//新建或帶開登錄表項目
NTSTATUS ntStatus = ZwCreateKey( &hRegister,
KEY_ALL_ACCESS,
&objectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
&ulResult);

if (NT_SUCCESS(ntStatus))
{
//判斷是被新新建,還是已經被新建
if(ulResult==REG_CREATED_NEW_KEY)
{
KdPrint(("The register item is created\n"));
}else if(ulResult==REG_OPENED_EXISTING_KEY)
{
KdPrint(("The register item has been created,and now is opened\n"));
}
}

//(2)新建或打開某登錄表項目的子項
UNICODE_STRING subRegUnicodeString;
HANDLE hSubRegister;

//初始化UNICODE_STRING字串
RtlInitUnicodeString( &subRegUnicodeString,
L"SubItem");

OBJECT_ATTRIBUTES subObjectAttributes;
//初始化subObjectAttributes
InitializeObjectAttributes(&subObjectAttributes,
&subRegUnicodeString,
OBJ_CASE_INSENSITIVE,//對大小寫敏感
hRegister, //附屬在MY_REG_SOFTWARE_KEY_NAME之下
NULL );
//新建或帶開登錄表項目
ntStatus = ZwCreateKey( &hSubRegister,
KEY_ALL_ACCESS,
&subObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
&ulResult);

if (NT_SUCCESS(ntStatus))
{
//判斷是被新建,還是已經被新建
if(ulResult==REG_CREATED_NEW_KEY)
{
KdPrint(("The sub register item is created\n"));
}else if(ulResult==REG_OPENED_EXISTING_KEY)
{
KdPrint(("The sub register item has been created,and now is opened\n"));
}
}

//關閉登錄表控制碼
ZwClose(hRegister);
ZwClose(hSubRegister);
}

=============================================================
另外有一種較為簡單的方式開啟登錄表
NTSTATUS ZwOpenKey(
OUT PHANDLE KeyHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);

=============================================================
增加或修改Key Value
NTSTATUS ZwSetValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName,
IN ULONG TitleIndex OPTIONAL,
IN ULONG Type,
IN PVOID Data,
IN ULONG DataSize
);

範例:

UNICODE_STRING ValueName;
//初始化ValueName
RtlInitUnicodeString( &ValueName, L"REG_DWORD value");

//設置REG_DWORD子鍵
ULONG ulValue = 1000;
ZwSetValueKey(hRegister,
&ValueName,
0,
REG_DWORD,
&ulValue,
sizeof(ulValue));

=============================================================
查詢登錄表
NTSTATUS ZwQueryValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);

//範例:
#pragma INITCODE
VOID QueryRegTest()
{
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;

//初始化UNICODE_STRING字串
RtlInitUnicodeString( &RegUnicodeString,
MY_REG_SOFTWARE_KEY_NAME);

OBJECT_ATTRIBUTES objectAttributes;
//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,//對大小寫敏感
NULL,
NULL );
//打開登錄表
NTSTATUS ntStatus = ZwOpenKey( &hRegister,
KEY_ALL_ACCESS,
&objectAttributes);

if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully\n"));
}

UNICODE_STRING ValueName;
//初始化ValueName
RtlInitUnicodeString( &ValueName, L"REG_DWORD value");

//讀取REG_DWORD子鍵
ULONG ulSize;
ntStatus = ZwQueryValueKey(hRegister,
&ValueName,
KeyValuePartialInformation ,
NULL,
0,
&ulSize);

if (ntStatus==STATUS_OBJECT_NAME_NOT_FOUND || ulSize==0)
{
ZwClose(hRegister);
KdPrint(("The item is not exist\n"));
return;
}
PKEY_VALUE_PARTIAL_INFORMATION pvpi =
(PKEY_VALUE_PARTIAL_INFORMATION)
ExAllocatePool(PagedPool,ulSize);

ntStatus = ZwQueryValueKey(hRegister,
&ValueName,
KeyValuePartialInformation ,
pvpi,
ulSize,
&ulSize);
if (!NT_SUCCESS(ntStatus))
{
ZwClose(hRegister);
KdPrint(("Read regsiter error\n"));
return;
}
//判斷是否為REG_DWORD類型
if (pvpi->Type==REG_DWORD && pvpi->DataLength==sizeof(ULONG))
{
PULONG pulValue = (PULONG) pvpi->Data;
KdPrint(("The value:%d\n",*pulValue));
}

ExFreePool(pvpi);
ZwClose(hRegister);
}

=============================================================
列舉SubItem
NTSTATUS ZwQueryKey(
IN HANDLE KeyHandle,
IN KEY_INFORMATION_CLASS KeyInformationClass,
OUT PVOID KeyInformation,
IN ULONG Length,
OUT PULONG ResultLength
);

NTSTATUS ZwEnumerateKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_INFORMATION_CLASS KeyInformationClass,
OUT PVOID KeyInformation,
IN ULONG Length,
OUT PULONG ResultLength
);

流程:
1. 呼叫ZwQueryKey,獲取KEY_FULL_INFORMATION資料的長度
2. 再次呼叫ZwQueryKey,獲取KEY_FULL_INFORMATION資料的資料
3. 呼叫ZwEnumerateKey,獲取KEY_BASIC_INFORMATION資料的長度
4. 利用迴圈呼叫ZwEnumerateKey,獲取KEY_BASIC_INFORMATION的資料

範例:
#pragma INITCODE
VOID EnumerateSubItemRegTest()
{
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;

//初始化UNICODE_STRING字串
RtlInitUnicodeString( &RegUnicodeString,
MY_REG_SOFTWARE_KEY_NAME);

OBJECT_ATTRIBUTES objectAttributes;
//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,//對大小寫敏感
NULL,
NULL );
//打開登錄表
NTSTATUS ntStatus = ZwOpenKey( &hRegister,
KEY_ALL_ACCESS,
&objectAttributes);

if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully\n"));
}

ULONG ulSize;
//第一次呼叫ZwQueryKey為了獲取KEY_FULL_INFORMATION資料的長度
ZwQueryKey(hRegister,
KeyFullInformation,
NULL,
0,
&ulSize);

PKEY_FULL_INFORMATION pfi =
(PKEY_FULL_INFORMATION)
ExAllocatePool(PagedPool,ulSize);

//第二次呼叫ZwQueryKey為了獲取KEY_FULL_INFORMATION資料的資料
ZwQueryKey(hRegister,
KeyFullInformation,
pfi,
ulSize,
&ulSize);

for (ULONG i=0;iSubKeys;i++)
{
//第一次呼叫ZwEnumerateKey為了獲取KEY_BASIC_INFORMATION資料的長度
ZwEnumerateKey(hRegister,
i,
KeyBasicInformation,
NULL,
0,
&ulSize);

PKEY_BASIC_INFORMATION pbi =
(PKEY_BASIC_INFORMATION)
ExAllocatePool(PagedPool,ulSize);

//第二次呼叫ZwEnumerateKey為了獲取KEY_BASIC_INFORMATION資料的資料
ZwEnumerateKey(hRegister,
i,
KeyBasicInformation,
pbi,
ulSize,
&ulSize);

UNICODE_STRING uniKeyName;
uniKeyName.Length =
uniKeyName.MaximumLength =
(USHORT)pbi->NameLength;

uniKeyName.Buffer = pbi->Name;

KdPrint(("The %d sub item name:%wZ\n",i,&uniKeyName));

ExFreePool(pbi);
}

ExFreePool(pfi);
ZwClose(hRegister);
}

=============================================================
列舉SubKey

NTSTATUS ZwEnumerateValueKey(
IN HANDLE KeyHandle,
IN ULONG Index,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);

流程與列舉SubItem類似
1. 呼叫ZwQueryKey,獲取KEY_FULL_INFORMATION資料的長度
2. 再次呼叫ZwQueryKey,獲取KEY_FULL_INFORMATION資料的資料
3. 呼叫ZwEnumerateValueKey,獲取KEY_BASIC_INFORMATION資料的長度
4. 利用迴圈,呼叫ZwEnumerateValueKey,獲取KEY_BASIC_INFORMATION的資料

範例:(只列出ZwEnumerateValueKey部分)
for (ULONG i=0;iValues;i++)
{
ZwEnumerateValueKey(hRegister,
i,
KeyValueBasicInformation,
NULL,
0,
&ulSize);

PKEY_VALUE_BASIC_INFORMATION pvbi =
(PKEY_VALUE_BASIC_INFORMATION)
ExAllocatePool(PagedPool,ulSize);

ZwEnumerateValueKey(hRegister,
i,
KeyValueBasicInformation,
pvbi,
ulSize,
&ulSize);

UNICODE_STRING uniKeyName;
uniKeyName.Length =
uniKeyName.MaximumLength =
(USHORT)pvbi->NameLength;

uniKeyName.Buffer = pvbi->Name;

KdPrint(("The %d sub value name:%wZ\n",i,&uniKeyName));

if (pvbi->Type==REG_SZ)
{
KdPrint(("The sub value type:REG_SZ\n"));
}else if (pvbi->Type==REG_MULTI_SZ)
{
KdPrint(("The sub value type:REG_MULTI_SZ\n"));

}else if (pvbi->Type==REG_DWORD)
{
KdPrint(("The sub value type:REG_DWORD\n"));
}else if (pvbi->Type==REG_BINARY)
{
KdPrint(("The sub value type:REG_BINARY\n"));
}

ExFreePool(pvbi);
}

=============================================================
刪除SubItem
NTSTATUS ZwDeleteKey(
IN HANDLE KeyHandle
);

刪除SubItem的時候,需要將該SubItem中所有的子項刪除,才能刪除該SubItem

範例
#pragma INITCODE
VOID DeleteItemRegTest()
{
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;

#define MY_REG_SOFTWARE_KEY_NAME1 L"\\Registry\\Machine\\Software\\Inaba"
//初始化UNICODE_STRING字串
RtlInitUnicodeString( &RegUnicodeString,
MY_REG_SOFTWARE_KEY_NAME1);

OBJECT_ATTRIBUTES objectAttributes;
//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&RegUnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
//打開登錄表
NTSTATUS ntStatus = ZwOpenKey( &hRegister,
KEY_ALL_ACCESS,
&objectAttributes);

if (NT_SUCCESS(ntStatus))
{
KdPrint(("Open register successfully\n"));
}

ntStatus = ZwDeleteKey(hRegister);
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Delete the item successfully\n"));
}else if(ntStatus == STATUS_ACCESS_DENIED)
{
KdPrint(("STATUS_ACCESS_DENIED\n"));

}else if(ntStatus == STATUS_INVALID_HANDLE)
{
KdPrint(("STATUS_INVALID_HANDLE\n"));
}else
{
KdPrint(("Maybe the item has sub item to delete\n"));
}

ZwClose(hRegister);
}

=============================================================
DDK提供一些簡單的function把上面介紹的function包了一層

//新建登錄表
NTSTATUS RtlCreateRegistryKey(
IN ULONG RelativeTo,
IN PWSTR Path
);

//確認登錄表是否存在
NTSTATUS RtlCheckRegistryKey(
IN ULONG RelativeTo,
IN PWSTR Path
);

//寫入登錄表
NTSTATUS
RtlWriteRegistryValue(
IN ULONG RelativeTo,
IN PCWSTR Path,
IN PCWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength
);

//刪除
NTSTATUS RtlDeleteRegistryValue(
IN ULONG RelativeTo,
IN PCWSTR Path,
IN PCWSTR ValueName
);

//查詢登錄表
NTSTATUS RtlQueryRegistryValues(
IN ULONG RelativeTo,
IN PCWSTR Path,
IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
IN PVOID Context,
IN PVOID Environment OPTIONAL
);

範例
#pragma INITCODE
void RtlRegTest()
{
//新建子項目
NTSTATUS ntStatus =
RtlCreateRegistryKey(RTL_REGISTRY_SERVICES,L"HelloDDK\\Inaba");
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Create the item successfully\n"));
}

//檢查某項是否存在
ntStatus =
RtlCheckRegistryKey(RTL_REGISTRY_SERVICES,L"HelloDDK\\Zhangfan");
if (NT_SUCCESS(ntStatus))
{
KdPrint(("The item is exist\n"));
}

//寫入REG_DWORD的資料
ULONG value1 = 100;
ntStatus =
RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
L"HelloDDK\\Zhangfan",
L"DWORD_Value",
REG_DWORD,
&value1,
sizeof(value1));
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Write the DWORD value succuessfully\n"));
}

RTL_QUERY_REGISTRY_TABLE paramTable[2];
RtlZeroMemory(paramTable, sizeof(paramTable));

ULONG defaultData=0;
ULONG uQueryValue;
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
paramTable[0].Name = L"DWORD_Value";
paramTable[0].EntryContext = &uQueryValue;
paramTable[0].DefaultType = REG_DWORD;
paramTable[0].DefaultData = &defaultData;
paramTable[0].DefaultLength = sizeof(ULONG);

//查詢REG_DWORD的資料
ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
L"HelloDDK\\Inaba",
paramTable,
NULL,
NULL);
if (NT_SUCCESS(ntStatus))
{
KdPrint(("Query the item successfully\n"));
KdPrint(("The item is :%d\n",uQueryValue));
}

//刪除子鍵
ntStatus = RtlDeleteRegistryValue(RTL_REGISTRY_SERVICES,
L"HelloDDK\\Inaba",
L"DWORD_Value");
if (NT_SUCCESS(ntStatus))
{
KdPrint(("delete the value successfully\n"));
}
}

以上範例,出自Windows Device Driver Progrmaing驅動程式設計一書

沒有留言 :