驅動開發:通過Async反向與內核通信

【驅動開發:通過Async反向與內核通信】在前幾篇文章中給大家具體解釋了驅動與應用層之間正向通信的一些經典案例 , 本章將繼續學習驅動通信,不過這次我們學習的是通過運用Async異步模式實現的反向通信,反向通信機制在開發中時常被用到,例如一個殺毒軟件如果監控到有異常進程運行或有異常注冊表被改寫后,該驅動需要主動的通知應用層進程讓其知道,這就需要用到驅動反向通信的相關知識點,如下將循序漸進的實現一個反向通信案例 。
在開始學習Async反向通信之前先來研究一個Sync正向通信案例,不論是正向反向通信其在通信模式上與《驅動開發:通過ReadFile與內核層通信》所介紹的通信模式基本一致,都是通過ReadFile觸發驅動中的IRP_MJ_READ讀取派遣,唯一的區別是在傳輸數據時使用了MmGetSystemAddressForMdl方式,它將給定MDL描述的物理頁面映射到系統空間,并調用RtlCopyMemory()將全局字符串復制到這個空間內,這樣客戶端就可以循環讀取內核傳出的數據 。
我們來看驅動端代碼是如何實現的這個功能,代碼并沒有什么特殊的無法理解的點,只是需要注意我們在驅動入口調用IoCreateDevice()時傳入了第二個參數FILE_DEVICE_EXTENSION , 該參數的作用是,創建設備時,指定設備擴展內存的大小,傳一個值進去,就會給設備分配一塊非頁面內存 。
#include <ntddk.h>#include <stdio.h>// 保存一段非分頁內存,用于給全局變量使用#define FILE_DEVICE_EXTENSION 4096// 定義全局字符串static int global_count = 0;static char global_char[5][128] = { 0 };// 驅動綁定默認派遣函數NTSTATUS _DefaultDispatch(PDEVICE_OBJECT _pDeviceObject, PIRP _pIrp){ _pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; _pIrp->IoStatus.Information = 0; IoCompleteRequest(_pIrp, IO_NO_INCREMENT); return _pIrp->IoStatus.Status;}// 驅動創建后觸發NTSTATUS _SyncCreateCloseDispatch(PDEVICE_OBJECT _pDevcieObject, PIRP _pIrp){ _pIrp->IoStatus.Status = STATUS_SUCCESS; _pIrp->IoStatus.Information = 0; IoCompleteRequest(_pIrp, IO_NO_INCREMENT); return _pIrp->IoStatus.Status;}// 應用層讀數據后觸發NTSTATUS _SyncReadDispatch(PDEVICE_OBJECT _pDeviceObject, PIRP _pIrp){ NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(_pIrp); PVOID pBuffer = NULL; ULONG uBufferLen = 0; do {// 讀寫請求使用的是直接I/O方式pBuffer = MmGetSystemAddressForMdl(_pIrp->MdlAddress);if (pBuffer == NULL){status = STATUS_UNSUCCESSFUL;break;}uBufferLen = pIrpStack->Parameters.Read.Length;DbgPrint("讀字節長度: %d \n", uBufferLen);// 最大支持20字節讀請求uBufferLen = uBufferLen >= 20 ? 20 : uBufferLen;// 輸出五次字符串if (global_count < 5){RtlCopyMemory(pBuffer, global_char[global_count], uBufferLen);global_count = global_count + 1;} } while (FALSE); // 填寫返回狀態及返回大小 _pIrp->IoStatus.Status = status; _pIrp->IoStatus.Information = uBufferLen; // 完成IRP IoCompleteRequest(_pIrp, IO_NO_INCREMENT); return status;}// 卸載驅動VOID _UnloadDispatch(PDRIVER_OBJECT _pDriverObject){ // 刪除創建的設備 UNICODE_STRING  Win32DeviceName; RtlInitUnicodeString(&Win32DeviceName, L"\\DosDevices\\LySharkSync"); IoDeleteDevice(_pDriverObject->DeviceObject);}// 驅動入口NTSTATUS DriverEntry(PDRIVER_OBJECT _pDriverObject, PUNICODE_STRING _pRegistryPath){ UNICODE_STRING DeviceName, Win32DeivceName; PDEVICE_OBJECT pDeviceObject = NULL; NTSTATUS status; HANDLE hThread; OBJECT_ATTRIBUTES ObjectAttributes; // 設置符號名 RtlInitUnicodeString(&DeviceName, L"\\Device\\LySharkSync"); RtlInitUnicodeString(&Win32DeivceName, L"\\DosDevices\\LySharkSync"); // 循環初始化IRP函數 for (ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {_pDriverObject->MajorFunction[i] = _DefaultDispatch; } // 再次覆蓋派遣函數 _pDriverObject->MajorFunction[IRP_MJ_CREATE] = _SyncCreateCloseDispatch; _pDriverObject->MajorFunction[IRP_MJ_CLOSE] = _SyncCreateCloseDispatch; _pDriverObject->MajorFunction[IRP_MJ_READ] = _SyncReadDispatch; _pDriverObject->DriverUnload = _UnloadDispatch; // 分配一個自定義擴展 大小為sizeof(DEVEXT) // By: LyShark.com status = IoCreateDevice(_pDriverObject, sizeof(FILE_DEVICE_EXTENSION), &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject); if (!NT_SUCCESS(status))return status; if (!pDeviceObject)return STATUS_UNEXPECTED_IO_ERROR; // 為全局變量賦值 strcpy(global_char[0], "hi,lyshark A"); strcpy(global_char[1], "hi,lyshark B"); strcpy(global_char[2], "hi,lyshark C"); strcpy(global_char[3], "hi,lyshark D"); strcpy(global_char[4], "hi,lyshark E"); // 指定讀寫方式為 直接I/O MDL模式 pDeviceObject->Flags |= DO_DIRECT_IO; // 數據傳輸時地址校驗大小 pDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; status = IoCreateSymbolicLink(&Win32DeivceName, &DeviceName); pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS;}

推薦閱讀