第三讲:Windows驱动的结构

最近有点忙,一直没有时间来总结一下,好不容易逮着个有时间的星期天,静下心来,好好总结一下,完成未完成的系列教程,好了,废话少说,开题了。

现在进行Windows驱动开发,主要有两种框架,一种是NT框架的驱动,一种是WDM框架的驱动程序,微软后来为了区分WDM驱动的,又推出了KMDFUMDF两种框架,KMDF是针对内核态的驱动程序开发的框架,而UMDF是用户态的驱动程序的开发框架,这两个框架对底层的API的封装程度又加重了一点,对于底层的安全软件的开发降低了控制的程度,就像微过滤驱动一样,不少安全厂商并不买账。

NT驱动主要工作在Windows 2000下,不支持即插即用和电源管理,大概包括三部分:入口函数(DriverEntry)、卸载历程(DriverUnload)、分发例程(Dispatch Function)。下面分别讲述这三个部分。

入口函数(DriverEntry)

驱动的入口函数主要是对驱动程序进行初始化工作,它是由系统进程所调用。在驱动程序初始化的时候,入口函数被加载进内存,进行初始化,完成之后,就要退出内存。一般入口函数的前边都要有这么一个标记

#pragma code_seg("INIT")标记驱动入口函数在内存中的位置。NT驱动的入口函数一般完成的工作也很简单,就是注册分发例程,下面是一个简单的代码示例:

[cpp]  view plain  copy
  1. #pragma code_seg("INIT")  
  2. extern"C"   
  3. NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,  
  4.     IN PUNICODE_STRING pRegistryPath  
  5.     )  
  6.     {  
  7.         NTSTATUS status;  
  8.         KdPrint(("Hello!welcome to the driver entry!/n"));  
  9.         pDriverObject->DriverUnload = DriverUnload;  
  10.         pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateClose;  
  11.         pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateClose;  
  12.         pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;  
  13.         pDriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;  
  14.           
  15.         status = CreateDevice(pDriverObject); //创建设备对象,这个要另外实现  
  16.         return status;  
  17.     }  

卸载例程(DriverUnload)

卸载例程,顾名思义,就是负责驱动程序的卸载的。完成清扫的工作,删除符号链接,删除设备对象等等,下面是示例代码:

[cpp]  view plain  copy
  1. #pragma CodeSeg("PAGED")  
  2. VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)   
  3. {  
  4.     PDEVICE_OBJECT  pNextObj;  
  5.     KdPrint(("Enter DriverUnload/n"));  
  6.     pNextObj = pDriverObject->DeviceObject;  
  7.     while (pNextObj != NULL)   
  8.     {  
  9.         PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)  
  10.             pNextObj->DeviceExtension;  
  11.   
  12.         //删除符号链接  
  13.         UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;  
  14.         IoDeleteSymbolicLink(&pLinkName);  
  15.         pNextObj = pNextObj->NextDevice;  
  16.         IoDeleteDevice( pDevExt->pDevice );  
  17.     }  
  18. }  

分发例程Dispatch

分发例程是驱动中真正进行功能实现的部分,系统产生的IRP都是由该部分进行处理,并且在执行的时候,分发函数运行在不同的进程中,存在于分页内存中,最最简单的处理函数可以参考上一篇文章中的示例代码,只是实现了转交的作用,具体想实现的功能,就要看用户的不同需求了,这里就不再赘述。

创建设备对象的函数代码:

[cpp]  view plain  copy
  1. #pragma code_seg("INIT")  
  2. NTSTATUS CreateDevice (  
  3.         IN PDRIVER_OBJECT   pDriverObject)   
  4. {  
  5.     NTSTATUS status;  
  6.     PDEVICE_OBJECT pDevObj;  
  7.     PDEVICE_EXTENSION pDevExt;  
  8.       
  9.     //创建设备名称  
  10.     UNICODE_STRING devName;  
  11.     RtlInitUnicodeString(&devName,L"//Device//MyDDKDevice");  
  12.       
  13.     //创建设备  
  14.     status = IoCreateDevice( pDriverObject,  
  15.                         sizeof(DEVICE_EXTENSION),  
  16.                         &(UNICODE_STRING)devName,  
  17.                         FILE_DEVICE_UNKNOWN,  
  18.                         0, TRUE,  
  19.                         &pDevObj );  
  20.     if (!NT_SUCCESS(status))  
  21.         return status;  
  22.   
  23.     pDevObj->Flags |= DO_BUFFERED_IO;  
  24.     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;  
  25.     pDevExt->pDevice = pDevObj;  
  26.     pDevExt->ustrDeviceName = devName;  
  27.     //创建符号链接  
  28.     UNICODE_STRING symLinkName;  
  29.     RtlInitUnicodeString(&symLinkName,L"//??//HelloDDK");  
  30.     pDevExt->ustrSymLinkName = symLinkName;  
  31.     status = IoCreateSymbolicLink( &symLinkName,&devName );  
  32.     if (!NT_SUCCESS(status))   
  33.     {  
  34.         IoDeleteDevice( pDevObj );  
  35.         return status;  
  36.     }  
  37.     return STATUS_SUCCESS;  
  38. }  

 Windows 2000出现之后,微软又加入了新的驱动模型--WDM驱动模型,主要添加了对即插即用和电源管理的支持。驱动的大概结构和NT驱动很类似,新增了添加设备例程,类似于上面的CreateDevice函数,因为在NT驱动中,不少开发者直接把CreateDevice的实现放在了DriverEntry中了,而我只是把它单拿出来了。

