1.事件对象

可以使用事件对象同步完成IRP,或者驱动线程间同步执行某些操作。

首先调用KeInitializeEvent IoCreateNotificationEvent或IoCreateSynchronizationEvent初始化事件。

流程:

驱动的一个线程调用KeWaitForSingleObject等待已初始化的事件

当操作完成后,该事件被置信号(调用KeSetEvent),等待线程进入准备执行状态。

内核执行线程分发,原本等待时间的线程开始执行。

2.信号灯对象

任何驱动都可以使用信号灯对象在驱动线程和处理例程之间同步I/O操作。

首先调用KeInitializeSemaphore 函数初始化信号灯。

流程:

驱动程序的一个线程调用KeWaitForSingleObject等待信号灯有信号。

当驱动程序接受到一个IRP请求后,相应处理例程将该IRP排入队列,并调用KeReleaseSemaphore函数增加一个信号灯,随后等待线程满足等待条件,准备执行。

线程分发,原等待线程开始执行。

3.互斥体对象

初始化:KeInitializeMutex

用来确保对共享资源互斥访问的同步机制。其中还有快速互斥体Fast Mutex和受限互斥体Guarded Mutex。互斥体可以递归请求(KeWaitForSingleObject)拥有对一个互斥体对象的所属权。只有完全释放 (KeReleaseMutex)所属权,互斥体对象才会有信号。

4.定时器对象

驱动程序可以使用定时器对象执行一个定时的操作。定时器对象包括DPC定时器和I/O定时器。IO定时器固定时间为1s,不可以改变。

首先调用KeInitializeTimer或KeInitializeTimerEx来初始化定时器。Ex函数比普通函数多一个TYPE参数,用 来指定DPC定时器响应类型是NotificationTimer(需要显式的设置为无信号。调用KeSetTimer)或者 SynchronizationTimer(自动变更为无信号状态)。KeInitializeTimer设置的为NotificationTimer。

1 #include "ntddk.h"
 2  
 3 #ifdef __cplusplus
 4 extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath);
 5 #endif
 6  
 7 void DPCDemoUnload(PDRIVER_OBJECT DriverObject);
 8 VOID ThreadStart(PVOID StartContext);
 9 VOID CustomDpc(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2);
10  
11 KTIMER Timer;
12  
13 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
14 {
15     HANDLE hThread;
16     OBJECT_ATTRIBUTES ObjectAttributes;
17     CLIENT_ID CID;
18     NTSTATUS status;
19      
20  
21     KdPrint(("[DriverEntry]DriverEntry Current Process:%s Current IRQL: %d\n", (char*)((ULONG)IoGetCurrentProcess()+0x174),KeGetCurrentIrql()));
22      
23     //初始化定时器
24     KeInitializeTimer(&Timer);
25  
26     DriverObject->DriverUnload = DPCDemoUnload;
27  
28     InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
29  
30     //创建一个系统线程
31     status = PsCreateSystemThread(&hThread,
32                                     GENERIC_READ | GENERIC_WRITE,
33                                     &ObjectAttributes,
34                                     NtCurrentProcess(),
35                                     &CID,
36                                     (PKSTART_ROUTINE)ThreadStart,
37                                     NULL);
38     if (!NT_SUCCESS(status))
39     {
40         KdPrint(("PsCreateSystemThread failed!\n"));
41         return 0;
42     }
43     ZwClose(hThread);
44     KdPrint(("Exit DriverEntry!\n"));
45     return STATUS_SUCCESS;
46 }
47  
48 VOID ThreadStart(PVOID StartContext)
49 {
50     LARGE_INTEGER DueTime;
51     KDPC Dpc;
52  
53     KdPrint(("Current Process: %s  IRQL:%d\n", (char*)((ULONG)IoGetCurrentProcess()+0x174), KeGetCurrentIrql()));
54  
55     DueTime = RtlConvertLongToLargeInteger(-1000000);
56  
57     //初始化一个DPC
58     KeInitializeDpc(&Dpc, (PKDEFERRED_ROUTINE)CustomDpc, NULL);
59  
60     //设置DPC定时器
61     KeSetTimer(&Timer, DueTime, &Dpc);
62  
63     //等待定时器
64     KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
65  
66     KdPrint(("ThreadStart time expire!\n"));
67  
68     return;
69 }
70  
71 VOID CustomDpc(struct _KDPC *Dpc, PVOID DefferedContext, PVOID SystemArgument1, PVOID systemArgument2)
72 {
73     KdPrint(("Current Process: %s  IRQL:%d\n", (char*)((ULONG)IoGetCurrentProcess()+0x174), KeGetCurrentIrql()));
74  
75     return;
76 }
77  
78 void DPCDemoUnload(PDRIVER_OBJECT DriverObject)
79 {
80  
81     return;
82 }

5.自旋锁

是一种内核模式专用的同步机制,可以在并行访问时保护共享数据。

当某个函数在获取自旋锁的过程中,不可以有如下行为:

触发硬件或者软件异常。

试图访问分页内存

可能造成死锁的递归或者把持自旋锁超过25微秒

调用可能引起以上三条的外部函数

 

使用KeInitialiezeSpinLock初始化自旋锁

使用KeAcquireSpinLock获取自旋锁

使用KeReleaseSpinLock释放自旋锁

KeAcquireInStackQueuedSpinLock和KeReleaseInStackQueuedSpinLock来获取和释放排队自旋锁。

 

6.回调对象

当某条件满足时,驱动程序A向驱动程序B通知某一消息。驱动程序A首先要创建一个回调对象,其他的驱动程序可以向该回调对象注册回调函数,当条件满足的时候,驱动程序A将调用所有像其注册的回调函数。

 

首先使用InitializeObjectAttributes初始化回调对象的属性,必须为回调对象赋名字,且Attributes参数必须设置OBJ_PERMANENT标记,然后调用ExCreateCallback函数创建回调对象。注册回调函数使用的函数是ExRegisterCallback。