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驅動程式設計一書

DDK 檔案操作

//新建及打開檔案
//
ZwCreateFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);

typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

#pragma INITCODE
VOID CreateFileTest()
{
//新建檔案範例
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;
UNICODE_STRING logFileUnicodeString;

//初始化UNICODE_STRING字串
RtlInitUnicodeString( &logFileUnicodeString,
L"\\??\\C:\\test.log");
//或者寫成 "\\Device\\HarddiskVolume1\\test.LOG"


//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&logFileUnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );

//新建檔案
NTSTATUS ntStatus = ZwCreateFile( &hfile,
GENERIC_WRITE,
&objectAttributes,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF, //如果要讀取檔案,改成FILE_OPEN,如果不存在則返回錯誤
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0 );
if ( NT_SUCCESS(ntStatus))
{
KdPrint(("Create file succussfully!\n"));
}else
{
KdPrint(("Create file unsuccessfully!\n"));
}

//關閉檔案控制代碼
ZwClose(hfile);
}

===========================================================
可以使用較簡單的方式開啟檔案
ZwOpenFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
===========================================================
檔案屬性讀取及設定
ZwQueryInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);

ZwSetInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
);

FileInformationClass用來指定或查詢的類別
ex:FilePositionInformation,FileBasicInformation...

範例
FILE_STANDARD_INFORMATION fsi;
//讀取檔案長度
ntStatus = ZwQueryInformationFile(hfile,
&iostatus,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (NT_SUCCESS(ntStatus))
{
KdPrint(("file length:%u\n",fsi.EndOfFile.QuadPart));
}

//修改當前檔案指標
FILE_POSITION_INFORMATION fpi;
fpi.CurrentByteOffset.QuadPart = 100i64;
ntStatus = ZwSetInformationFile(hfile,
&iostatus,
&fpi,
sizeof(FILE_POSITION_INFORMATION),
FilePositionInformation);

===========================================================
FILE讀寫
ZwWriteFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL
);

ZwReadFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL
);

範例:
寫檔

OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;
UNICODE_STRING logFileUnicodeString;

//初始化UNICODE_STRING字串
RtlInitUnicodeString( &logFileUnicodeString,
L"\\??\\C:\\test.log");

//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
&logFileUnicodeString,
OBJ_CASE_INSENSITIVE,//對大小寫敏感
NULL,
NULL );

//新建檔案
NTSTATUS ntStatus = ZwCreateFile( &hfile,
GENERIC_WRITE,
&objectAttributes,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_WRITE,
FILE_OPEN_IF,//即使存在該檔案,也新建
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0 );
#define BUFFER_SIZE 1024
PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
//建構要填充的資料
RtlFillMemory(pBuffer,BUFFER_SIZE,0xAA);

KdPrint(("The program will write %d bytes\n",BUFFER_SIZE));
//寫入檔案
ZwWriteFile(hfile,NULL,NULL,NULL,&iostatus,pBuffer,BUFFER_SIZE,NULL,NULL);
KdPrint(("The program really wrote %d bytes\n",iostatus.Information));


//建構要填充的資料
RtlFillMemory(pBuffer,BUFFER_SIZE,0xBB);

KdPrint(("The program will append %d bytes\n",BUFFER_SIZE));
//追加資料
LARGE_INTEGER number;
number.QuadPart = 1024i64;//設置檔案指標
//對檔案進行附加寫
ZwWriteFile(hfile,NULL,NULL,NULL,&iostatus,pBuffer,BUFFER_SIZE,&number,NULL);
KdPrint(("The program really appended %d bytes\n",iostatus.Information));

//關閉檔案控制代碼
ZwClose(hfile);

ExFreePool(pBuffer);

讀檔與寫檔類似:
FILE_STANDARD_INFORMATION fsi;
//讀取檔案長度
ntStatus = ZwQueryInformationFile(hfile,
&iostatus,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);

KdPrint(("The program want to read %d bytes\n",fsi.EndOfFile.QuadPart));

//為讀取的檔案分配緩衝區
PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,
(LONG)fsi.EndOfFile.QuadPart);

//讀取檔案
ZwReadFile(hfile,NULL,
NULL,NULL,
&iostatus,
pBuffer,
(LONG)fsi.EndOfFile.QuadPart,
NULL,NULL);
KdPrint(("The program really read %d bytes\n",iostatus.Information));

DDK 字串處理

ASCII字串及寬字元
ANSI字元 char *str1 = "abc";
UNICODE wchar_t *str2 = L"abc";

DDK自訂字串
typedef struct _STRING {
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} STRING;
typedef STRING *PSTRING;

typedef STRING ANSI_STRING;
typedef PSTRING PANSI_STRING;
typedef STRING OEM_STRING;
typedef PSTRING POEM_STRING;

//初始字串
RtlInitAnsiString(PANSI_STRING DestinationString, PCSZ SourceString);
RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString);

