www.2527.com_澳门新葡8455手机版_新京葡娱乐场网址_
做最好的网站

windows内核情景深入分析,关于DPC和workitem的简约

2019-08-24 00:28 来源:未知

关于DPC和workitem的简单用法,dpcworkitem

这个随笔是记录我半个月左右的时间,从想法到查资料请教,以及到实践的成果。

我想实现的是,隔定时时间写文件,本以为调用写的函数就可以实现了,结果各种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:%dn", 
 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 failuren"));    
 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:Exitn"));
 80         return STATUS_SUCCESS;
 81 }
 82 
 83 VOID ThreadStart(IN PVOID StartContext)
 84 {
 85       
 86     PmyInfo pmyInfo;
 87     KdPrint(("dpc:Cur Process: %s IRQL:%dn",
 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:%dn",
116                 (char*)((ULONG)PsGetCurrentProcess() 0x174), KeGetCurrentIrql()));
117      // KdPrint(("dpc: my age is %d , my weight is %d, my name is %sn",
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 %sn",
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,可直接运行。

 

这个随笔是记录我半个月左右的时间,从想法到查资料请教,以及到实践的成果。 我想实现的是,隔...

我想实现的是,隔定时时间写文件,本以为调用写的函数就可以实现了,结果各种BSOD,IRQL_NOT_LESS_OR_EQUAL,这个蓝屏提示,结果是函数的IRQL导致的,内核函数都有IRQL,我是想在DISPATCH_LEVEL中运行低级别的PASSIVE_LEVEL,因为写函数就是在PASSIVE_LEVEL上运行的。解决方法是,使用DPC,IoQueueWorkItem。下面的代码是我简单的测试了我的想法,给文件中只写入了时间和简单的数据结构信息,只适合新手,全部代码如下:

    ASSERT(FALSE); "

这个随笔是记录我半个月左右的时间,从想法到查资料请教,以及到实践的成果。

#define HIGH_LEVEL                                31

代码赋值粘贴,编译后安装.sys,可直接运行。

}

  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:%dn",  41         (char*)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 53             return status; 54         if(!DeviceObject) 55             { 56                 KdPrint(("dpc:DeviceObject is failuren"));     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 74             { 75                 KdPrint(("dpc:PsCreateSystemThread failure!n")); 76                 return 0; 77             } 78         ZwClose; 79         KdPrint(("dpc:Exitn")); 80         return STATUS_SUCCESS; 81 } 82  83 VOID ThreadStart(IN PVOID StartContext) 84 { 85        86     PmyInfo pmyInfo; 87     KdPrint(("dpc:Cur Process: %s IRQL:%dn", 88             (char*)PsGetCurrentProcess() 0x174), KeGetCurrentIrql; 89     pmyInfo = ExAllocatePool(NonPagedPool, sizeof; 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:%dn",116                 (char*)PsGetCurrentProcess() 0x174), KeGetCurrentIrql;117      // KdPrint(("dpc: my age is %d , my weight is %d, my name is %sn",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 NTSTATUS136 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 %sn",186                                                  pmyInfo->age, pmyInfo->weight, pmyInfo->name));187          //写文件188          status = ZwWriteFile(hFile, NULL, NULL, NULL, &iostatus,189                                                           pBuffer, wcslen*sizeof, NULL, NULL);190          //写入换行符191          status = ZwWriteFile(hFile, NULL, NULL, NULL, &iostatus,192                                                                 L"n", sizeof, NULL, NULL);193 194          //关闭文件句柄195          ZwClose;196          //释放内存197         // ExFreePool;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 }

这里的PASSIVE_LEVEL是级别最低的,但是却对应着系统结构中较高的层次。当CPU运行于用户空间,或者虽然进入了内核但还只是运行于管理层的时候,其运行级别就是PASSIVE_LEVEL。比其略高的是APC_LEVEL,那是在(内核中)为APC函数(见本书“进程与线程”一章)的执行进行准备时的运行级别,APC请求相当于对用户空间程序的(软件)中断。注意IRQL在x86系统结构中并没有硬件的支持(CPU中并没有这么一个寄存器)而只是一个变量。与CPU只能通过特殊的指令或中断/异常才能进入系统态不同,IRQL是CPU可以自由设置的,每当CPU进入更底层、更核心的层次时就提高IRQL,反之则降低IRQL。不过,表明IRQL的变量在内核中,运行于用户空间时是无法改变IRQL的。

其基本的意图是,如果CPU从而一个线程已经处于某个级别,其操作就不能受同级或更低级别的操作所干扰。

#define CLOCK1_LEVEL                             28

                                                  KeGetCurrentIrql() )); "

#define PAGED_CODE() { "

#define PASSIVE_LEVEL                             0

  if (KeGetCurrentIrql() > APC_LEVEL) { "

#define IPI_LEVEL                                   29

当然,光是在程序中引用宏操作PAGED_CODE()不会使一个函数所在的页面可倒换,真正使其可倒换的是编译指示“#pragma alloc_text()”。例如NtQueryObject()中的第一行就是PAGED_CODE(),与此相应,这个函数所在的源文件中就有这么一行:

    KdPrint( ("NTDDK: Pageable code called at IRQL > APC_LEVEL (%d)"n",

#endif

#define APC_LEVEL                                  1

#define PAGED_CODE()

#define PROFILE_LEVEL                             27

#define POWER_LEVEL                             30

  } "

#define DISPATCH_LEVEL                           2

#ifdef DBG

IRQL级别3及以上用于硬件中断。显然,设计者的意图是采用中断优先级,即优先级较高的中断源可以中断优先级较低的中断服务。但是x86的系统结构并不支持中断优先级,所以这实际上是来自VMS的遗迹,因为VAX和PDP的系统结构都是支持中断优先级的。

#pragma alloc_text(PAGE, NtQueryObject)

正是这一行编译指示让编译工具将为此函数生成的可执行代码放在可被倒换的区间。

在Debug模式下,这个宏操作检查CPU当前的运行级别,如果发现高于APC_LEVEL就说明这个函数有可能在DISPATCH_LEVEL或更高的级别上受到调用,因而是不应该被倒换出去的,所以就发出警告。至于在正式运行的版本中,则这个宏操作定义为空。

#define LOW_LEVEL                                 0

再高一级是DISPATCH_LEVEL,这大致相当于CPU运行于Windows内核中的核心层,即“内核”层。线程的切换只能发生于CPU行将从DISPATCH_LEVEL级别下降的时候。

www.2527.com,回到页面换出的问题上,只要CPU的IRQL级别不高于APC_LEVEL的层次,其代码都是允许倒换的,但是从DISPATCH_LEVEL开始就不允许了。显然,如果在这一点上搞错了,后果是很严重的。所以在管理层的代码中几乎每个函数的开头都要放上一个宏操作PAGED_CODE(),说明代码作者的意图是让这个函数所占的页面可以被倒换出去。这个宏操作的定义如下:

与此相关,Windows为CPU的运行状态定义了许多“IRQ级别”,即IRQL。在任一时间中,CPU总是运行于其中的某一个级别,这个级别就表明了什么事情可以做、什么事情不可以做。下面是这些级别的定义:

#else

#define CLOCK2_LEVEL                             28

TAG标签:
版权声明:本文由澳门新葡8455手机版发布于www.2527.com,转载请注明出处:windows内核情景深入分析,关于DPC和workitem的简约