《Windows驱动开发技术详解》之HelloDDK

编写如下代码:

运行会报错:

这里的原因是有没有引用到的形参,需要添加如下代码即可:

记得在系统启动时按F8禁用掉数字签名:

将编译好的驱动拖入虚拟机,以管理员身份运行DbgView捕捉内核态输出数据,以管理员身份运行InstDrv以加载驱动,我们就可以看到启动和停止时,DriverEntry和DriverUnload中输出的数据了:

 

下面,来对上面的实验进行简单的说明:

Windows驱动程序的入口函数并不是main函数,而是DriverEntry函数,这个函数由内核中的I/O管理器负责调用。参数pDriverObject是I/O管理器传递进来的驱动对象;参数pRegistryPath是驱动程序在注册表中的路径。

 下面,我们来把上面的例子完善下:

 1 #include"helloddk.h"
 2 typedef struct _DEVICE_EXTENSION{
 3     PDEVICE_OBJECT pDevice;
 4     UNICODE_STRING ustrDeviceName;
 5     UNICODE_STRING ustrSymLinkName;
 6 }DEVICE_EXTENSION,*PDEVICE_EXTENSION;
 7 
 8 
 9 NTSTATUS DriverEntry(
10     IN PDRIVER_OBJECT pDriverObject,
11     IN PUNICODE_STRING pRegistryPath)
12 {
13     DbgPrint("Hello, world\n");
14     UNREFERENCED_PARAMETER(pDriverObject);
15     UNREFERENCED_PARAMETER(pRegistryPath);
16     NTSTATUS status;
17     
18     pDriverObject->DriverUnload = DriverUnload;//向IO管理器注册回调函数
19     pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
20     pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
21     pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
22     pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
23     status = CreateDevice(pDriverObject);//创建驱动设备对象
24     return STATUS_SUCCESS;
25 }
26 
27 VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
28 {
29     UNREFERENCED_PARAMETER(pDriverObject);
30     PDEVICE_OBJECT pNextObj;
31     pNextObj = pDriverObject->DeviceObject;
32     while (pNextObj != NULL){
33         PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;//获取设备扩展
34         UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
35         IoDeleteSymbolicLink(&pLinkName);//删除符号链接
36         pNextObj = pNextObj->NextDevice;//得到下一个设备对象地址
37         IoDeleteDevice(pDevExt->pDevice);
38     }
39     DbgPrint("Goodbye world!\n");
40 }
41 //创建设备对象
42 NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject){
43     DbgPrint("Create Device!\n");
44     NTSTATUS status;
45     PDEVICE_OBJECT pDevObj;
46     PDEVICE_EXTENSION pDevExt;
47 
48     UNICODE_STRING devName;
49     RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");
50 
51     status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);
52     if (!NT_SUCCESS(status))
53         return status;
54     pDevObj->Flags |= DO_BUFFERED_IO;
55     pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
56     pDevExt->pDevice = pDevObj;
57     pDevExt->ustrDeviceName = devName;
58     UNICODE_STRING symLinkName;
59     RtlInitUnicodeString(&symLinkName, L"\\??\\HelloDDK");
60     pDevExt->ustrSymLinkName = symLinkName;
61     status = IoCreateSymbolicLink(&symLinkName, &devName);//创建符号链接
62     //驱动的设备名称只有在内核态可见,对于应用程序是不可见的,
63     //驱动需要暴露一个符号链接,该链接指向真正的设备名称
64     if (!NT_SUCCESS(status)){
65         IoDeleteDevice(pDevObj);
66         return status;
67     }
68     return STATUS_SUCCESS;
69 }
70 
71 NTSTATUS HelloDDKDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp){
72     DbgPrint("HelloDDKDispatchRoutine!\n");
73     UNREFERENCED_PARAMETER(pDevObj);
74     NTSTATUS status = STATUS_SUCCESS;
75     pIrp->IoStatus.Status = status;
76     pIrp->IoStatus.Information = 0;
77     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
78     return status;
79 }

启动、停止:

 

I/O管理器的作用:

I/O管理器在内存中创建一个IRP来代表一个I/O操作,传递一个指向IRP的指针到正确的驱动程序,当此I/O操作完成时再处理该请求包。相反地,驱动程序接收一个IRP,执行该IRP指定的操作,然后将IRP传回给I/O管理器,这是因为:所请求的I/O操作已经完成,或者必须将其传给另一个驱动程序以作进一步处理。

I/O管理器也提供一些对于不同驱动程序都通用的代码,例如,I/O管理器提供了这样一个功能:允许一个驱动程序调用其它驱动程序。它也为I/O请求管理缓冲区、为驱动程序提供超时支持、记录下哪些可安装的文件系统被加载到操作系统中。在I/O管理器中有将近100个不同的例程可供设备驱动程序调用。

 

posted @ 2016-05-19 22:41  _No.47  阅读(1310)  评论(0编辑  收藏  举报