《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求

时间:2021-04-21 03:44:21

1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置。

 

2)DRIVER_OBJECT下的派遣函数(分发函数)指针的个数为:IRP_MJ_MAXINUM_FUNCTION,保存在一个数组中,编写驱动程序,实质上就是自己编写处理I/O请求IRP包的派遣函数,可以使用for循环将所有的派遣函数注册到同一个派遣函数。分发函数类似MFC消息机制中的回调函数,它的名字也是程序员自定义的,但是参数确定。卸载函数通过地址在驱动对象的DriverUnload域,在驱动卸载中会自动调用该函数。由于DriverUnload函数没有返回值,所以不能决定是否真正被卸载,只能做一些善后处理。

 

3)驱动程序和系统其它组件之间的交互是通过给设备对象(DEVICE_OBJECT)发送或者接受发送给设备对象的请求(IRP包)来交互的(设备对象通过符号链接使其在运用层可见,如果不创建符号链接,则只在内核可见),一个驱动程序不创建设备,就不会受到任何IRP,分发函数也就失去了意义。但在一些只要HOOK等不需要交互的驱动,可以不创建设备。运用层使用符号链接可通过CreateFile像打开文件一样打开设备,只不过路径格式为“\\\\.\\设备符号链接”。

 

4)IoCreateDevice生成的设备有权限限制,使用IoCreateDeviceSecure(在wdmsec.lib中)可以对所有用户开放权限,函数原型为:

 1 NTSTATUS IoCreateDeviceSecure(
2 IN PDRIVER_OBJECT DriverObject,
3 IN ULONG DeviceExtensionSize,
4 IN PUNICODE_STRING DeviceName OPTIONAL,
5 IN DEVICE_TYPE DeviceType,
6 IN ULONG DeviceCharacteristics,
7 IN BOOLEAN Exclusive,
8 IN PCUNICODE_STRING DefaultSDDLString,
9 IN LPCGUID DeviceClassGuid,
10 OUT PDEVICE_OBJECT *DeviceObject
11 );

  这个函数增加了两个内容(注:亲测不通过,不知道还需要导入什么lib文件而作者没提到):

    a)DefaultSDDLString:描述权限的字符串,使用“D:P(A;;GA;;;WD)”即可对所有用户开放权限,如:UNICODE_STRING         sddl = RTL_CONSTANT_STRING(L” D:P(A;;GA;;;WD)”)

    b)DeviceClassGuid:随便填写GUID,不与其他设备冲突即可。如:const        GUID DECLSPEC_SELECTANY  MYGUID_CLASS_MYCDO = {0x26e0d1e0L,0x8189,0x12e0,{0x99,0x14,0x88,0x00,0x22,0x30,0x19,0x13}}

 

5)在\DosDevices\(注:由《驱动开发技术详解》可知,WDM驱动为\DosDevice\,而ddk驱动为\??\,我测试使用的是ddk,作者并未说明,而如下代码暂时未测试)下的简单符号链接并不是对所有用户可见,但是在DriverEnter中生成符号链接则对所有用户可见,因为入口函数总是在进程“System”中,但是注销后可能消失。解决办法:生成全局符号链接“\DosDevice\Global\符号链接”即可,在不支持符号链接用户相关性的系统上,使用如下代码:

 1 UNICODE_STRING  device_name;
2 UNICODE_STRING symbl_name;
3 if( IoIsWdmVersionAvailable( 1, 0x10) )
4 {
5
6 //如果支持符号链接用户相关,用全局符号链接
7 RtlInitUnicodeString(&symbl_name,L” \\DosDevice\\Global\\符号链接”);
8 }
9 else
10 {
11 //如果不支持,则不用全局的
12 RtlInitUnicodeString(&symbl_name,L” \\DosDevice\\符号链接”);
13 }
14 IoCreateSymbolicLink(&symbl_name,&device_name);

 

6)IRP类型取决于主功能号,也就是DRIVER_OBJECT中分发函数指针数组中的索引(如IRP_MJ_CREATE等)。IRP主功能号在IRP的当前栈空间。打开设备IRP可简单返回成功,这需要3个步骤(返回失败也一样):

  a)设置pIrp->IoStatus.Information=0

  b)设置pIrp->IoStatus.Status=STATUS_SUCCESS(如果要让处理失败,则返回错误代码)

  c)调用IoCompleteRequest(pIrp,IO_NO_INCREMENT)这个函数指示完成IRP处理

  完成以上3步以后可直接返回pIrp->IoStatus.Status。

 

