1. 程式人生 > >內核事件KEVENT(同步)

內核事件KEVENT(同步)

ica i++ 函數指針 obj ifs () seh 存在 nap

轉載請您註明出處: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(同步)