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

對于應用層來說并沒有什么特別的 , 同樣調用ReadFile讀取內核中的參數 , 同樣for循環讀取五次 , 代碼如下:
#include <stdio.h>#include <Windows.h>int main(int argc, char *argv[]){ HANDLE hFile; char Buffer[10] = { 0 }; DWORD dwRet = 0; BOOL bRet; hFile = CreateFileA("\\\\.\\LySharkSync", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE)return 0; for (int x = 0; x < 5; x++) {bRet = ReadFile(hFile, Buffer, 20, &dwRet, NULL);if (!bRet){CloseHandle(hFile);return 0;}printf("讀入數據: %s -> 讀取長度: %d \n", Buffer, dwRet); } return 0;}這段代碼運行效果如下:

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

文章插圖
與同步模式不同,異步模式雖然同樣使用ReadFile實現通信,但在通信中引入了Event事件通知機制 , 這也是異步與同步最大的區別所在,用戶層可以分別創建多個Event事件,等待內核依次做出相應并最終一并返回 。
首先驅動內定義了_DeviceExtension自定義接口,該接口用于保存此次事件所對應的Irp以及其所對應的DPC時間等 。
異步分發函數_AsyncReadDispatch同樣是被IRP_MJ_READ派遣函數觸發的,觸發后其內部會首先IoGetCurrentIrpStackLocation得到當前IRP的堆棧信息,然后設置IoMarkIrpPending()并最終將該IRP通過InsertTailList()插入到IRP鏈表內等待被處理 。
  • IoMarkIrpPending
    • 用于標記指定的IRP,標志著某個驅動的分發例程(分發函數)因需要被其他的驅動程序進一步處理最終返回STATUS_PENDING狀態 。