7)运用层消息传入:可使用WriteFile,也可以使用DeviceIoControl(设备控制接口),后者是双向的。DeviceIoControl的IRP携带了控制码(必须预先宏定义)、输入缓冲区位置和长度,以及输出缓冲区和位置长度,使用示例(注:DDk驱动代码,实现的功能是在R3层MFC运用程序点击一个按钮,将发送一个字符串到R0内核程序,内核程序接收字符串并打印它):

  1 //最后修改13-10-15
2 #include "xde.h"
3 #include <ntddk.h>
4
5 #define INITCODE code_seg("INIT") /*指的代码运行后就从内存释放掉*/
6 #define PAGECODE code_seg("PAGE") /*表示内存不足时,可以被置换到硬盘*/
7
8 #define DEVNAME L"\\Device\\testDDk_Device"
9 #define SYMNAME L"\\??\\TestLinkName"
10
11 //IRP_MJ_DEVICE_CONTROL类型IRP用于R3运用程序写,内核读数据时的控制码宏定义
12 #define MY_DVC_IN_CODE (ULONG)CTL_CODE(\
13 FILE_DEVICE_UNKNOWN,/*设备类型*/\
14 0xa01,/*用户自定义功能号*/\
15 METHOD_BUFFERED,/*传输方式:带缓冲区*/\
16 FILE_WRITE_DATA/*调用者需求权限:文件写*/)
17
18 typedef unsigned long ULONG;
19
20 //函数声明
21 NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject);//创建设备对象与符号链接
22 NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp);//派遣函数
23 DRIVER_INITIALIZE DriverEntry;//入口,添加设备,启动HOOk
24 DRIVER_UNLOAD DriverUnload;//卸载,删除设备,停止HOOk
25
26 /////////////////////////////////////////////////////////////////
27 #pragma PAGECODE
28 //DriverEntry,入口函数。相当于main
29 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING sRegPath)
30 {
31 //创建设备对象与符号链接
32 CreateMyDevice (pDriverObject);
33 //派遣函数
34 pDriverObject->MajorFunction[IRP_MJ_CREATE]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
35 pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
36 pDriverObject->MajorFunction[IRP_MJ_READ]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
37 pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
38 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
39
40 pDriverObject->DriverUnload = DriverUnload;
41 return STATUS_SUCCESS;
42 }
43
44 ///////////////////////////////////////////////////////////////////
45 #pragma PAGECODE
46 //提供一个Unload函数值是为了让这个程序能动态卸载,方便调试
47 VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
48 {
49 PDEVICE_OBJECT pDev;//用来取得要删除设备对象
50 UNICODE_STRING symLinkName; //
51 //打印一句
52 KdPrint(("Our driver is unloading...\n"));
53 pDev=pDriverObject->DeviceObject;//从驱动对象取得设备对象,所有设备对象连成一条链,这里假定只有一个设备
54 IoDeleteDevice(pDev); //删除设备
55
56
57 RtlInitUnicodeString(&symLinkName,SYMNAME);
58 //删除符号链接
59 IoDeleteSymbolicLink(&symLinkName);
60 KdPrint(("驱动成功被卸载... ")); //sprintf,printf
61 //取得要删除设备对象
62 //删掉所有设备
63 }
64
65
66 //读取IRP_MJ_DEVICE_CONTROL类型IRP包中的数据信息:驱动读
67 NTSTATUS MyDeviceIoCtrlIn(PIRP pIrp)
68 {
69 PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(pIrp);
70 //得到输入缓存长度
71 ULONG in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
72 //输入输出缓冲是公用内存的
73 PVOID buffer = pIrp->AssociatedIrp.SystemBuffer;
74
75 //输出缓冲区信息
76 KdPrint(("The Messege from R3 is : %s \n",buffer));
77
78 pIrp->IoStatus.Information = in_len;//设置IRP读取的字节数
79 pIrp->IoStatus.Status=STATUS_SUCCESS;//设置IRP处理状态
80 IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP的处理
81 return STATUS_SUCCESS; //返回成功,这样,发起I/O操作的Win32API将会返回TRUE,使用GetLastError和设置的IPR处理状态一致
82 }
83
84
85
86 //分类处理
87 NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj, IN PIRP pIrp)
88 {
89 //IoGetCurrentIrpStackLocation得到调用者堆栈的指针
90 PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(pIrp);
91
92 //判断IRP请求包的类型
93 switch(irpsp->MajorFunction)
94 {
95 case IRP_MJ_CREATE://处理打开请求(CreateFile)
96 KdPrint(("IRP_MJ_CREATE\n"));
97 break;
98 case IRP_MJ_CLOSE://处理关闭请求(CloseHandle)
99 KdPrint(("IRP_MJ_CLOSE\n"));
100 break;
101 case IRP_MJ_READ://处理读请求(ReadFile)
102 KdPrint(("IRP_MJ_READ\n"));
103 break;
104 case IRP_MJ_WRITE://处理写请求(WriteFile)
105 KdPrint(("IRP_MJ_WRITE\n"));
106 break;
107 case IRP_MJ_DEVICE_CONTROL://处理设备控制信息(DeviceIoControl)
108 {
109 //首先得到功能号
110 ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;
111 KdPrint(("IRP_MJ_DEVICE_CONTROL\n"));
112 if ( code == MY_DVC_IN_CODE )//内核读取数据
113 {
114 KdPrint(("MY_DVC_IN_CODE\n"));
115 return MyDeviceIoCtrlIn(pIrp);
116 }
117 break;
118 }
119 default:
120 KdPrint(("其它处理\n"));
121 }
122
123 pIrp->IoStatus.Information=0;//设置IRP操作的字节数为,这里无实际意义
124 pIrp->IoStatus.Status=STATUS_SUCCESS;//设置IRP处理状态
125 IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP的处理
126 return STATUS_SUCCESS; //返回成功,这样,发起I/O操作的Win32API将会返回TRUE,使用GetLastError和设置的IPR处理状态一致
127 }
128
129 #pragma INITCODE
130 NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject)
131 {
132 NTSTATUS status;
133 PDEVICE_OBJECT pDevObj;/*用来返回创建设备结构体的指针*/
134 //设备对象(DEVICE_OBJECT)由驱动创建。一个驱动可以创建多个设备对象。
135 //通过驱动对象(DRIVER_OBJECT),可以找到由该驱动创建的所有设备对象。
136 //一个驱动创建的所有设备对象链成一条链。该驱动的驱动对象可以找到这个链,
137 //一个设备对象也可以找到创建它的驱动的驱动对象。DEVICE_OBJECT是设备对象存在的形式
138
139 //创建设备名称
140 UNICODE_STRING devName;
141 UNICODE_STRING symLinkName; // 结构体,包含了宽字节字符缓冲区与其长度
142 RtlInitUnicodeString(&devName,DEVNAME);//对devName初始化字串为"\\Device\\testDDK_Device"
143 //这个宽字节的路径“\\Device\\ ”部分不能改变,后面是设备名称
144
145 //创建设备对象
146 status = IoCreateDevice ( pDriverObject, //驱动程序对象指针。在入库函数DriverEntry过程里接收
147 0,//指定驱动程序为设备扩展对象定义的结构体大小
148 &devName,//设备名称,必须是完整的设备路径名,设置为NULL则是无名设备
149 FILE_DEVICE_UNKNOWN,//设备类型
150 0, TRUE,//驱动程序的其它信息以及指定设备是否是独占的,TRUE则是
151 &pDevObj);//输出,用来保存PDEVICE_OBJECT结构体指针,这个指针指向设备对象自身
152 if (!NT_SUCCESS(status))
153 {
154 if (status==STATUS_INSUFFICIENT_RESOURCES)
155 {
156 KdPrint(("资源不足STATUS_INSUFFICIENT_RESOURCES"));
157 }
158 if (status==STATUS_OBJECT_NAME_EXISTS )
159 {
160 KdPrint(("指定对象名存在"));
161 }
162 if (status==STATUS_OBJECT_NAME_COLLISION)
163 {
164 KdPrint(("//对象名有冲突"));
165 }
166 KdPrint(("设备创建失败...++++++++"));
167 return status;
168 }
169 KdPrint(("设备创建成功...++++++++"));
170 // IoCreateDevice 会把新创建的这个设备对象,链入驱动的设备链中
171 pDevObj->Flags |= DO_BUFFERED_IO;
172 //创建符号链接
173 RtlInitUnicodeString(&symLinkName,SYMNAME);
174 status = IoCreateSymbolicLink( &symLinkName,// Unicode字符串指针,是一个用户态可见的名称
175 &devName );// Unicode字符串指针,是驱动程序创建的设备对象名称。
176 if (!NT_SUCCESS(status)) /*status等于*/
177 {
178 IoDeleteDevice( pDevObj );//删除驱动设备
179 return status;
180 }
181 return STATUS_SUCCESS;
182 }

  在R3运用程序上,进行DeviceIoControl代码(写MFC程序,添加按钮点击事件):

 1 //在头文件添加
