今天在trace serial port driver,使用sscom去連結COM port的時候,
sscom在對COM寫入的時候會發出IRP_MJ_WRITE,
接著driver去記錄WRITE資料的長度,
sscom不知道做了什麼事,
driver會收到 IOCTL_SERIAL_GET_COMMSTATUS,
再將WRITE資料的長度傳回來,
我利用CSerial去做overlapped的時候,可以產生與sscom一樣的Irp,
唯獨 IOCTL_SERIAL_GET_COMMSTATUS不知道是用了什麼WIN32 API,
後來總算查到了,是使用 ClearCommError
在CSerial當中,加入一段code,就可以使用
//app:
DWORD dwBytesRead = 0;
int count = serial.GetLength ();
if (count >0)
lLastError = serial.Read(szBuffer,count,&dwBytesRead);
//CSerial
int CSerial::GetLength (void)
{
DWORD dwErrors = 0;
COMSTAT ComStat;
if (!::ClearCommError(m_hFile,&dwErrors,&ComStat))
{
m_lLastError = ::GetLastError();
return -1;
}
return (int)ComStat.cbInQue ;
}
2009年10月15日 星期四
DDK 連結錯誤
記錄一下今天遇到的錯誤及解決方式
利用VC開發driver的時候,
發生了連結錯誤的訊息,
Driver.obj : error LNK2001: unresolved external symbol __imp_@KfReleaseSpinLock@8
Driver.obj : error LNK2001: unresolved external symbol __imp_@KfAcquireSpinLock@4
Driver.obj : error LNK2001: unresolved external symbol __imp__KeGetCurrentIrql@0
主要是使用了KeReleaseSpinLock,KeAcquireSpinLock等等的function,
在link的時候因為找不到lib而產生錯誤,
解決方式:在 Project Settings->Link->object/library modules加入
NT式: 加入hal.lib
WDM: 加入wdm.lib
結論:
用VC開發Driver的時候,
如果是NT式的,一開始就先加入hal.lib與ntoskrnl.lib
如果是WDM式的,就加入wdm.lib
利用VC開發driver的時候,
發生了連結錯誤的訊息,
Driver.obj : error LNK2001: unresolved external symbol __imp_@KfReleaseSpinLock@8
Driver.obj : error LNK2001: unresolved external symbol __imp_@KfAcquireSpinLock@4
Driver.obj : error LNK2001: unresolved external symbol __imp__KeGetCurrentIrql@0
主要是使用了KeReleaseSpinLock,KeAcquireSpinLock等等的function,
在link的時候因為找不到lib而產生錯誤,
解決方式:在 Project Settings->Link->object/library modules加入
NT式: 加入hal.lib
WDM: 加入wdm.lib
結論:
用VC開發Driver的時候,
如果是NT式的,一開始就先加入hal.lib與ntoskrnl.lib
如果是WDM式的,就加入wdm.lib
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驅動程式設計一書
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;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;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));
//
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
);
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"));
}
}
但為了保證程式碼可攜,要儘量使用標準的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物件
}
分配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
專案名稱是 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);
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);
訂閱:
文章 (Atom)
winsock2.h redefined問題
解法: #define _WINSOCKAPI_ // stops windows.h including winsock.h #include #include
-
昨天要回新竹的路上,差點A到一臺摩托車, 可以清楚看到路口是綠燈,可是這位老兄,竟然從左方過來要待轉, 旁邊的女騎士也差點A到他,尖叫了一聲... 緊急煞車的同時,第一次感受到ABS做動,還好平安無事... 奉勸大家車子一定要裝行車記錄器阿~
-
對了,要跟大家推薦一下新竹的家具行, 當初要添購家具的時候,跟小丸子很努力的找遍新竹的家具行, 新竹市的家具行其實很多,大部分集中在新竹市的經國路, 還有中華路五段這兩個部分,竹北也有不少家具行, 不過我們主要還是找新竹市的, 找來找去,發現其實家具很多都是一模一樣的,應該都...
-
前陣子收到大潤發寄來的DM,有一份全部都是在賣機車的, 現在的機車真的是滿貴的,但也發現一台檔車超帥的, 跟了我10幾年的YAMAHA風光雖然還不至於要報廢的階段, 但還是忍不住想完成年輕時的夢想, 所以,也就有了這篇文章, 在買檔車之前,也survey了幾台國產的...