這個隨筆是記錄我半個月左右的時間,從想法到查資料請教,以及到實踐的成果。
我想實現的是,隔定時時間寫文件,本以為調用寫的函數就可以實現了,結果各種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,可直接運行。