事件很简单分别分为 事件状态. 以及事件类别.windows
事件状态:
有信号 Signaled
无信号 Non-signaled
事件类别
自动恢复 Synchronization 自动设置
不自动恢复. Notification 手动设置数据结构
事件的建立函数app
** IoCreateNotificationEvent() **函数
** KeClearEvent() ** 设置为无信号状态线程
** KeResetEvent() ** 设置为无信号状态并返回以前的状态
** KeSetEvent()** 设置事件为有信号.指针
其实理解有信号跟无信号就能够了. 有信号了.个人等待函数才能够等待.
无信号就会阻塞在哪里.code
事件的类别就是等待以后 根据你的设置.是自动设置为无信号. 仍是不设置.
若是自动设置为无信号.那么下个线程来就会阻塞.直到咱们设置为事件为有信号.才能够.orm
在内核中通常使用事件是使用匿名内核事件. 而不是使用IoCreateNotificationEvent对象
代码以下:blog
KEVENT myKevent; KeInitializeEvent(&myKevent, NotificationEvent,FALSE); //设置事件为有信号 KeSetEvent(&myKevent,IO_NO_INCREMENT,FALSE); //等待事件 KeWaitForSingleObject(&myEvent,Executive,KernerMode,False,NULL); //由于设置的类别是手动设置类别.因此咱们本身要把事件信号设置为无信号 //调用两个均可以 KeResetEvent(&myEvent); KeClearEvent(&myEvent);
若是ring0跟ring3通信.就要使用咱们上面说的
ring0 -> ring3通信的命名函数了.
IoCreateNotificationEvent
在使用Ring0 -> ring3通信的时候.咱们要了解下这个函数以及其它相关的知识
1.ring0 建立命名事件 - > ring3使用这个事件. 那么就须要创建一个名字了.名字以下;
** L"\\BaseNamedObjects\\你自定义的名字
2.再探 IoCreateDevice**函数的做用.
IoCreateDevice 函数.众所周知.是创建设备对象.
定义以下:
NTSTATUS IoCreateDevice( PDRIVER_OBJECT DriverObject, ULONG DeviceExtensionSize, //设备扩展大小 PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType, ULONG DeviceCharacteristics, BOOLEAN Exclusive, PDEVICE_OBJECT *DeviceObject );
咱们先前所说.建立设备对象的时候.第二个参数是设备扩展大小.
咱们一直给0.可是如今由于 ring0 - ring3通讯. 须要咱们自定义数据结构.进行存储ring0的数据. 那么可使用这个设备扩展了.
如:
咱们建立一个结构体. 将这个结构体的大小传入到第二个参数中.
使用的时候在咱们建立的设备对象中.有一个成员.是s DeviceExtension.这个就是咱们设备扩展为咱们申请的那块内存.
咱们能够转化为咱们自定义结构体大小.
代码很简单.以下:
typedef struct _MYDEVICE_EXTENSION { //自定义数据 }MYDEVICE_EXTENSION,*PMYDEVICE_EXTENSION; IoCreateDevice(DriverObject,sizeof(MYDEVICE_EXTENSION),....); 主要就是第二个参数. 使用: PMYDEVICE_EXTENSION pMyDevice = (PMYDEVICE_EXTENSION)Device->DeviceExtension; 这个成员就指向咱们扩展的内存. 强转为咱们的指针便可. pMyDevice->xxx = xxx; pMyDevice->xxx = xxx;
最后使用内核建立事件 进行建立便可. IoCreateNotificationEvent
ring3想使用ring0下定义的Event很简单.
以下:
#define EVENT_NAME L"\\Global\\xxx" HANDLE hEvent = OpenEventW(SYNCHRONIZE,FASE,EVENT_NAME); while(WaitForSingleObject(hEvent,INFINITE)) { 发送 DeviceIoControl读取内核层的数据便可.(上面说的设备扩展数据) }
ring3等待ring0的事件就很简单了. 直接打开事件.等待便可.
进程监视.首先会用到上面所说内容.而后分为下面几个步骤
1.建立设备对象.设备对象中扩展属性咱们自定义结构体.传入结构体大小便可.
2.建立全局设备对象变量指针.保存建立的设备对象
3.建立符号连接,ring3 跟 ring 0进行通信
4.建立控制派遣函数.接受ring3下发的控制吗.
5.使用IoCreateNotificationEvent建立事件对象.用于Ring3跟Ring0的事件同步.
6.注册进程控制回调函数.当进程建立.或者销毁会调用回调
7.回调函数,全局设备对象指针的子成员.指向咱们自定义结构体.
转换一下. 赋值参数.而且设置事件对象
8.ring3读取数据的时候.控制函数将回调函数中赋值出来的数据拷贝给
ring3便可.
9.ring3进行打开事件.等待事件.发送DeviceIoControl控制吗.读取数据.显示 数据.
代码以下:
ring0:
#include <ntddk.h> #include <ntstrsafe.h> /* 符号链接名 设备对象名 事件等待名 */ #define IBINARY_LINKNAME L"\\DosDevices\\IBinarySymboliclnk" #define IBINARY_DEVICENAME L"\\Device\\IBinaryProcLook" #define IBINARY_EVENTNAME L"\\BaseNamedObjects\\ProcLook" //定义 ring0 ring3控制码 #define CTRLCODE_BASE 0x8000 #define MYCTRL_CODE(i) \ CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE +i,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_PROCESS_LOCK_READ MYCTRL_CODE(1) UNICODE_STRING g_uSymbolicLinkName = { 0 }; //控制派遣函数.以及卸载函数. void DriverUnLoad(PDRIVER_OBJECT pDriverObject); NTSTATUS InitDeviceAnSymbolicLink( PDRIVER_OBJECT pDriverObj, UNICODE_STRING uDeviceName, UNICODE_STRING uSymbolicLinkName, UNICODE_STRING uEventName); NTSTATUS DisPatchComd(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DisPatchIoControl(PDEVICE_OBJECT pDeviceObject,PIRP pIrp); VOID pMyCreateRoutine (IN HANDLE pParentId,HANDLE hProcessId,BOOLEAN bisCreate); //自定义设备扩展.以及全局变量指针.进行保存的. typedef struct _Device_Exten { /* 自定义数据.好比保存 进程PID 父PID 进程事件对象 全局事件对象 */ HANDLE hProcess; //进程句柄 PKEVENT pkProcessEvent; //全局事件对象,ring3使用 HANDLE hProcessId; //进程的PID HANDLE hpParProcessId; //父进程ID.当前你也能够有进程名字 BOOLEAN bIsCreateMark; //表示是建立进程仍是销毁.建立进程回调能够看到 }DEVICE_EXTEN,* PDEVICE_EXTEN; PDEVICE_OBJECT g_PDeviceObject; //定义ring3->读取ring0的数据 typedef struct _PROCESS_LONNK_READDATA { HANDLE hProcessId; HANDLE hpParProcessId; BOOLEAN bIsCreateMark; }PROCESS_LONNK_READDATA,*PPROCESS_LONNK_READDATA; NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS ntStatus; UNICODE_STRING uDeviceName = { 0 }; UNICODE_STRING uEventName = { 0 }; //setp 1注册卸载函数,以及设置通信方式 pDriverObject->DriverUnload = DriverUnLoad; //setp 2 初始化符号连接名.设备名. 以及事件对象名字,而且检验一下 ntStatus = RtlUnicodeStringInit(&uDeviceName, IBINARY_DEVICENAME); if (!NT_SUCCESS(ntStatus)) { KdPrint(("初始化设备名称失败")); return ntStatus; } KdPrint(("初始化设备名称成功")); ntStatus = RtlUnicodeStringInit(&g_uSymbolicLinkName, IBINARY_LINKNAME); if (!NT_SUCCESS(ntStatus)) { KdPrint(("初始化符号连接名字失败")); return ntStatus; } KdPrint(("初始化符号连接名字成功")); ntStatus = RtlUnicodeStringInit(&uEventName, IBINARY_EVENTNAME); if (!NT_SUCCESS(ntStatus)) { KdPrint(("初始化全局事件对象失败")); return ntStatus; } KdPrint(("初始化全局事件对象成功")); //setp 3创建一个函数.函数内部进行初始化设备对象.初始化符号连接.初始化全局事件对象. ntStatus = InitDeviceAnSymbolicLink( pDriverObject, uDeviceName, g_uSymbolicLinkName, uEventName); return ntStatus; } //卸载驱动.关闭符号连接 void DriverUnLoad(PDRIVER_OBJECT pDriverObject) { NTSTATUS ntStatus; UNICODE_STRING SymboLicLinkStr = { 0 }; ntStatus = RtlUnicodeStringInit(&SymboLicLinkStr, IBINARY_LINKNAME); if (NT_SUCCESS(ntStatus)) { ntStatus = IoDeleteSymbolicLink(&SymboLicLinkStr); if (!NT_SUCCESS(ntStatus)) { KdPrint(("删除符号连接失败")); } } IoDeleteDevice(pDriverObject->DeviceObject); PsSetCreateProcessNotifyRoutine(pMyCreateRoutine, TRUE); KdPrint(("驱动已卸载")); } NTSTATUS InitDeviceAnSymbolicLink( PDRIVER_OBJECT pDriverObj, UNICODE_STRING uDeviceName, UNICODE_STRING uSymbolicLinkName, UNICODE_STRING uEventName) { NTSTATUS ntStatus; PDEVICE_OBJECT pDeviceObject = NULL; //使用自定义结构 ULONG i = 0; ntStatus = IoCreateDevice( pDriverObj, sizeof(DEVICE_EXTEN),//使用设备扩展.指定大小.那么设备对象中成员就会指向这块内存 &uDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, //独占设备 &pDeviceObject); if (!NT_SUCCESS(ntStatus)) { KdPrint(("建立设备对象失败")); IoDeleteDevice(pDeviceObject); return ntStatus; } pDriverObj->Flags |= DO_BUFFERED_IO; //成功以后保存到全局变量中 KdPrint(("建立设备对象成功")); g_PDeviceObject = pDeviceObject; //建立事件.ring3->ring0的事件 PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)pDeviceObject->DeviceExtension; pDeviceExten->pkProcessEvent = IoCreateNotificationEvent(&uEventName, &pDeviceExten->hProcess); KeClearEvent(pDeviceExten->pkProcessEvent); //建立符号连接 ntStatus = IoCreateSymbolicLink(&g_uSymbolicLinkName, &uDeviceName); if (!NT_SUCCESS(ntStatus)) { KdPrint(("建立符号连接失败")); IoDeleteDevice(pDeviceObject); return ntStatus; } KdPrint(("建立符号连接成功")); /* 由于设备对象扩展咱们传入了DEVICE_EXTEN大小.因此在调用IoCreateDevice的时候.返回的 设备对象中.设备对象会根据咱们传入的大小建立一块内存.这块内存就保存在DeviceExtension 这个字段中. 下面调用IoCreateNotificationEvent是建立了一个命名事件.咱们将事件放到咱们结构体中. 这个函数建立的事件必须手工设置事件状态.因此咱们首先初始化为无信号状态. 总的来讲.IoCreateNotificationEvent建立的时候须要一个HANDLE以及一个PKEVENT. */ //注册回调控制函数.当进程来了会通知. // PsSetCreateProcessNotifyRoutine ntStatus = PsSetCreateProcessNotifyRoutine(pMyCreateRoutine,FALSE); //FASLE为注册 if (!NT_SUCCESS(ntStatus)) { KdPrint(("注册系统回调失败")); IoDeleteDevice(pDeviceObject); return ntStatus; } KdPrint(("注册系统回调成功")); //初始化派遣函数 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { pDriverObj->MajorFunction[i] = DisPatchComd; } pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DisPatchIoControl; return STATUS_SUCCESS; } //当进程来的时候.会通知你. VOID pMyCreateRoutine( IN HANDLE pParentId, HANDLE hProcessId, BOOLEAN bisCreate) { /* 进程来的时候会通知咱们.因此咱们给设备扩展进行赋值.赋值进程ID以及是否建立 */ PDEVICE_EXTEN pDeviceExten =(PDEVICE_EXTEN)g_PDeviceObject->DeviceExtension; pDeviceExten->hProcessId = hProcessId; pDeviceExten->hpParProcessId = pParentId; pDeviceExten->bIsCreateMark = bisCreate; //赋值完毕以后.设置信号状态为有信号. 这样Ring3就会等待到事件了. KeSetEvent(pDeviceExten->pkProcessEvent,0,FALSE); //通知ring3能够读取了.那么还要设置为ring0的事件为无信号.用来保持同步 //KeClearEvent(pDeviceExten->pkProcessEvent); KeResetEvent(pDeviceExten->pkProcessEvent); //跟ClearEvent同样.上面的快.这个会返回上一个设置的信号状态.都用一次 } NTSTATUS DisPatchComd(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return pIrp->IoStatus.Status; } NTSTATUS DisPatchIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { /* Ring3 -> ring0通信的控制派遣函数.自定义控制码.获取Irp堆栈.获取缓冲区. */ NTSTATUS ntStatus; PIO_STACK_LOCATION pIrpStack; PVOID pUserOutPutBuffer; PPROCESS_LONNK_READDATA pReadData; ULONG uIoControl = 0; ULONG uReadLength; ULONG uWriteLeng; PDEVICE_EXTEN pDeviceExten; /* 开始解析用户操做 */ KdPrint(("解析用户控制码")); pIrpStack = IoGetCurrentIrpStackLocation(pIrp); //从堆栈中获取用户控制数据 pUserOutPutBuffer = pIrp->AssociatedIrp.SystemBuffer; //若是控制码是缓冲区方式.就使用这个. //定义读取的数据 pReadData = (PPROCESS_LONNK_READDATA)pUserOutPutBuffer; //获取控制码.长度.进行读取 uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode; uReadLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength; uWriteLeng = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; switch (uIoControl) { case IOCTL_PROCESS_LOCK_READ: //拷贝数据便可. pDeviceExten = (PDEVICE_EXTEN)g_PDeviceObject->DeviceExtension; pReadData->hProcessId = pDeviceExten->hProcessId; pReadData->hpParProcessId = pDeviceExten->hpParProcessId; pReadData->bIsCreateMark = pDeviceExten->bIsCreateMark; KdPrint(("内核读取 父ID = %d,子Id = %d,是否建立 = %d", (ULONG)pDeviceExten->hpParProcessId, (ULONG)pDeviceExten->hProcessId, (ULONG)pDeviceExten->bIsCreateMark)); break; default: KdPrint(("其它控制码")); ntStatus = STATUS_INVALID_PARAMETER; uWriteLeng = 0; break; } pIrp->IoStatus.Information = uWriteLeng; //读取的字节数 pIrp->IoStatus.Status = ntStatus; IoCompleteRequest(pIrp,IO_NO_INCREMENT); return ntStatus; }
ring3下打开事件对象便可. 注意我本身写的是打开 全局事件对象\\Global
而后发送控制码.ring0进行赋值便可.
ring3代码.
// ProcWatchClientConsole.cpp : Defines the entry point for the console application. // #include "windows.h" #include "winioctl.h" #include "stdio.h" #define EVENT_NAME L"Global\\ProcLook" #define CTRLCODE_BASE 0x8000 #define MYCTRL_CODE(i) \ CTL_CODE(FILE_DEVICE_UNKNOWN,CTRLCODE_BASE +i,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_PROCESS_LOCK_READ MYCTRL_CODE(1) #define IOCTL_PROCESS_LOCK_READ MYCTRL_CODE(1) typedef struct _PROCESS_LONNK_READDATA { HANDLE hProcessId; HANDLE hpParProcessId; BOOLEAN bIsCreateMark; }PROCESS_LONNK_READDATA, *PPROCESS_LONNK_READDATA; int main(int argc, char* argv[]) { PROCESS_LONNK_READDATA pmdInfoNow = { 0 }; PROCESS_LONNK_READDATA pmdInfoBefore = { 0 }; // 打开驱动设备对象 HANDLE hDriver = ::CreateFile( "\\\\.\\IBinarySymboliclnk", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDriver == INVALID_HANDLE_VALUE) { printf("Open device failed:%x\n", GetLastError()); return -1; } // 打开内核事件对象 HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME); if (NULL == hProcessEvent) { OutputDebugString("打开事件对象失败"); system("pause"); return 0; } OutputDebugString("打开事件对象成功"); while (TRUE) { ::WaitForSingleObject(hProcessEvent, INFINITE); //等待事件 DWORD dwRet = 0; BOOL bRet = FALSE; bRet = ::DeviceIoControl( hDriver, IOCTL_PROCESS_LOCK_READ, NULL, 0, &pmdInfoNow, sizeof(pmdInfoNow), &dwRet, NULL); if (!bRet) { OutputDebugString("发送控制码失败"); system("pause"); return 0; } OutputDebugString("Ring3发送控制码成功"); if (bRet) { if (pmdInfoNow.hpParProcessId != pmdInfoBefore.hpParProcessId || \ pmdInfoNow.hProcessId != pmdInfoBefore.hProcessId || \ pmdInfoNow.bIsCreateMark != pmdInfoBefore.bIsCreateMark) { if (pmdInfoNow.bIsCreateMark) { printf("进程建立 PID = %d\n", pmdInfoNow.hProcessId); } else { printf("进程退出,PID = %d\n", pmdInfoNow.hProcessId); } pmdInfoBefore = pmdInfoNow; } } else { printf("Get Proc Info Failed!\n"); break; } } ::CloseHandle(hDriver); system("pause"); return 0; }
注意,ring0下设置的进程系统回调是用的 PsSetCreateProcessNotifyRoutine 这个内核函数只能监视
进程ID 父进程ID以及一个建立或者结束标记. 咱们可使用Ex系列.这样的话能够监视到进程的名字.等等.
演示