這個隨筆是記錄我半個月左右的時間,從想法到查資料請教,以及到實踐的成果。
我想實現的是,隔定時時間寫文件,本以為調用寫的函數就可以實現了,結果各種BSOD,IRQL_NOT_LESS_OR_EQUAL,這個藍屏提示,結果是函數的IRQL導致的,內核函數都有IRQL,我是想在DISPATCH_LEVEL中運行低級別的PASSIVE_LEVEL,因為寫函數就是在PASSIVE_LEVEL上運行的。解決方法是,使用DPC,IoQueueWorkItem。下面的代碼是我簡單的測試了我的想法,給文件中只寫入了時間和簡單的數據結構信息,只適合新手,全部代碼如下(注意紅色標記代碼):
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include "ntddk.h"
4
5 #define WRITE_FILE_INTERVAL -10000 * 1000 * 10
6 typedef struct my_info{
7 int age;
8 int weight;
9 char* name;
10 }myInfo, *PmyInfo;
11 VOID ThreadStart(IN PVOID StartContext);
12
13 VOID CustomDpc(IN struct _KDPC *Dpc,
14 IN PVOID DeferredContext,
15 IN PVOID SystemArgument1,
16 IN PVOID SystemArgument2);
17
18 VOID SyncTechUnload(IN PDRIVER_OBJECT DriverObject);
19 //VOID workItem();
20 NTSTATUS GetLocalTime( OUT PTIME_FIELDS timeFields );
21 VOID TestFile(IN PDEVICE_OBJECT DeviceObject,
22 IN PVOID Context);
23
24 KTIMER Timer; //?????????????????
25 PDEVICE_OBJECT DeviceObject;
26 PIO_WORKITEM pIoWorkItem;
27 LARGE_INTEGER DueTime;
28 KDPC Dpc;
29 HANDLE hThread;
30
31 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
32 {
33
34 OBJECT_ATTRIBUTES ObjectAttributes;
35 CLIENT_ID CID;
36 NTSTATUS status;
37 UNICODE_STRING DeviceName, Win32Device;
38
39
40 KdPrint(("dpc:DriverEntry Cur Process:%s Cur IRQL:%d\n",
41 (char*)((ULONG)PsGetCurrentProcess()+0x174), KeGetCurrentIrql()));
42
43 RtlInitUnicodeString(&DeviceName, L"\\Device\\jay0");
44 RtlInitUnicodeString(&Win32Device, L"\\DosDevices\\jay0");
45 status = IoCreateDevice(DriverObject,
46 10,
47 &DeviceName,
48 FILE_DEVICE_UNKNOWN,
49 0,
50 FALSE,
51 &DeviceObject);
52 if(!NT_SUCCESS(status))
53 return status;
54 if(!DeviceObject)
55 {
56 KdPrint(("dpc:DeviceObject is failure\n"));
57 return STATUS_UNEXPECTED_IO_ERROR;
58 }
59 //初始化定時器
60 KeInitializeTimer(&Timer);
61 DriverObject->DriverUnload = SyncTechUnload;
62 InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
63 //創建一個系統線程
64 status = PsCreateSystemThread(
65 &hThread,
66 GENERIC_READ|GENERIC_WRITE,
67 &ObjectAttributes,
68 NtCurrentProcess(),
69 &CID,
70 (PKSTART_ROUTINE)ThreadStart,
71 NULL
72 );
73 if (!NT_SUCCESS(status))
74 {
75 KdPrint(("dpc:PsCreateSystemThread failure!\n"));
76 return 0;
77 }
78 ZwClose(hThread);
79 KdPrint(("dpc:Exit\n"));
80 return STATUS_SUCCESS;
81 }
82
83 VOID ThreadStart(IN PVOID StartContext)
84 {
85
86 PmyInfo pmyInfo;
87 KdPrint(("dpc:Cur Process: %s IRQL:%d\n",
88 (char*)((ULONG)PsGetCurrentProcess()+0x174), KeGetCurrentIrql()));
89 pmyInfo = ExAllocatePool(NonPagedPool, sizeof(myInfo));
90 pmyInfo->age = 23;
91 pmyInfo->weight = 60;
92 pmyInfo->name = "zc";
93 //KdPrint(("dpc: my age is %d , my weight is %d \n", context->age, context->weight));
94 DueTime = RtlConvertLongToLargeInteger(WRITE_FILE_INTERVAL);
95 //初始化一個Dpc
96 //這個CustomDpc是自定義的函數,運行在DISPATCH_LEVEL上,後面的參數myInfo是該函數的參數
97 KeInitializeDpc(&Dpc, (PKDEFERRED_ROUTINE)CustomDpc, pmyInfo);
98 //設置DPC定時器
99 KeSetTimer(&Timer, DueTime, &Dpc);
100 //等待定時器
101 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
102 KdPrint(("dpc:ThreadStart time expire"));
103 return;
104 }
105
106 //簡單輸出進程名和當前的IRQL,注意該函數運行在dispatch級別
107
108 VOID CustomDpc(IN struct _KDPC *Dpc,
109 IN PmyInfo pmyInfo,
110 IN PVOID SystemArgument1,
111 IN PVOID SystemArgument2)
112 {
113
114
115 KdPrint(("dpc:CustomDpc Process: %s IRQL:%d\n",
116 (char*)((ULONG)PsGetCurrentProcess()+0x174), KeGetCurrentIrql()));
117 // KdPrint(("dpc: my age is %d , my weight is %d, my name is %s\n",
118 // pmyInfo->age, pmyInfo->weight, pmyInfo->name));
119
120 //使用IoAllocateWorkItem分配一個ioworkitem
121 pIoWorkItem = IoAllocateWorkItem(DeviceObject);
122 // IoInitializeWorkItem(DeviceObject,pIoWorkItem);
123
124
125 if(pIoWorkItem)
126 {
127 //插入一個workitem, 其中TestFile就是我要寫文件的函數,第四個參數也是該函數的參數
128 IoQueueWorkItem(pIoWorkItem, (PIO_WORKITEM_ROUTINE)TestFile, DelayedWorkQueue, pmyInfo);
129 }
130 //由於要定時寫,因此再次設置定時器,如果不設置只寫一次
131 KeSetTimer(&Timer, DueTime, Dpc);
132 }
133
134
135 NTSTATUS
136 GetLocalTime( OUT PTIME_FIELDS timeFields )
137 /*++
138 --*/
139 {
140 NTSTATUS status = STATUS_SUCCESS;
141 LARGE_INTEGER sysTime,locTime;
142
143 KeQuerySystemTime( &sysTime );
144 ExSystemTimeToLocalTime( &sysTime,&locTime );
145 RtlTimeToTimeFields( &locTime,timeFields );
146
147 return STATUS_SUCCESS;
148
149 }
150
151 VOID TestFile(IN PDEVICE_OBJECT DeviceObject,
152 IN PmyInfo pmyInfo)
153
154 {
155 TIME_FIELDS time;
156 UNICODE_STRING string;
157 HANDLE hFile;
158 IO_STATUS_BLOCK iostatus;
159 NTSTATUS status;
160 WCHAR pBuffer[200];
161 OBJECT_ATTRIBUTES objattr;
162 LARGE_INTEGER ByteOffset;
163 KIRQL irql;
164
165 RtlInitUnicodeString(&string, L"\\??\\C:\\Log\\1.log");
166 InitializeObjectAttributes(&objattr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL);
167 GetLocalTime(&time);
168 irql = KeGetCurrentIrql();
169 KdPrint(("dpc: cur irql=%d", irql));
170 //打開文件
171 status = ZwCreateFile(&hFile, FILE_APPEND_DATA,
172 &objattr, &iostatus,
173 NULL, FILE_ATTRIBUTE_NORMAL,
174 FILE_SHARE_WRITE,
175 FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
176
177 swprintf( pBuffer,L"[%d-%d-%d-%d-%d-%d]",
178 time.Year,
179 time.Month,
180 time.Day,
181 time.Hour,
182 time.Minute,
183 time.Second);
184 KdPrint(("dpc: %S", pBuffer));
185 KdPrint(("dpc: my age is %d , my weight is %d, my name is %s\n",
186 pmyInfo->age, pmyInfo->weight, pmyInfo->name));
187 //寫文件
188 status = ZwWriteFile(hFile, NULL, NULL, NULL, &iostatus,
189 pBuffer, wcslen(pBuffer)*sizeof(WCHAR), NULL, NULL);
190 //寫入換行符
191 status = ZwWriteFile(hFile, NULL, NULL, NULL, &iostatus,
192 L"\n", sizeof(WCHAR), NULL, NULL);
193
194 //關閉文件句柄
195 ZwClose(hFile);
196 //釋放內存
197 // ExFreePool(pBuffer);
198
199
200 }
201
202 VOID SyncTechUnload(IN PDRIVER_OBJECT DriverObject)
203 {
204
205 KeCancelTimer(&Timer);
206 IoFreeWorkItem(pIoWorkItem);
207 IoDeleteDevice(DriverObject->DeviceObject);
208 KdPrint(("dpc:DpcTest unload!\n"));
209
210 }
代碼賦值粘貼,編譯後安裝.sys,可直接運行。