2 #include <winioctl.h>
3 #define SYMNAME "\\\\.\\TestLinkName"
4 //IRP_MJ_DEVICE_CONTROL类型IRP用于R3运用程序写,内核读数据时的控制码宏定义
5 #define MY_DVC_IN_CODE (ULONG)CTL_CODE(\
6 FILE_DEVICE_UNKNOWN,/*设备类型*/\
7 0xa01,/*用户自定义功能号*/\
8 METHOD_BUFFERED,/*传输方式:带缓冲区*/\
9 FILE_WRITE_DATA/*调用者需求权限:文件写*/)
10
11 //添加按钮点击事件
12 // TODO: 在此添加控件通知处理程序代码
13 DWORD length = 0;//返回的长度
14
15 HANDLE device = CreateFile(SYMNAME,
16 GENERIC_READ|GENERIC_WRITE,0,0,
17 OPEN_EXISTING,
18 FILE_ATTRIBUTE_SYSTEM,0);
19
20 if ( device == INVALID_HANDLE_VALUE )
21 {
22 //打开失败
23 AfxMessageBox(_T("打开符号链接失败"));
24 return;
25 }
26
27 CString message("Hello R0");
28 LPVOID in_buffer = message.GetBuffer();
29 int in_buffer_len = message.GetLength();
30
31 BOOL ret = DeviceIoControl(device,
32 MY_DVC_IN_CODE, //功能号
33 in_buffer, //输入缓冲,要传递的信息,预先填好
34 in_buffer_len, //输入缓冲长度
35 NULL, //没有输出缓冲
36 0, //输出缓冲为长度
37 &length, //返回的长度
38 NULL);
39 if (!ret)
40 {
41 // DeviceIoControl失败
42 AfxMessageBox(_T("DeviceIoControl失败"));
43 }
44
45 if ( length != in_buffer_len)
46 {
47 AfxMessageBox(_T("读取字节数不一致"));
48 }
49

  输出效果:

              《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求

 

