內核事件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
#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
#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
// 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
#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
#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
#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; } } }
內核事件KEVENT(同步)