DDK开发
要在Windows下开发驱动程序,最直接的方法就是用免费的WDK(Windows Driver
Kit)。但是WDK只提供了命令行下运行的编译和链接工具,并没有IDE,这样对于那些用贯了Visual C++的开发者会来说有些不方便。
要把WDK集成到Visual C++里,要对项目进行如下设置:
1 - 新建一个DLL项目,把驱动程序的源代码都添加到项目中,打开项目的属性页对话框。
2 - 展开“C/C++”文件夹。
3 - 单击“常规”属性页,在“附加包含目录”框中追加WDK的头文件目录路径。 4 - 单击“预处理器”属性页,在“预处理器”框中追加一个指定目标平台的宏,可以是“_X86_”、“_AMD64_”和“_IA64_”之一。
5 - 单击“高级”属性页,在“调用约定”栏中选择“__stdcall”。 6 - 单击“命令行”属性页,在“附加选项”框中加入“/X”以忽略Visual C++全局的头文件包含路径。
7 - 展开“链接器”文件夹。
8 - 单击“常规”属性页,在“附加包含目录”框中追加和目标平台相关的WDK库文件目录路径。
9 - 单击“输入”属性页,在“附加依赖项”框中输入“ntoskrnl.lib ntstrsafe.lib hal.lib BufferOverflowK.lib”;在“忽略所有默认库”栏中
选择“是”。
10 - 单击“系统”属性页,在“子系统”栏中选择“本机”。 11 - 单击“高级”属性页,在“入口点”框中输入“DriverEntry”;在“目标计算机”栏中选择一个和目标平台匹配的值。
经过这些步骤,就可以直接用Visual C++编译和生成驱动程序了,DDK(Driver Development Kit)的集成方法也大致相同
DDK常用函数与数据结构描述
Support Function and Data Structure Reference
ASSERT
ASSERTMSG
CM_FULL_RESOURCE_DESCRIPTOR
CM_PARTIAL_RESOURCE_DESCRIPTOR
CM_PARTIAL_RESOURCE_LIST
CM_RESOURCE_LIST
CONFIGURATION_INFORMATION
CONTAINING_RECORD
CONTROLLER_OBJECT
DbgBreakPoint
DbgPrint
DEVICE_DESCRIPTION
DEVICE_OBJECT
DriverEntry
DRIVER_OBJECT
ExAcquireFastMutex
ExAcquireFastMutexUnsafe ExAcquireResourceExclusiveLite ExAcquireResourceSharedLite ExAcquireSharedStarveExclusive ExAcquireSharedWaitForExclusive
ExAllocateFromNPagedLookasideList
ExAllocateFromPagedLookasideList ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithQuotaTag ExAllocatePoolWithTag
ExConvertExclusiveToSharedLite ExDeleteNPagedLookasideList ExDeletePagedLookasideList ExDeleteResourceLite
ExFreePool
ExFreeToNPagedLookasideList ExFreeToPagedLookasideList ExGetCurrentResourceThread ExInitializeFastMutex
ExInitializeNPagedLookasideList ExInitializePagedLookasideList ExInitializeResourceLite ExInitializeWorkItem
ExInterlockedInsertHeadList ExInterlockedInsertTailList ExInterlockedRemoveHeadList ExIsResourceAcquiredExclusiveLite ExIsResourceAcquiredSharedLite ExQueueWorkItem
ExReleaseFastMutex
ExReleaseFastMutexUnsafe ExReleaseResourceForThreadLite ExTryToAcquireFastMutex
ExTryToAcquireResourceExclusiveLite HalAssignSlotResources
HalGetAdapter
HalGetBusData
HalGetBusDataByOffset
HalGetInterruptVector
HalSetBusData
HalSetBusDataByOffset
HalTranslateBusAddress HKEY_LOCAL_MACHINE
InitializeListHead
InitializeObjectAttributes InsertHeadList
InsertTailList
INTERFACE_TYPE
InterlockedDecrement
InterlockedExchange
InterlockedExchangeAdd InterlockedIncrement
IoAcquireCancelSpinLock IoAllocateAdapterChannel IoAllocateController
IoAllocateErrorLogEntry IoAllocateIrp
IoAllocateMdl
IoAssignResources
IoAttachDevice
IoAttachDeviceToDeviceStack IoBuildAsynchronousFsdRequest IoBuildDeviceIoControlRequest IoBuildPartialMdl
IoBuildSynchronousFSDRequest IoCallDriver
IoCancelIrp
IoCompleteRequest
IoConnectInterrupt
IoCopyCurrentIrpStackLocationToNext
IoCreateController
IoCreateDevice
IoCreateNotificationEvent IoCreateSymbolicLink
IoCreateSynchronizationEvent IoDeleteController
IoDeleteDevice
IoDeleteSymbolicLink
IoDetachDevice
IoDisconnectInterrupt IO_ERROR_LOG_PACKET
IoFlushAdapterBuffers IoFreeAdapterChannel
IoFreeController
IoFreeIrp
IoFreeMapRegisters
IoFreeMdl
IoGetConfiguationInformation IoGetCurrentIrpStackLocation IoGetCurrentProcess
IoGetDeviceObjectPointer IoGetNextIrpStackLocation
IoInitializeDpcRequest
IoInitializeIrp
IoInitializeTimer
IoMakeAssociatedIrp
IoMapTransfer
IoMarkIrpPending
IoRegisterShutdownNotification IoReleaseCancelSpinLock IoRequestDpc
IO_RESOURCE_DESCRIPTOR IO_RESOURCE_LIST
IO_RESOURCE_REQUIREMENTS_LIST IoSetCancelRoutine
IoSetCompletionRoutine IoSetNextIrpStackLocation IoSizeOfIrp
IoSkipCurrentIrpStackLocation IO_STACK_LOCATION
IoStartNextPacket
IoStartNextPacketByKey IoStartPacket
IoStartTimer
IO_STATUS_BLOCK
IoStopTimer
IoUnregisterShutdownNotification IoWriteErrorLogEntry
IsListEmpty
IRP
KdPrint
KeAcquireSpinLock
KeAcquireSpinLockAtDpcLevel KeBugCheck
KeBugCheckEx
KeCancelTimer
KeClearEvent
KeDelayExecutionThread KeDeregisterBugCheckCallback
KeFlushIoBuffers
KeGetCurrentIrql
KeGetCurrentProcessorNumber KeGetDcacheFillSize KeInitializeCallbackRecord KeInitializeDeviceQueue KeInitializeDpc
KeInitializeEvent
KeInitializeMutex
KeInitializeSemaphore KeInitializeSpinLock KeInitializeTimer
KeInitializeTimerEx KeInsertByKeyDeviceQueue KeInsertDeviceQueue KeInsertQueueDpc
KeLowerIrql
KeNumberProcessors
KeQueryPerformanceCounter KeQuerySystemTime
KeQueryTickCount
KeQueryTimeIncrement KeRaiseIrql
KeReadStateEvent
KeReadStateMutex
KeReadStateSemaphore KeReadStateTimer
KeRegisterBugCheckCallback KeReleaseMutex
KeReleaseSemaphore
KeReleaseSpinLock
KeReleaseSpinLockFromDpcLevel KeRemoveByKeyDeviceQueue KeRemoveDeviceQueue KeRemoveEntryDeviceQueue KeRemoveQueueDpc
KeResetEvent
KeSetEvent
KeSetPriorityThread KeSetTimer
KeSetTimerEx
KeStallExecutionProcessor KeSynchronizeExecution KeWaitForMultipleObjects
KeWaitForMutexObject KeWaitForSingleObject KEY_BASIC_INFORMATION KEY_FULL_INFORMATION KEY_NODE_INFORMATION KEY_VALUE_BASIC_INFORMATION KEY_VALUE_FULL_INFORMATION
KEY_VALUE_PARTIAL_INFORMATION
KIRQL
KSYNCHRONIZE_ROUTINE LARGE_INTEGER
MmAllocateContiguousMemory MmAllocateNonCachedMemory MmCreateMdl
MmFreeContiguousMemory MmFreeNonCachedMemory MmGetMdlByteCount
MmGetMdlByteOffset
MmGetMdlVirtualAddress MmGetPhysicalAddress MmGetSystemAddressForMdl MmInitializeMdl
MmIsAddressValid
MmMapIoSpace
MmMapLockedPages
MmPrepareMdlForReuse MmProbeAndLockPages
MmQuerySystemSize
MmSizeOfMdl
MmUnlockPages
MmUnlockPagableImageSection MmUnmapIoSpace
MmUnmapLockedPages
NTSTATUS
ObDereferenceObject
ObReferenceObjectByHandle ObReferenceObjectByPointer PCI_COMMON_CONFIG
PCI_SLOT_NUMBER
PDRIVER_CONTROL
PIO_DPC_ROUTINE
PIO_TIMER_ROUTINE
PKDEFERRED_ROUTINE
PKSTART_ROUTINE
PsCreateSystemThread
PsGetCurrentProcess
PsGetCurrentThread
PsTerminateSystemThread READ_PORT_BUFFER_type
READ_PORT_type
READ_REGISTER_BUFFER_type
READ_REGISTER_type
RemoveEntryList
RemoveHeadList
RemoveTailList
RtlInitUnicodeString
RtlMoveMemory
RTL_QUERY_REGISTRY_ROUTINE RTL_QUERY_REGISTRY_TABLE RtlQueryRegistryValues RtlUnicodeStringToAnsiString RtlZeroMemory
UNICODE_STRING
_URB_CONTROL_DESCRIPTOR_REQUEST _URB_HEADER
UsbBuildGetDescriptorRequest WRITE_PORT_BUFFER_type WRITE_PORT_type
WRITE_REGISTER_BUFFER_type WRITE_REGISTER_type
ZwClose
ZwCreateFile
ZwCreateKey
ZwDeleteKey
ZwEnumerateKey
ZwEnumerateValueKey
ZwFlushKey
ZwMapViewOfSection
ZwOpenKey
ZwOpenSection
ZwQueryKey
ZwQueryValueKey
ZwSetInformationThread ZwSetValueKey
ZwUnmapViewOfSection
1 首先在vc6里面设置ddk的include和lib路径,要安装好一个ddk,以前安装好的也可
以,只要ddk目录还在就可以了,这里假设ddk目录是F:\WINDDK
那么该目录下还会有子目录,一般2660是xp的ddk,3790是win2003的sdk,随便用一种都无所谓。
在vc6里面,Tools --> Option -->Directoriers里面设置
Include路径
F:\WINDDK\3790\inc\wnet
F:\WINDDK\3790\INC\DDK\WNET
LIB路径
F:\WINDDK\3790\LIB\WNET\I386
DDK的路径要放到最先
这些设置好了,就可以开始下一步了。有时候,你还需要用到最新的SDK,那么请同样把sdk目录添加进去,sdk应该在ddk后面,不过一般无所谓
2 用vc新建一个工程,选择Windows的空的工程,然后添加一个cpp文件,内容如下:
extern "C"
{
#include
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING
pRegistryPath)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
UNICODE_STRING usDriverName, usDosDeviceName;
DbgPrint("DriverEntry Called \r\n");
RtlInitUnicodeString(&usDriverName, L"\\Device\\Example");
RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\Example");
DbgPrint("%S",usDriverName);
return NtStatus;
}
这里需要用到 extern "C" 才包含 ntddk.h,为什么呢,因为,如果不这样做,在cpp文件中,默认以为 DbgPrint 这些函数是c++规则的,那么就导致错误
unresolved external symbol "unsigned long __cdecl DbgPrint(char *,...)"
(?DbgPrint@@YAKPADZZ)
3 这时候直接编译,那么就会有错误
f:\winddk\3790\inc\ddk\wnet\ntddk.h(11545) : error C2146: syntax error : missing ';' before
identifier 'ContextRecord'
f:\winddk\3790\inc\ddk\wnet\ntddk.h(11545) : error C2501: 'PCONTEXT' : missing storage-class or type specifiers
f:\winddk\3790\inc\ddk\wnet\ntddk.h(11545) : error C2501: 'ContextRecord' : missing
storage-class or type specifiers
f:\winddk\3790\inc\ddk\wnet\ntddk.h(12331) : fatal error C1189: #error : "no target
architecture"
因为,没有定义任何的ddk的目标体系,这时候,需要在 C++设置Preprocessor definitions
里面,添加 预定义_X86_,当然,你也可以在cpp Include ntddk.h 文件之前这样定义
#define _X86_
4 继续编译,错误为:
DriverMain.obj : error LNK2001: unresolved external symbol __imp__RtlInitUnicodeString@8
DriverMain.obj : error LNK2001: unresolved external symbol _DbgPrint LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16
这时候需要在link --> Object/library Modules去掉全部默认的lib,添加 ntoskrnl.lib并且在
Output里面更改Base Address为0x10000、Entry-point symbol为DriverEntry
并且把/subsystem:windows 改为 /subsystem:native
5 保存,编译,还有一个错误
DriverMain.obj : error LNK2001: unresolved external symbol __chkesp
这个需要在C++选项下面,把/GZ 这个参数删除,默认下,debug模式,vc6会添加这个
选项。我们不需要函数调用返回时对esp进行错误检查,可以去掉这个选项
6 编译通过了,但是还是需要修改一下,首先输出的是.sys而不应该是.exe,这个可以到link
选项下修改
我们还可以添加一个编译选项 /driver 或者/DRIVER:WDM 有或者 /DRIVER:UP (这个选
项表明,该驱动不能用于多处理器环境)
7 还有一点应该修改的是C++ --> Code Generation -->Calling convention:修改为
__stdcall 并且C++ Language里面把所有特性都去掉,什么 exception handling以及
Enable Run-Time Type Inform去掉
并且由于这个是驱动,所以Debug Info应该使用C7 Compatible,这样可以让softice调试
驱动可以载入符号
并且link选项,应该把Link incrementally去掉,Debug Info应该选择 Both formats以
保证各种调试器的兼容性。
8现在就可以正确编译了,不过还有以下错误,无法更正
F:\WINDDK\3790\inc\wnet\ntdef.h(963) : warning C4163: '_rotl64' : not available as an intrinsic function
F:\WINDDK\3790\inc\wnet\ntdef.h(965) : warning C4163: '_rotr64' : not available as an intrinsic function
F:\WINDDK\3790\INC\DDK\WNET\ntddk.h(7423) : warning C4035:
'InterlockedExchange' : no return value
F:\WINDDK\3790\INC\DDK\WNET\ntddk.h(7477) : warning C4035:
'InterlockedExchangeAdd' : no return value
F:\WINDDK\3790\INC\DDK\WNET\ntddk.h(7508) : warning C4035:
'InterlockedCompareExchange' : no return value
F:\WINDDK\3790\INC\DDK\WNET\ntddk.h(7723) : warning C4163: '_ReadWriteBarrier' : not available as an intrinsic function
查了一下,没有找到解决方法,好像不影响驱动,就不管它了