在学习驱动过程中,一个很重要的内容就是Ring3层与Ring0层的通信,方法有很多种,互斥体,信号量,文件等等,用的比较普遍的,还是事件。所以在学习的过程中,做了一个简单的Demo,主要是体会一下方法。
在驱动程序下,首先要定义一个事件名,前面的一部分必须是BaseNamedObjects,这其实就是一个目录,后面的部分可以自己起,但不要太过简单和普遍,以免与现有的冲突。
#define EVENT_NAME L"\\BaseNamedObjects\\Ring0Event"
定义两个全局变量
PKEVENT g_Event;
HANDLE g_EventHandle;
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
UNICODE_STRING EventName;
RtlInitUnicodeString(&EventName, EVENT_NAME); //需要UNICODE_STRING型,所以用RtlInitUnicodeString转换一下
DriverObject->DriverUnload = DriverUnload;
//IoCreateNotificationEvent例程创建或打开一个命名的通知事件,用来通知一个或多个线程执行一个事件发生。
g_Event = IoCreateNotificationEvent(&EventName, &g_EventHandle); //1参数输入,2参数输出
return Status;
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload()\r\n");
if (g_EventHandle != NULL)
{
KeClearEvent(g_Event);
ZwClose(g_EventHandle); //销毁资源
g_EventHandle = NULL;
g_Event = NULL;
}
}
应用层代码
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE EventHandle = NULL;
while (TRUE)
{
//事件名必须与驱动的相同
EventHandle = OpenEvent(SYNCHRONIZE, FALSE, L"Global\\Ring0Event");
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\\Ring0Event"); //第一参数为访问的事件对象,第二参数为是否继承,名字必须与驱动相同
if (EventHandle == NULL)
{
cout << "对象已经不存在" << endl;
break;
}
}
continue;
}
if (Index == 0) //成功
{
cout << "Ring0触发Ring3" << endl;
}
if (Index == WAIT_FAILED)
{
break;
}
Sleep(1);
}
if (EventHandle != NULL)
{
CloseHandle(EventHandle);
EventHandle = NULL;
}
getchar();
return 0;
}
上述代码在win7 x86 和win7 x64 的虚拟机下测试成功。