内核事件KEVENT(同步)
转载请您注明出处:http://www.cnblogs.com/lsh123/p/7358702.html
一.驱动程序与驱动程序的事件交互 IoCreateNotificationEvent ———> IoCreateNotificationEvent
在内核驱动中可以通过给某个内核对象创建一个命名对象,然后在另一个驱动中通过名字来获取这个对象,然后操作它来实现两个驱动之间的内核对象的通讯,针对事件对象来说,要实现两个驱动交互事件对象,通过这样几步:
1. 在驱动Server中调用IoCreateNotificationEvent或者IoCreateSynchronizationEvent来创建一个通知事件对象或者同步事件对象
2. 在驱动Client中调用
IoCreateNotificationEvent或者IoCreateSynchronizationEvent获取已经有名字的内核对象的句柄 ,设置事件的激发状态
(3. 在驱动B中调用ObReferenceObjectByHandle根据上面两个函数返回的句柄来获取A中的事件对象,并操作它)
源代码:
Server.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <ntifs.h> #define EVENT_NAME L"\\BaseNamedObjects\\ServerKernelEvent" void ThreadProcedure( PVOID ParameterData); VOID DriverUnload(PDRIVER_OBJECT DriverObject); PKEVENT __Event; HANDLE __EventHandle; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING EventName; PDEVICE_OBJECT DeviceObject = NULL; HANDLE ThreadHandle = NULL; CLIENT_ID ClientID = { 0 }; DriverObject->DriverUnload = DriverUnload; RtlInitUnicodeString(&EventName, EVENT_NAME); DriverObject->DriverUnload = DriverUnload; __Event = IoCreateNotificationEvent( &EventName, //自定义事件名 &__EventHandle); //返回的事件句柄 KeResetEvent(__Event); Status = PsCreateSystemThread(&ThreadHandle, 0, NULL, NtCurrentProcess(), &ClientID, (PKSTART_ROUTINE)ThreadProcedure,NULL); return Status; } void ThreadProcedure( PVOID ParameterData) { NTSTATUS Status; KeWaitForSingleObject(__Event, Executive, KernelMode, FALSE, NULL); DbgPrint( "ThreadProcedure() Exit\r\n" ); PsTerminateSystemThread(STATUS_SUCCESS); } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { DbgPrint( "DriverUnload()\r\n" ); if (__EventHandle != NULL) { KeClearEvent(__Event); ZwClose(__EventHandle); __EventHandle = NULL; __Event = NULL; } } |
Client.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include <ntifs.h> #define EVENT_NAME L"\\BaseNamedObjects\\ServerKernelEvent" VOID DriverUnload(PDRIVER_OBJECT DriverObject); PKEVENT __Event; HANDLE __EventHandle; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING EventName; PDEVICE_OBJECT DeviceObject = NULL; DriverObject->DriverUnload = DriverUnload; RtlInitUnicodeString(&EventName, EVENT_NAME); __Event = IoCreateNotificationEvent(&EventName, &__EventHandle); //获取已经有名字的内核对象的句柄 KeSetEvent(__Event, IO_NO_INCREMENT, FALSE); //设置激发态 return Status; } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { DbgPrint( "DriverUnload()\r\n" ); if (__EventHandle != NULL) { KeClearEvent(__Event); ZwClose(__EventHandle); __EventHandle = NULL; __Event = NULL; } } |
二.驱动程序与应用程序的事件交互(驱动程序创建事件——>应用程序设置事件)IoCreateNotificationEvent ——> OpenEvent
应用程序中创建的事件和在内核模式下创建的事件对象,本质上是同一个东西。在用户模式下,它用句柄代表,在内核模式下,它用KEVENT数据结构代表。
在应用程序中,所有内核对象都不会被用户看到,用户看到的只是代表内核对象的对象句柄。
__Event = IoCreateNotificationEvent(&EventName, &__EventHandle); //DriverEntry 进程回调通知
EventHandle = OpenEvent(
SYNCHRONIZE, //请求访问权限
FALSE, // 不继承
L"Global\\Ring0KernelEvent"); //事件对象名称
1.驱动程序IoCreateNotificationEvent创建事件
2.应用程序OpenEvent得到事件句柄
Ring3.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | // Ring3(设置).cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> #include <iostream> using namespace std; int main() { HANDLE EventHandle = NULL; while (TRUE) { EventHandle = OpenEvent( SYNCHRONIZE, //请求访问权限 FALSE, // 不继承 L "Global\\Ring0KernelEvent" ); //事件对象名称 if (EventHandle == NULL) { continue ; } break ; } cout << "Ring3等待" << endl; while (TRUE) { int Index = WaitForSingleObject(EventHandle, 3000); Index = Index - WAIT_OBJECT_0; if (Index == WAIT_TIMEOUT) { //注意这里当驱动卸载并关闭事件时事件对象是不能够得到及时的销毁 因为应用层占用了该对象 //所以我们长时间等待不到授信 就关闭并重新打开 if (EventHandle != NULL) { CloseHandle(EventHandle); EventHandle = NULL; EventHandle = OpenEvent(SYNCHRONIZE, FALSE, L "Global\\Ring0KernelEvent" ); if (EventHandle == NULL) { cout << "对象已经不存在" << endl; break ; } } continue ; } if (Index == 0) //有信号状态 { cout << "Ring0触发Ring3" << endl; } if (Index == WAIT_FAILED) { break ; } Sleep(1); } cout << "Input AnyKey To Exit" << endl; getchar (); if (EventHandle != NULL) { CloseHandle(EventHandle); EventHandle = NULL; } return 0; } |
Ring0.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <ntifs.h> #define EVENT_NAME L"\\BaseNamedObjects\\Ring0KernelEvent" VOID DriverUnload(PDRIVER_OBJECT DriverObject); PKEVENT __Event; HANDLE __EventHandle; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject = NULL; UNICODE_STRING EventName; RtlInitUnicodeString(&EventName, EVENT_NAME); DriverObject->DriverUnload = DriverUnload; __Event = IoCreateNotificationEvent(&EventName, &__EventHandle); //DriverEntry 进程回调通知 return Status; } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { DbgPrint( "DriverUnload()\r\n" ); if (__EventHandle != NULL) { KeClearEvent(__Event); ZwClose(__EventHandle); __EventHandle = NULL; __Event = NULL; } } |
三.应用程序与驱动程序的事件交互(应用程序创建事件——>驱动程序设置事件) DeviceIoControl ——> ObReferenceObjectByHandle
要将用户模式下创建的事件传递给驱动程序,可以用DeviceIoControl API函数。DDK提供了内核函数将句柄转化为指针,该函数如下:
NTSTATUS
ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
);
ObReferenceObjectByHandle函数在得到指针的同时,会为对象的指针维护一个计数。每次调用ObReferenceObjectByHandle函数时会使计数加1.因此为了计数平衡,在使用完 ObReferenceObjectByHandle函数后,需要调用如下函数:
VOID
ObDereferenceObject(
IN PVOID Object
);
ObDereferenceObject函数使计数减一。
1.应用程序通过符号链接名由CreateFile函数得到设备句柄
HANDLE DeviceHandle = CreateFile(DeviceLinkName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
2.应用程序CreateEvent创建事件
//创建自动重置的,初始为未激发的事件对象
EventHandle[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
3.应用程序通过DeviceIoControl 函数将用户模式下创建的事件传递给驱动程序
//调用DeviceIoControl把事件句柄传进内核
IsOk = DeviceIoControl(DeviceHandle, CTL_EVENT,
EventHandle,
sizeof(HANDLE) * 2,
NULL,
0,
&ReturnLength,
NULL);
//调用DeviceIoControl,通知驱动程序设置事件激发状态
IsOk = DeviceIoControl(DeviceHandle, CTL_SET_EVENT,
NULL,
0,
NULL,
0,
&ReturnLength,
NULL);
4.驱动程序通过ObReferenceObjectByHandle将句柄转化为PKEVENT指针
/把句柄转化为KEvent结构
Status = ObReferenceObjectByHandle(
(HANDLE)EventHandle[i], //Irp->AssociatedIrp.SystemBuffer 句柄
SYNCHRONIZE, //权限
*ExEventObjectType, //对象类型,对象类型
KernelMode, //访问模式分KernelMode
&__KernelEvent[i], //指向映射句柄对象的指针
NULL);
Ring3.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #include "stdafx.h" #include <windows.h> #include <iostream> using namespace std; #define CTL_EVENT \ CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) #define CTL_SET_EVENT \ CTL_CODE(FILE_DEVICE_UNKNOWN,0x831,METHOD_BUFFERED,FILE_ANY_ACCESS) HANDLE SeOpenDeviceObject( WCHAR * DeviceLinkName); DWORD WINAPI ThreadProcedure( LPVOID ParameterData); int main() { HANDLE DeviceHandle = SeOpenDeviceObject(L "\\\\.\\Ring0DeviceLinkName" ); if (DeviceHandle == NULL) { return 0; } ULONG i = 0; HANDLE EventHandle[3] = { 0 }; for (i = 0; i < 3; i++) { //创建自动重置的,初始为未激发的事件对象 EventHandle[i] = CreateEvent(NULL, FALSE, FALSE, NULL); } BOOL IsOk = 0; DWORD ReturnLength = 0; //调用DeviceIoControl把事件句柄传进内核 IsOk = DeviceIoControl(DeviceHandle, CTL_EVENT, EventHandle, sizeof ( HANDLE ) * 2, NULL, 0, &ReturnLength, NULL); if (IsOk == FALSE) { goto Exit; } HANDLE ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcedure, ( PVOID )EventHandle, 0, NULL); //调用DeviceIoControl,通知驱动程序设置事件激发状态 IsOk = DeviceIoControl(DeviceHandle, CTL_SET_EVENT, NULL, 0, NULL, 0, &ReturnLength, NULL); if (IsOk == FALSE) { cout << "Send IoCode Error" << endl; SetEvent(EventHandle[2]); WaitForSingleObject(ThreadHandle, INFINITE); goto Exit; } WaitForSingleObject(ThreadHandle, INFINITE); Exit: { for (i = 0; i < 3; i++) { if (EventHandle[i] != NULL) { CloseHandle(EventHandle[i]); EventHandle[i] = NULL; } } if (ThreadHandle != NULL) { CloseHandle(ThreadHandle); ThreadHandle = NULL; } if (DeviceHandle != NULL) { CloseHandle(DeviceHandle); DeviceHandle = NULL; } } printf ( "卸载驱动后 Input AnyKey To Exit\r\n" ); getchar (); getchar (); return 0; } DWORD WINAPI ThreadProcedure( LPVOID ParameterData) { cout << "Ring3等待" << endl; //等待三个之中有激发状态的信号 DWORD Index = WaitForMultipleObjects(3, ( HANDLE *)ParameterData, FALSE, INFINITE); Index = Index - WAIT_OBJECT_0; if (Index == 2) //0 1 2 { printf ( "ThreadProcedure() Exit\r\n" ); return 0; } cout << "Ring0触发Ring3" << endl; cout << "输入任意键Ring3触发Ring0" << endl; getchar (); getchar (); SetEvent((( HANDLE *)ParameterData)[1]); //Ring0中KeWaitForSingleObject响应 printf ( "ThreadProcedure() Exit\r\n" ); return 0; } HANDLE SeOpenDeviceObject( WCHAR * DeviceLinkName) { HANDLE DeviceHandle = CreateFile(DeviceLinkName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (DeviceHandle == INVALID_HANDLE_VALUE) { return NULL; } return DeviceHandle; } |
Ring0.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | #include <ntifs.h> #define CTL_EVENT \ CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) #define CTL_SET_EVENT \ CTL_CODE(FILE_DEVICE_UNKNOWN,0x831,METHOD_BUFFERED,FILE_ANY_ACCESS) #define DEVICE_OBJECT_NAME L"\\Device\\Ring0DeviceObjectName" //设备与设备之间通信 #define DEVICE_LINK_NAME L"\\DosDevices\\Ring0DeviceLinkName" NTSTATUS PassThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp); VOID DriverUnload(PDRIVER_OBJECT DriverObject); NTSTATUS Ring3EventHandleToRing0KernelEvent( HANDLE * EventHandle, ULONG_PTR EventHandleCount); PKEVENT __KernelEvent[20] = { 0 }; ULONG_PTR __KernelEventCount = 0; extern POBJECT_TYPE* ExEventObjectType; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { UNREFERENCED_PARAMETER(RegisterPath); NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject = NULL; UNICODE_STRING DeviceObjectName; UNICODE_STRING DeviceLinkName; ULONG i; DriverObject->DriverUnload = DriverUnload; //创建设备对象名称 RtlInitUnicodeString(&DeviceObjectName, DEVICE_OBJECT_NAME); //创建设备对象 Status = IoCreateDevice(DriverObject, NULL, &DeviceObjectName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject); if (!NT_SUCCESS(Status)) { return Status; } //创建设备连接名称 RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME); //将设备连接名称与设备名称关联 Status = IoCreateSymbolicLink(&DeviceLinkName, &DeviceObjectName); if (!NT_SUCCESS(Status)) { IoDeleteDevice(DeviceObject); return Status; } //设计符合我们代码的派遣历程 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = PassThroughDispatch; //函数指针 } DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlThroughDispatch; return STATUS_SUCCESS; } NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS Status = STATUS_UNSUCCESSFUL; ULONG_PTR Information = 0; PVOID InputData = NULL; ULONG InputDataLength = 0; PVOID OutputData = NULL; ULONG OutputDataLength = 0; ULONG IoControlCode = 0; PEPROCESS EProcess = NULL; PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp); //Irp堆栈 IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode; InputData = Irp->AssociatedIrp.SystemBuffer; OutputData = Irp->AssociatedIrp.SystemBuffer; InputDataLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength; OutputDataLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; switch (IoControlCode) { case CTL_EVENT: { if (InputData != NULL&&InputDataLength == sizeof ( HANDLE )*2) { Status = Ring3EventHandleToRing0KernelEvent(( HANDLE *)InputData, InputDataLength / sizeof ( HANDLE )); } Information = 0; break ; } case CTL_SET_EVENT: { DbgPrint( "Ring0触发Ring3\r\n" ); KeSetEvent(__KernelEvent[0], IO_NO_INCREMENT, FALSE); //Ring3层线程中WaitForMultipleObjects响应 DbgPrint( "Ring0等待\r\n" ); Status = KeWaitForSingleObject(__KernelEvent[1], Executive, KernelMode, FALSE, NULL); //注意这里的最后一个参数NULL 是永久等待 DbgPrint( "Ring3触发Ring0\r\n" ); Information = 0; break ; } default : { Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; Irp->IoStatus.Information = 0; break ; } } Irp->IoStatus.Status = Status; Irp->IoStatus.Information = Information; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } NTSTATUS Ring3EventHandleToRing0KernelEvent( HANDLE * EventHandle, ULONG_PTR EventHandleCount) { NTSTATUS Status = STATUS_SUCCESS; PULONG_PTR HandleArray = NULL; ULONG i = 0; if (EventHandle==NULL) { return STATUS_UNSUCCESSFUL; } __KernelEventCount = EventHandleCount; for (i = 0; i < EventHandleCount; i++) { //把句柄转化为KEvent结构 Status = ObReferenceObjectByHandle( ( HANDLE )EventHandle[i], //Irp->AssociatedIrp.SystemBuffer 句柄 SYNCHRONIZE, //权限 *ExEventObjectType, //对象类型,对象类型 KernelMode, //访问模式分KernelMode &__KernelEvent[i], //指向映射句柄对象的指针 NULL); if (!NT_SUCCESS(Status)) { break ; } } if (Status != STATUS_SUCCESS) { for (i = 0; i < EventHandleCount; i++) { if (__KernelEvent[i] != NULL) { //递减计数 ObDereferenceObject(__KernelEvent[i]); __KernelEvent[i] = NULL; } } } return Status; } NTSTATUS PassThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; //LastError() Irp->IoStatus.Information = 0; //ReturnLength IoCompleteRequest(Irp, IO_NO_INCREMENT); //将Irp返回给Io管理器 return STATUS_SUCCESS; } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { int i = 0; UNICODE_STRING DeviceLinkName; PDEVICE_OBJECT v1 = NULL; PDEVICE_OBJECT DeleteDeviceObject = NULL; RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME); IoDeleteSymbolicLink(&DeviceLinkName); DeleteDeviceObject = DriverObject->DeviceObject; while (DeleteDeviceObject != NULL) { v1 = DeleteDeviceObject->NextDevice; IoDeleteDevice(DeleteDeviceObject); DeleteDeviceObject = v1; } for (i = 0; i < __KernelEventCount; i++) { if (__KernelEvent[i] != NULL) { ObDereferenceObject(__KernelEvent[i]); __KernelEvent[i] = NULL; } } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