这个随笔是记录我半个月左右的时间,从想法到查资料请教,以及到实践的成果。
我想实现的是,隔定时时间写文件,本以为调用写的函数就可以实现了,结果各种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,可直接运行。