入口函数(DriverEntry)

WDM驱动程序的入口函数和上面的差不多,通用的代码中加入下边一句话就行了:

[cpp]  view plain  copy
  1. pDriverObject->DriverExtension->AddDevice = MyDeviceAdd;  

添加设备例程(AddDevice)

AddDevice类似于NT驱动中DriverEntry创建设备对象函数,但是略有不同,参数的个数不同,DriverObjectI/O管理器创建的驱动对象,PhysicalDeviceObject是底层总线驱动创建的PDO对象。大概的步骤是这样的:

首先通过IoCreateDevice创建设备对象,然后保存设备对象的地址,接下来将创建的设备对象FDO附加在底层PDO上面,最后设置FDOflags子域。示例代码:

[cpp]  view plain  copy
  1. #pragma CodeSeg("PAGED")  
  2. NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject,  
  3.                            IN PDEVICE_OBJECT PhysicalDeviceObject)  
  4. {   
  5.     PAGED_CODE();  
  6.     KdPrint(("Enter AddDevice/n"));  
  7.   
  8.     NTSTATUS status;  
  9.     PDEVICE_OBJECT fdo;  
  10.     UNICODE_STRING devName;  
  11.     RtlInitUnicodeString(&devName,L"//Device//MyWDMDevice");  
  12.     status = IoCreateDevice(  
  13.         DriverObject,  
  14.         sizeof(DEVICE_EXTENSION),  
  15.         &(UNICODE_STRING)devName,  
  16.         FILE_DEVICE_UNKNOWN,  
  17.         0,  
  18.         FALSE,  
  19.         &fdo);  
  20.     if( !NT_SUCCESS(status))  
  21.         return status;  
  22.     PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;  
  23.     pdx->fdo = fdo;  
  24.     pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);  
  25.     UNICODE_STRING symLinkName;  
  26.     RtlInitUnicodeString(&symLinkName,L"//DosDevices//MyWDM");  
  27.   
  28.     pdx->ustrDeviceName = devName;  
  29.     pdx->ustrSymLinkName = symLinkName;  
  30.     status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);  
  31.   
  32.     if( !NT_SUCCESS(status))  
  33.     {  
  34.         IoDeleteSymbolicLink(&pdx->ustrSymLinkName);  
  35.         status = IoCreateSymbolicLink(&symLinkName,&devName);  
  36.         if( !NT_SUCCESS(status))  
  37.         {  
  38.             return status;  
  39.         }  
  40.     }  
  41.   
  42.     fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;  
  43.     fdo->Flags &= ~DO_DEVICE_INITIALIZING;  
  44.   
  45.     KdPrint(("Leave AddDevice/n"));  
  46.     return STATUS_SUCCESS;  
  47. }  

分发例程(Dispatch Function)

通用的分发例程就不在介绍了,跟上面NT驱动的一样,没什么区别,下面介绍一下PNP

即插即用例程Pnp

即插即用IRP,即IRP_MJ_PNP,一般是由即插即用管理器发送给WDM驱动程序的。关于即插即用,用户可以查看更加详细的资料,这里主要讲述一个IRP的处理,对IRP_MN_REMOVE_DEVICE IRP进行处理,这个例程主要实现了原来DriverUnload所实现的功能。原理很简单,看一下示例代码:

[cpp]  view plain  copy
  1. NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)  
  2. {  
  3.     PAGED_CODE();  
  4.     KdPrint(("Enter HandleRemoveDevice/n"));  
  5.   
  6.     Irp->IoStatus.Status = STATUS_SUCCESS;  
  7.     NTSTATUS status = DefaultPnpHandler(pdx, Irp);  
  8.     IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);  
  9.   
  10.     //调用IoDetachDevice()把fdo从设备栈中脱开:  
  11.     if (pdx->NextStackDevice)  
  12.         IoDetachDevice(pdx->NextStackDevice);  
  13.       
  14.     //删除fdo:  
  15.     IoDeleteDevice(pdx->fdo);  
  16.     KdPrint(("Leave HandleRemoveDevice/n"));  
  17.     return status;  
  18. }  

卸载历程(DriverUnload)

卸载例程现在显得可有可无了,给一个简单的示例吧,其实什么都没实现

[cpp]  view plain  copy
  1. void DriverUnload(IN PDRIVER_OBJECT DriverObject)  
  2. {  
  3.     PAGED_CODE();  
  4.     KdPrint(("Enter DriverUnload/n"));  
  5.     KdPrint(("Leave DriverUnload/n"));  
  6. }  
 

这一点就说到这吧,本来还想说说驱动栈的结构,因为需要用图表比较清晰,现在无法上传图片,就不讲了。




此文章来自于【http://blog.csdn.net/caperingrabbit/article/details/5376297】

你可能感兴趣的:(windows,驱动开发)