函數_CustomDpc則是定時器內部要執行的具體操作,在DriverEntry驅動入口處做了如下初始化,初始化了鏈表,并初始化了一個定時器 , 最后啟動這個定時器每隔1秒都會執行一次_CustomDpc如果我們的IRP鏈表內IsListEmpty() 檢測存在數據,則會主動拷貝內存RtlCopyMemory并推送到應用層 。
// 初始化IRP鏈表InitializeListHead(&pDevExt->IrpList);// 初始化定時器KeInitializeTimer(&(pDevExt->timer));// 初始化DPC pDevExt是傳給_CustomDpc函數的參數KeInitializeDpc(&pDevExt->dpc, (PKDEFERRED_ROUTINE)_CustomDpc, pDevExt);// 設置定時時間位1spDevExt->liDueTime = RtlConvertLongToLargeInteger(-10000000);// 啟動定時器KeSetTimer(&pDevExt->timer, pDevExt->liDueTime, &pDevExt->dpc);驅動層完成代碼如下所示:
#include <ntddk.h>// 自定義接口擴展typedef struct _DeviceExtension{ LIST_ENTRY IrpList; KTIMER timer; LARGE_INTEGER liDueTime; KDPC dpc;}DEV_EXT, *PDEV_EXT;// 默認派遣函數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 _AsyncCreateCloseDispatch(PDEVICE_OBJECT _pDevcieObject, PIRP _pIrp){ _pIrp->IoStatus.Status = STATUS_SUCCESS; _pIrp->IoStatus.Information = 0; IoCompleteRequest(_pIrp, IO_NO_INCREMENT); return  _pIrp->IoStatus.Status;}// 讀取派遣函數NTSTATUS _AsyncReadDispatch(PDEVICE_OBJECT _pDeviceObject, PIRP _pIrp){ NTSTATUS status; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(_pIrp); PDEV_EXT pDevExt = (PDEV_EXT)_pDeviceObject->DeviceExtension; IoMarkIrpPending(_pIrp); // 將IRP插入自定義鏈表中插入的是ListEntry InsertTailList(&pDevExt->IrpList, &_pIrp->Tail.Overlay.ListEntry); // 返回pending 主要返回給I/O管理器的值必須和IRP的Pending標志位一致 // By: LyShark.com // 即調用iomarkirppending和返回值要一致 return STATUS_PENDING;}// DPC線程VOID _CustomDpc(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2){ PIRP pIrp; PDEV_EXT pDevExt = (PDEV_EXT)DeferredContext; PVOID pBuffer = NULL; ULONG uBufferLen = 0; PIO_STACK_LOCATION pIrpStack = NULL; do {if (!pDevExt){break;}// 檢查尾端IRP鏈表是否為空 為空則跳出if (IsListEmpty(&pDevExt->IrpList)){break;}// 從IRP鏈表中取出一個IRP并完成該IRP 取出的是ListEntry的地址PLIST_ENTRY pListEntry = (PLIST_ENTRY)RemoveHeadList(&pDevExt->IrpList);if (!pListEntry)break;pIrp = (PIRP)CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);pIrpStack = IoGetCurrentIrpStackLocation(pIrp);DbgPrint("當前DPC Irp: 0x%x\n", pIrp);// 驅動程序的讀寫方式位直接I/OpBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);if (pBuffer == NULL){pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);break;}uBufferLen = pIrpStack->Parameters.Read.Length;DbgPrint("讀取DPC長度: %d\n", uBufferLen);// 支持5字節以下的讀請求uBufferLen = uBufferLen > 13 ? 13 : uBufferLen;// 復制請求內容RtlCopyMemory(pBuffer, "hello lyshark", uBufferLen);pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = uBufferLen;// 完成該IRPIoCompleteRequest(pIrp, IO_NO_INCREMENT); } while (FALSE); // 重新設置定時器 KeSetTimer(&pDevExt->timer, pDevExt->liDueTime, &pDevExt->dpc);}// 卸載驅動VOID _UnloadDispatch(PDRIVER_OBJECT _pDriverObject){ UNICODE_STRING Win32DeviceName; PDEV_EXT pDevExt = (PDEV_EXT)_pDriverObject->DeviceObject->DeviceExtension; RtlInitUnicodeString(&Win32DeviceName, L"\\DosDevices\\LySharkAsync"); // 刪除定時器 // LyShark KeCancelTimer(&pDevExt->timer); // 刪除創建的設備 IoDeleteDevice(_pDriverObject->DeviceObject);}// 驅動入口NTSTATUS DriverEntry(PDRIVER_OBJECT _pDriverObject, PUNICODE_STRING _pRegistryPath){ UNICODE_STRING DeviceName, Win32DeivceName; PDEVICE_OBJECT pDeviceObject = NULL; NTSTATUS status; PDEV_EXT pDevExt = NULL; HANDLE hThread; OBJECT_ATTRIBUTES ObjectAttributes; CLIENT_ID CID; RtlInitUnicodeString(&DeviceName, L"\\Device\\LySharkAsync"); RtlInitUnicodeString(&Win32DeivceName, L"\\DosDevices\\LySharkAsync"); for (ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {_pDriverObject->MajorFunction[i] = _DefaultDispatch; } _pDriverObject->MajorFunction[IRP_MJ_CREATE] = _AsyncCreateCloseDispatch; _pDriverObject->MajorFunction[IRP_MJ_CLOSE] = _AsyncCreateCloseDispatch; _pDriverObject->MajorFunction[IRP_MJ_READ] = _AsyncReadDispatch; _pDriverObject->DriverUnload = _UnloadDispatch; // 分配自定義擴展 status = IoCreateDevice(_pDriverObject, sizeof(DEV_EXT), &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject); if (!NT_SUCCESS(status))return status; if (!pDeviceObject)return STATUS_UNEXPECTED_IO_ERROR; pDeviceObject->Flags |= DO_DIRECT_IO; pDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; status = IoCreateSymbolicLink(&Win32DeivceName, &DeviceName); pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; pDevExt = (PDEV_EXT)pDeviceObject->DeviceExtension; // 初始化IRP鏈表 InitializeListHead(&pDevExt->IrpList); // 初始化定時器 KeInitializeTimer(&(pDevExt->timer)); // 初始化DPC pDevExt是傳給_CustomDpc函數的參數 KeInitializeDpc(&pDevExt->dpc, (PKDEFERRED_ROUTINE)_CustomDpc, pDevExt); // 設置定時時間位1s pDevExt->liDueTime = RtlConvertLongToLargeInteger(-10000000); // 啟動定時器 KeSetTimer(&pDevExt->timer, pDevExt->liDueTime, &pDevExt->dpc); return STATUS_SUCCESS;}

推薦閱讀