//拷貝字串
RtlCopyString(PSTRING DestinationString, PSTRING SourceString);
RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString );

範例:
//初始化UnicodeString1
#define BUFFER_SIZE 1024
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1,L"Hello World");

//初始化UnicodeString2,因為有分配記憶體空間,最後要記得free
UNICODE_STRING UnicodeString2={0};
UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
UnicodeString2.MaximumLength = BUFFER_SIZE;

//將初始化UnicodeString2拷貝到UnicodeString1
RtlCopyUnicodeString(&UnicodeString2,&UnicodeString1);

//銷毀UnicodeString2
RtlFreeUnicodeString(&UnicodeString2);

==========================================================================
//字串比較
RtlCompareString(PSTRING String1, PSTRING String2, BOOLEAN CaseInSensitive);
RtlCompareUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive);

//轉成大寫 , AllocateDestinationString 是否為DestinationString分配記憶體
RtlUpperString(PSTRING DestinationString, PSTRING SourceString);
RtlUpcaseUnicodeString(PUNICODE_STRING DestinationString, PCUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString);

//ANSI_STRING UNICODE_STRING 字串互轉
RtlAnsiStringToUnicodeString(PUNICODE_STRING DestinationString,
PANSI_STRING SourceString,
BOOLEAN AllocateDestinationString
);
RtlUnicodeStringToAnsiString(PANSI_STRING DestinationString,
PUNICODE_STRING SourceString,
BOOLEAN AllocateDestinationString
);

2009年10月7日 星期三

DDk 記憶體複製、填充、比較

DDK提供以下的記憶體操作的function,也可以使用memcpy,memset等function
但為了保證程式碼可攜,要儘量使用標準的function

//記憶體比較
RtlEqualMemory(Destination,Source,Length);

//記憶體複製,可重疊
RtlMoveMemory(Destination,Source,Length);

//記憶體複製,不可重疊
RtlCopyMemory(Destination,Source,Length);

//記憶體填充
RtlFillMemory(Destination,Length,Fill);

//將記憶體清成0
RtlZeroMemory(Destination,Length);


範例
VOID RtlTest()
{
PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
//用零填充記憶體
RtlZeroMemory(pBuffer,BUFFER_SIZE);

PUCHAR pBuffer2 = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
//用固定位元組填充記憶體
RtlFillMemory(pBuffer2,BUFFER_SIZE,0xAA);

//記憶體拷貝
RtlCopyMemory(pBuffer,pBuffer2,BUFFER_SIZE);

//判斷記憶體是否一致
ULONG ulRet = RtlCompareMemory(pBuffer,pBuffer2,BUFFER_SIZE);
if (ulRet==BUFFER_SIZE)
{
KdPrint(("The two blocks are same.\n"));
}
}

DDK 記憶體配置及Linked-list處理

1.
分配Kernal記憶體
PVOID ExAllocatePool(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes);
PVOID ExAllocatePoolWithTag(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes, IN ULONG Tag);
PVOID ExAllocatePoolWithQuota(IN POOL_TYPE, IN SIZE_T);
PVOID ExAllocatePoolWithQuataTag(IN POOL_TYPE, IN SIZE_T, IN UNLONG);
釋放Kernal記憶體
VOID ExFreePool(IN PVOID P);
NTKERNELAPI VOID ExFreePoolWithTag(IN PVOID P, ULONG tag);

2.
Kernal使用link-list:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY* Flink;
struct _LIST_ENTRY* Blink;
} LIST_ENTRY, *PLIST_ENTRY;

判斷 linked-list是否為空
IsListEmpty(PLIST_ENTRY);

插入element至 linked-list
InsertHeadList(PLIST_ENTRY head, PLIST_ENTRY entry);
InsertTailList(PLIST_ENTRY tail, PLIST_ENTRY entry);

從linked-list刪除element
RemoveHeadList(PLIST_ENTRY)
RemoveTailList(PLIST_ENTRY)

將element轉換成自訂資料結構
CONTAINING_RECORD(address, type, field) ;
address:自訂資料結構的位址
type:自訂的資料結構
filed:自訂資料結構中的pEntry

範例:
typedef struct _MYDATASTRUCT
{
ULONG number;
LIST_ENTRY ListEntry;
} MYDATASTRUCT, *PMYDATASTRUCT;

#pragma INITCODE
VOID LinkListTest()
{
LIST_ENTRY linkListHead;
//初始化鏈表
InitializeListHead(&linkListHead);

MYDATASTRUCT *pData;
ULONG i = 0;
//在鏈表中插入10個元素
KdPrint(("Begin insert to link list"));
for (i=0 ; i<5 ; i++)
{
pData = (MYDATASTRUCT *)ExAllocatePool(PagedPool,sizeof(MYDATASTRUCT));
pData->number = i;
InsertTailList(&linkListHead,&pData->ListEntry);
}

KdPrint(("Begin remove from link list\n"));
while(!IsListEmpty(&linkListHead))
{
PLIST_ENTRY pEntry = RemoveTailList(&linkListHead);
pData = CONTAINING_RECORD(pEntry,
MYDATASTRUCT,
ListEntry);
KdPrint(("%d\n",pData->number));
ExFreePool(pData);
}
}