8)驱动层消息传出:运用程序需要开启一个线程调用DeviceIoControl(或者ReadFile)读取数据,而驱动在没有消息的时候阻塞这个IRP,等待有消息时返回(使用事件也行,但还要传递事件句柄,较繁琐)。驱动内部制作一个链表,当有消息的要通知运用程序时,把消息放入链表,并设置同步事件,在DeviceIoControl的处理中等待事件。这里测试一下,避免麻烦,传送一个ULONG类型,传输10次,R3运用程序开线程接收,不停的弹窗,这里不考虑数据覆盖问题。

 

  1 //内核程序
2 #include "xde.h"
3 #include <ntddk.h>
4
5 #define INITCODE code_seg("INIT") /*指的代码运行后就从内存释放掉*/
6 #define PAGECODE code_seg("PAGE") /*表示内存不足时,可以被置换到硬盘*/
7
8 #define DELAY_ONE_MICROSECOND (-10)
9 #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
10
11
12 #define DEVNAME L"\\Device\\testDDk_Device"
13 #define SYMNAME L"\\??\\TestLinkName"
14
15 //IRP_MJ_DEVICE_CONTROL类型IRP用于R3运用程序读,内核写数据时的控制码宏定义
16 #define MY_DVC_OUT_CODE (ULONG)CTL_CODE(\
17 FILE_DEVICE_UNKNOWN,/*设备类型*/\
18 0xa02,/*用户自定义功能号*/\
19 METHOD_BUFFERED,/*传输方式:带缓冲区*/\
20 FILE_READ_DATA/*调用者需求权限:文件读*/)
21
22 typedef unsigned long ULONG;
23 typedef ULONG* PULONG;
24
25 //要发送的数据
26 tatic ULONG data;
27 //全局事件变量
28 static KEVENT g_my_notify_event;
29
30 //函数声明
31 NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject);//创建设备对象与符号链接
32 NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp);//派遣函数
33 void MySleep(LONG msec);//延时函数
34 void MyThreadProc(PVOID context);//测试线程
35 DRIVER_INITIALIZE DriverEntry;//入口,添加设备,启动HOOk
36 DRIVER_UNLOAD DriverUnload;//卸载,删除设备,停止HOOk
37
38
39 /////////////////////////////////////////////////////////////////
40 #pragma PAGECODE
41 //DriverEntry,入口函数。相当于main
42 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING sRegPath)
43 {
44 HANDLE hThread = NULL;
45 NTSTATUS status;
46 //对ZwCreateSection进行HOOK
47 RtlInitUnicodeString(&apiFuncName,L"ZwCreateSection");
48 if (InlineHookIofCallDriverXp(&apiFuncName,(ULONG)MyIofCallDriver,TRUE) == FALSE)
49 {
50 KdPrint(("Inline Hook failed!\n"));
51 }
52
53
54 //创建设备对象与符号链接
55 CreateMyDevice (pDriverObject);
56 //派遣函数
57 pDriverObject->MajorFunction[IRP_MJ_CREATE]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
58 pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
59 pDriverObject->MajorFunction[IRP_MJ_READ]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
60 pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CONTROL;//IRP_MJ_CREATE相关IRP处理函数
61 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
62
63 //创建线程:
64 status = PsCreateSystemThread(
65 &hThread,//新线程句柄
66 0L,NULL,NULL,NULL,
67 MyThreadProc,//函数地址
68 NULL//传递参数
69 );
70 if ( !NT_SUCCESS(status) )
71 {
72 KdPrint(("CreateSystemThread failed!"));
73 }
74
75 ZwClose(hThread);
76 pDriverObject->DriverUnload = DriverUnload;
77 return STATUS_SUCCESS;
78 }
79
80 void MyThreadProc(PVOID context)
81 {
82 //测试
83 KeInitializeEvent(&g_my_notify_event,
84 SynchronizationEvent,//自动复位
85 FALSE//初始为无信号状态
86 );
87 for ( data = 11234 ; data <= 11234 + 10 ; data ++)
88 {
89 //Sleep(3000)
90 MySleep(3000);
91 //设置有信号
92 KeSetEvent(&g_my_notify_event,
93 IO_NO_INCREMENT,//预备给被唤醒线程临时提升优先级的增量
94 FALSE//之后是否跟KeWaitForXXX等待(其它或者自身)事件
95 );
96 KdPrint(("The data is : %u \n",data));
97 }
98 }
99
100
101 void MySleep(LONG msec)
102 {
103 LARGE_INTEGER my_interval;
104 my_interval.QuadPart = DELAY_ONE_MILLISECOND;
105 my_interval.QuadPart *= msec;
106 KeDelayExecutionThread(KernelMode,0,&my_interval);
107 }
108
109 //提供一个Unload函数值是为了让这个程序能动态卸载,方便调试
110 VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
111 {
112 PDEVICE_OBJECT pDev;//用来取得要删除设备对象
113 UNICODE_STRING symLinkName; //
114 //打印一句
115 KdPrint(("Our driver is unloading...\n"));
116 //停止HOOk
117 if(InlineHookIofCallDriverXp(&apiFuncName,(ULONG)MyIofCallDriver,FALSE) == FALSE)
118 {
119 KdPrint(("UnHook failed!\n"));
120 }
121 KdPrint(("UnHook succeed!\n"));
122
123
124 pDev=pDriverObject->DeviceObject;//从驱动对象取得设备对象,所有设备对象连成一条链,这里假定只有一个设备
125 IoDeleteDevice(pDev); //删除设备
126 RtlInitUnicodeString(&symLinkName,SYMNAME);
127
128 //删除符号链接
129 IoDeleteSymbolicLink(&symLinkName);
130 KdPrint(("驱动成功被卸载... ")); //sprintf,printf
131 //取得要删除设备对象
132 //删掉所有设备
133 }
134
135
136 //读取IRP_MJ_DEVICE_CONTROL类型IRP包中的数据信息:驱动写
137 NTSTATUS MyDeviceIoCtrlOut(PIRP pIrp)
138 {
139 PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(pIrp);
140 //获得输出缓冲区
141 PVOID buffer = pIrp->AssociatedIrp.SystemBuffer;
142 //获取输出缓冲区长度
143 ULONG out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
144
145 //等待有事件信号
146 KeWaitForSingleObject(&g_my_notify_event,
147 Executive,//等待原因,驱动程序设置为Executive
148 KernelMode,//内核模式
149 FALSE,//不允许警告
150 NULL//等待超时时间:无限等待
151 );
152
153
154 //有请求了
155 if (out_len < sizeof(ULONG) )//缓冲长度不够
156 {
157 pIrp->IoStatus.Information = sizeof(ULONG);//写需要的长度
158 pIrp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
159 IoCompleteRequest(pIrp,IO_NO_INCREMENT);
160 return pIrp->IoStatus.Status;
161 }
162
163 //长度足够,填写输出缓冲区
164 *((PULONG)buffer) = data;
165
166 //返回成功
167 pIrp->IoStatus.Information = sizeof(ULONG);//写入的长度
168 pIrp->IoStatus.Status = STATUS_SUCCESS;
169 IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP的处理
170 return STATUS_SUCCESS; //返回成功,这样,发起I/O操作的Win32API将会返回TRUE,使用GetLastError和设置的IPR处理状态一致
171 }
172
173 //分类处理
174 NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj, IN PIRP pIrp)
175 {
176 //IoGetCurrentIrpStackLocation得到调用者堆栈的指针
177 PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(pIrp);
178
179 //判断IRP请求包的类型
180 switch(irpsp->MajorFunction)
181 {
182 case IRP_MJ_CREATE://处理打开请求(CreateFile)
183 KdPrint(("IRP_MJ_CREATE\n"));
184 break;
185 case IRP_MJ_CLOSE://处理关闭请求(CloseHandle)
186 KdPrint(("IRP_MJ_CLOSE\n"));
187 break;
188 case IRP_MJ_READ://处理读请求(ReadFile)
189 KdPrint(("IRP_MJ_READ\n"));
190 break;
191 case IRP_MJ_WRITE://处理写请求(WriteFile)
192 KdPrint(("IRP_MJ_WRITE\n"));
193 break;
194 case IRP_MJ_DEVICE_CONTROL://处理设备控制信息(DeviceIoControl)
195 {
196 //首先得到功能号
197 ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;
198 KdPrint(("IRP_MJ_DEVICE_CONTROL\n"));
199 if ( code == MY_DVC_OUT_CODE)//内核传出数据
200 {
201 KdPrint(("MY_DVC_OUT_CODE\n"));
202 return MyDeviceIoCtrlOut(pIrp);
203 }
204 break;
205 }
206 default:
207 KdPrint(("其它处理\n"));
208 }
209
210 //判断是输入还是输出操作
211
212
213 pIrp->IoStatus.Information=0;//设置IRP操作的字节数为,这里无实际意义
214 pIrp->IoStatus.Status=STATUS_SUCCESS;//设置IRP处理状态
215 IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP的处理
216 return STATUS_SUCCESS; //返回成功,这样,发起I/O操作的Win32API将会返回TRUE,使用GetLastError和设置的IPR处理状态一致
217 }
218
219 /////////////////////////////////////////////////////////////////
220 #pragma INITCODE
221 NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject)
222 {
223 NTSTATUS status;
224 PDEVICE_OBJECT pDevObj;
225
226 //创建设备名称
227 UNICODE_STRING devName;
228 UNICODE_STRING symLinkName;
229
230 RtlInitUnicodeString(&devName,DEVNAME);
231
232 //创建设备对象
233 status = IoCreateDevice/*Secure*/( pDriverObject, //驱动程序对象指针。在入库函数DriverEntry过程里接收
234 0,//指定驱动程序为设备扩展对象定义的结构体大小
235 &devName,//设备名称,必须是完整的设备路径名,设置为NULL则是无名设备
236 FILE_DEVICE_UNKNOWN,//设备类型
237 0, TRUE,//驱动程序的其它信息以及指定设备是否是独占的,TRUE则是
238 //&sddl,(LPCGUID)&MYGUID_CLASS_MYCDO,//sddl,guid
239 &pDevObj);//输出,用来保存PDEVICE_OBJECT结构体指针,这个指针指向设备对象自身
240 if (!NT_SUCCESS(status))
241 {
242 if (status==STATUS_INSUFFICIENT_RESOURCES)
243 {
244 KdPrint(("资源不足STATUS_INSUFFICIENT_RESOURCES"));
245 }
246 if (status==STATUS_OBJECT_NAME_EXISTS )
247 {
248 KdPrint(("指定对象名存在"));
249 }
250 if (status==STATUS_OBJECT_NAME_COLLISION)
251 {
252 KdPrint(("//对象名有冲突"));
253 }
254 KdPrint(("设备创建失败...++++++++"));
255 return status;
256 }
257 KdPrint(("设备创建成功...++++++++"));
258 // IoCreateDevice 会把新创建的这个设备对象,链入驱动的设备链中
259 pDevObj->Flags |= DO_BUFFERED_IO;
260 //创建符号链接
261
262
263 RtlInitUnicodeString(&symLinkName,SYMNAME);
264
265 status = IoCreateSymbolicLink( &symLinkName,// Unicode字符串指针,是一个用户态可见的名称
266 &devName );// Unicode字符串指针,是驱动程序创建的设备对象名称。
267 if (!NT_SUCCESS(status)) /*status等于*/
268 {
269 IoDeleteDevice( pDevObj );//删除驱动设备
270 return status;
271 }
272 return STATUS_SUCCESS;
273 }

  R3接收程序:

 1 #include <winioctl.h>
