1.驱动对象(DRIVER_OBJECT)
typedef struct _DRIVER_OBJECT
{
SHORT Type;
SHORT Size;
PDEVICE_OBJECT DeviceObject; //每个驱动会有一个或多个设备对象,此处指向第一个设备对象,通过它可以遍历驱动对象里的所有设备
ULONG Flags;
PVOID DriverStart; //从这两个属性可以得到驱动加载的区域
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName; //驱动的名字
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
LONG * DriverInit;
PVOID DriverStartIo;
PVOID DriverUnload;
LONG * MajorFunction[28]; //记录的是一个函数指针数组,每一个函数就是IRP的派遣函数
} DRIVER_OBJECT, *PDRIVER_OBJECT;
2.设备对象(DEVICE_OBJECT)
typedef struct _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject; //指向驱动中的驱动对象
struct _DEVICE_OBJECT *NextDevice; //指向下一个设备对象,这里指的是属于同一驱动的若干设备的下一个
struct _DEVICE_OBJECT *AttachedDevice; //如果有更高一层的驱动附加到这个驱动的时候,AttachedDevice指的就是更高一层的驱动
struct _IRP *CurrentIrp;
PIO_TIMER Timer;
ULONG Flags;
ULONG Characteristics; //设备的扩展对象,每个都会指定一个设备扩展对象记录自己定义的特殊结构体
__volatile PVPB Vpb;
PVOID DeviceExtension;
DEVICE_TYPE DeviceType; //设备的类型
CCHAR StackSize; //多层驱动情况下,驱动与驱动之间会形成类似堆栈的结构,IRP会一次从最高层传递到最底层,StackSize描述的就是这个层数
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc;
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION * DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT, *PDEVICE_OBJECT;
3.NT驱动 DriverUnload例程中遍历设备删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload\n")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } |
4.用WinObj观察驱动对象和设备对象
5.用DeviceTree观察驱动对象和设备对象
6.在WDM模型中,完成一个设备的操作,至少有两个设备对象共同完成。其中,一个是物理设备对象(PDO),另一个是功能设备对象(FDO).
当一个FDO附加在PDO上的时候,PDO设备对象的子域AttachedDevice会记录FDO的位置。PDO被称作底层驱动或者下层驱动,而FDO被称作高层驱动或者上层驱动。
这是最简单的一种情况,事实要比这个更加复杂。在FDO和FDO之间还会存在过滤驱动,在FDO上面的过滤驱动被称作上层过滤驱动,在FDO下层的驱动被称为下层过滤驱动。
7.NT驱动是主要加载设备的,也就是驱动一旦加载就创建设备。而WDM驱动是被动加载设备的,操作系统必须加载PDO以后,调用驱动的AddDevice例程,AddDevice例程中负责创建FDO,并且附加到PDO之上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | /************************************************************************ * 函数名称:HelloWDMAddDevice * 功能描述:添加新设备 * 参数列表: DriverObject:从I/O管理器中传进来的驱动对象 PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象 * 返回 值:返回添加新设备状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { PAGED_CODE(); KdPrint(("Enter HelloWDMAddDevice\n")); NTSTATUS status; PDEVICE_OBJECT fdo; UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\\Device\\MyWDMDevice"); status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); if( !NT_SUCCESS(status)) return status; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; pdx->fdo = fdo; pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\\DosDevices\\HelloWDM"); pdx->ustrDeviceName = devName; pdx->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName); if( !NT_SUCCESS(status)) { IoDeleteSymbolicLink(&pdx->ustrSymLinkName); status = IoCreateSymbolicLink(&symLinkName,&devName); if( !NT_SUCCESS(status)) { return status; } } fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; fdo->Flags &= ~DO_DEVICE_INITIALIZING; Dump(DriverObject); DumpDeviceStack(PhysicalDeviceObject); KdPrint(("Leave HelloWDMAddDevice\n")); return STATUS_SUCCESS; } |
设备对象PhysicalDeviceObject就是底层总线驱动创建的PDO设备对象。传进该参数的目的就是将FDO附在PDO之上。
AddDevice基本步骤:
1. AddDevice通过IoCreateDevice函数创建FDO,创建FDO的符号链接
2. 在驱动设备扩展保存刚才创建的FDO的地址。
3. 调用IoAttachDeviceToDeviceStack()将FDO附加到PDO上。
PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
_In_ PDEVICE_OBJECT SourceDevice,
_In_ PDEVICE_OBJECT TargetDevice
);
SourceDevice:FDO附加在PDO上时,这个参数代表FDO。
TargetDevice:被附加的设备。如果在FDO与PDO之间存在过滤驱动,则FDO实际上是附加在过滤驱动上的,过滤驱动则附加在PDO上。
返回值:返回SourceDevice的下层设备。如果没有过滤驱动那就是PDO,如果有就是过滤驱动
8.WDM 对IRP_MN_REMOVE_DEVICE的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /************************************************************************ * 函数名称:HandleRemoveDevice * 功能描述:对IRP_MN_REMOVE_DEVICE IRP进行处理 * 参数列表: fdo:功能设备对象 Irp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp) { PAGED_CODE(); KdPrint(("Enter HandleRemoveDevice\n")); Irp->IoStatus.Status = STATUS_SUCCESS; NTSTATUS status = DefaultPnpHandler(pdx, Irp); IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName); //调用IoDetachDevice()把fdo从设备栈中脱开: if (pdx->NextStackDevice) IoDetachDevice(pdx->NextStackDevice); //删除fdo: IoDeleteDevice(pdx->fdo); KdPrint(("Leave HandleRemoveDevice\n")); return status; } |