事件很簡單分別分爲 事件狀態. 以及事件類別.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系列.這樣的話能夠監視到進程的名字.等等.
演示