2 #define SYMNAME "\\\\.\\TestLinkName"
3
4
5 //IRP_MJ_DEVICE_CONTROL类型IRP用于R3运用程序读,内核写数据时的控制码宏定义
6 #define MY_DVC_OUT_CODE (ULONG)CTL_CODE(\
7 FILE_DEVICE_UNKNOWN,/*设备类型*/\
8 0xa02,/*用户自定义功能号*/\
9 METHOD_BUFFERED,/*传输方式:带缓冲区*/\
10 FILE_READ_DATA/*调用者需求权限:文件读*/)
11
12 DWORD MyThreadProc(void);
13
14 //按钮事件
15
16 void CMFCTestDlg::OnBnClickedButton1()
17 {
18 CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MyThreadProc,NULL,NULL,NULL);
19 }
20
21 DWORD MyThreadProc(void)
22 {
23 // TODO: 在此添加控件通知处理程序代码
24 ULONG data = 0;//返回的数据
25 DWORD length = 0;//返回的长度
26
27 HANDLE device = CreateFile(SYMNAME,
28 GENERIC_READ|GENERIC_WRITE,0,0,
29 OPEN_EXISTING,
30 FILE_ATTRIBUTE_SYSTEM,0);
31
32 if ( device == INVALID_HANDLE_VALUE )
33 {
34 //打开失败
35 AfxMessageBox(_T("打开符号链接失败"));
36 return FALSE;
37 }
38
39
40 int i = 0;
41 while ( i++ < 10 )
42 {
43 BOOL ret = DeviceIoControl(device,
44 MY_DVC_OUT_CODE, //功能号
45 NULL, //没有输入缓冲,要传递的信息,预先填好
46 NULL, //输入缓冲长度为
47 &data, //输出缓冲
48 sizeof(ULONG), //输出缓冲长度
49 &length, //返回的长度
50 NULL);
51 if (!ret)
52 {
53 // DeviceIoControl失败
54 AfxMessageBox(_T("DeviceIoControl失败"));
55 }
56
57 CString a;
58 a.Format("%u",data);
59 AfxMessageBox(a);
60 }
61 CloseHandle(device);
62 return TRUE;
63 }

  效果图:

 

 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求