3.
Lookaside結構:
避免頻繁配置及釋放記憶體,產生記憶體破碎的情況
使用前先要初始化,非分頁及分頁兩種方式
ExInitializeNPagedLookasideList (
IN PNPAGED_LOOKASIDE_LIST Lookaside,
IN PALLOCATE_FUNCTION Allocate,
IN PFREE_FUNCTION Free,
IN ULONG Flags,
IN SIZE_T Size,
IN ULONG Tag,
IN USHORT Depth
);

ExInitializePagedLookasideList (
IN PPAGED_LOOKASIDE_LIST Lookaside,
IN PALLOCATE_FUNCTION Allocate,
IN PFREE_FUNCTION Free,
IN ULONG Flags,
IN SIZE_T Size,
IN ULONG Tag,
IN USHORT Depth
);

配置記憶體
PVOID ExAllocateFromNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST);
PVOIDExAllocateFromPagedLookasideList(IN PPAGED_LOOKASIDE_LIST);
釋放記憶體
VOID ExFreeToNPagedLookasideList(IN PNPAGED_LOOKASIDE, IN PVOID);
VOID ExFreeToPagedLookasideList(IN PPAGED_LOOKASIDE, IN PVOID);
使用完需要刪除Lookaside物件
VOID ExDeleteNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST);
VOID ExDeletePagedLookasideList(IN PPAGED_LOOKASIDE_LIST);

範例:
typedef struct _MYDATASTRUCT
{
CHAR buffer[64];
} MYDATASTRUCT, *PMYDATASTRUCT;

#pragma INITCODE
VOID LookasideTest()
{
PAGED_LOOKASIDE_LIST pageList;
ExInitializePagedLookasideList(&pageList,NULL,NULL,0,sizeof(MYDATASTRUCT),'1234',0);

#define ARRAY_NUMBER 50
PMYDATASTRUCT MyObjectArray[ARRAY_NUMBER];
for (int i=0;i {
MyObjectArray[i] = (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&pageList);
KdPrint(("Alloc MyObjectArray[%d]\n",i));
}

//模擬頻繁回收記憶體
for (i=0;i {
KdPrint(("Free MyObjectArray[%d]\n",i));
ExFreeToPagedLookasideList(&pageList,MyObjectArray[i]);

MyObjectArray[i] = NULL;

}

ExDeletePagedLookasideList(&pageList);
//刪除Lookaside物件
}

DDK 使用VC6開發

DDK版本是Windows Server 2003 Sp1 Ddk
專案名稱是 MyDriver
步驟
1.File->New->Project->Win32 Application->輸入專案名稱->An Empty project

2.將.c與.h加入到專案

3.Build->Configuration 去掉Debug,Release,增加Driver Check Edition

4.project->Setting->General中,Intermediate files與Output Files改成MyDriver_Check

5.project->Setting->C/C++->Project Options,全部刪除,改成
/nologo /Gz /MLd /W3 /WX /Z7 /Od /D WIN32=100 /D _X86_=1 /D WINVER=0x500 /D DBG=1 /Fo"MyDriver_Check/" /Fd"MyDriver_Check/" /FD /c

6.project->Setting->Link->Project Options,全部刪除,改成
ntoskrnl.lib /nologo /base:"0x10000" /stack:0x400000,0x1000 /entry:"DriverEntry" /subsystem:console /incremental:no /pdb:"DriverDev___Win32_Driver_Release_Edtion/HelloDDK.pdb" /map:"DriverDev___Win32_Driver_Release_Edtion/HelloDDK.map" /debug /machine:I386 /nodefaultlib /out:"MyDriver_Check/HelloDDK.sys" /pdbtype:sept /subsystem:native /driver /SECTION:INIT,D /RELEASE /IGNORE:4078

7.修改VC lib及Include目錄,Tool->Option->Directoies->Show Directories for:
->Include Files加入DDK路徑\INC\W2K 以及INC\DDK\W2K
->Library Files加入DDK路徑\LIB\W2K\I386

2009年10月6日 星期二

PDO與FDO

在WDM的架構當中,
PDO如何得知上層FDO
->透過AttachedDevice 子欄位
ex:
PDEVICE_OBJECT pDevice = pDriverObject->DeviceObject;
pDevice->AttachedDevice

FDO如何得知下層的裝置
->透過裝置擴充紀錄
ex:
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice;
UNICODE_STRING ustrDeviceName; // 裝置名
UNICODE_STRING ustrSymLinkName; // 符號連結名
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

winsock2.h redefined問題

解法: #define _WINSOCKAPI_    // stops windows.h including winsock.h #include #include