<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
驅動與應用程式的通訊是非常有必要的,核心中執行程式碼後需要將其動態顯示給應用層,但驅動程式與應用層畢竟不在一個地址空間內,為了實現核心與應用層資料互動則必須有通訊的方法,微軟為我們提供了三種通訊方式,如下先來介紹通過ReadFile系列函數實現的通訊模式。
長話短說,不說沒用的概念,首先系統中支援的通訊模式可以總結為三種。
而通過ReadFile,WriteFile
系列函數實現的通訊機制則屬於緩衝區通訊模式,在該模式下作業系統會將應用層中的資料複製到核心中,此時應用層呼叫ReadFile,WriteFile
函數進行讀寫時,在驅動內會自動觸發 IRP_MJ_READ
與 IRP_MJ_WRITE
這兩個派遣函數,在派遣函數內則可以對收到的資料進行各類處理。
首先需要實現初始化各類派遣函數這麼一個案例,如下程式碼則是通用的一種初始化派遣函數的基本框架,分別處理了IRP_MJ_CREATE
建立派遣,以及IRP_MJ_CLOSE
關閉的派遣,此外函數DriverDefaultHandle
的作用時初始化其他派遣用的,也就是將除去CREATE/CLOSE
這兩個派遣之外,其他的全部賦值成初始值的意思,當然不增加此段程式碼也是無妨,並不影響程式碼的實際執行。
#include <ntifs.h> // 解除安裝驅動執行 VOID UnDriver(PDRIVER_OBJECT pDriver) { PDEVICE_OBJECT pDev; // 用來取得要刪除裝置物件 UNICODE_STRING SymLinkName; // 區域性變數symLinkName pDev = pDriver->DeviceObject; IoDeleteDevice(pDev); // 呼叫IoDeleteDevice用於刪除裝置 RtlInitUnicodeString(&SymLinkName, L"\??\LySharkDriver"); // 初始化字串將symLinkName定義成需要刪除的符號連結名稱 IoDeleteSymbolicLink(&SymLinkName); // 呼叫IoDeleteSymbolicLink刪除符號連結 DbgPrint("驅動解除安裝完畢..."); } // 建立裝置連線 // LyShark.com NTSTATUS CreateDriverObject(IN PDRIVER_OBJECT pDriver) { NTSTATUS Status; PDEVICE_OBJECT pDevObj; UNICODE_STRING DriverName; UNICODE_STRING SymLinkName; // 建立裝置名稱字串 RtlInitUnicodeString(&DriverName, L"\Device\LySharkDriver"); Status = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj); // 指定通訊方式為緩衝區 pDevObj->Flags |= DO_BUFFERED_IO; // 建立符號連結 RtlInitUnicodeString(&SymLinkName, L"\??\LySharkDriver"); Status = IoCreateSymbolicLink(&SymLinkName, &DriverName); return STATUS_SUCCESS; } // 建立回撥函數 NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; // 返回成功 DbgPrint("派遣函數 IRP_MJ_CREATE 執行 n"); IoCompleteRequest(pIrp, IO_NO_INCREMENT); // 指示完成此IRP return STATUS_SUCCESS; // 返回成功 } // 關閉回撥函數 NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; // 返回成功 DbgPrint("派遣函數 IRP_MJ_CLOSE 執行 n"); IoCompleteRequest(pIrp, IO_NO_INCREMENT); // 指示完成此IRP return STATUS_SUCCESS; // 返回成功 } // 預設派遣函數 NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; } // 入口函數 // By: LyShark NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath) { DbgPrint("hello lyshark n"); // 呼叫建立裝置 CreateDriverObject(pDriver); pDriver->DriverUnload = UnDriver; // 解除安裝函數 pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; // 建立派遣函數 pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; // 關閉派遣函數 // 初始化其他派遣 for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DbgPrint("初始化派遣: %d n", i); pDriver->MajorFunction[i] = DriverDefaultHandle; } DbgPrint("驅動載入完成..."); return STATUS_SUCCESS; }
程式碼執行效果如下:
通用框架有了,接下來就是讓該驅動支援使用ReadWrite
的方式實現通訊,首先我們需要在DriverEntry
處增加兩個派遣處理常式的初始化。
// 入口函數 // By: LyShark NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath) { DbgPrint("hello lyshark n"); // 呼叫建立裝置 CreateDriverObject(pDriver); // 初始化其他派遣 for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DbgPrint("初始化派遣: %d n", i); pDriver->MajorFunction[i] = DriverDefaultHandle; } pDriver->DriverUnload = UnDriver; // 解除安裝函數 pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; // 建立派遣函數 pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; // 關閉派遣函數 // 增加派遣處理 pDriver->MajorFunction[IRP_MJ_READ] = DispatchRead; // 讀取派遣函數 pDriver->MajorFunction[IRP_MJ_WRITE] = DispatchWrite; // 寫入派遣函數 DbgPrint("驅動載入完成..."); return STATUS_SUCCESS; }
接著,我們需要分別實現這兩個派遣處理常式,如下DispatchRead
負責讀取時觸發,與之對應DispatchWrite
負責寫入觸發。
SystemBuffer
,當完成請求時I/O管理器將驅動程式已經提供的資料從系統緩衝區複製到使用者緩衝區。SystemBuffer
設定為地址,使用者緩衝區的內容會被複制到系統緩衝區,但是不設定UserBuffer
緩衝。通過IoGetCurrentIrpStackLocation(pIrp)
接收讀寫請求長度,偏移等基本引數,AssociatedIrp.SystemBuffer
則是讀寫緩衝區,IoStatus.Information
是輸出緩衝位元組數,Parameters.Read.Length
是讀取寫入的位元組數。
// 讀取回撥函數 NTSTATUS DispatchRead(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(pIrp); ULONG ulReadLength = Stack->Parameters.Read.Length; char szBuf[128] = "hello lyshark"; pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = ulReadLength; DbgPrint("讀取長度:%d n", ulReadLength); // 取出字串前5個位元組返回給R3層 memcpy(pIrp->AssociatedIrp.SystemBuffer, szBuf, ulReadLength); IoCompleteRequest(pIrp, IO_NO_INCREMENT); return Status; } // 接收傳入回撥函數 // By: LyShark NTSTATUS DispatchWrite(struct _DEVICE_OBJECT *DeviceObject, struct _IRP *Irp) { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); ULONG ulWriteLength = Stack->Parameters.Write.Length; PVOID ulWriteData = Irp->AssociatedIrp.SystemBuffer; // 輸出傳入字串 DbgPrint("傳入長度: %d 傳入資料: %s n", ulWriteLength, ulWriteData); IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
如上部分都是在講解驅動層面的讀寫派遣,應用層還沒有介紹,在應用層我們只需要呼叫ReadFile
函數當呼叫該函數時驅動中會使用DispatchRead
派遣例程來處理這個請求,同理呼叫WriteFile
函數則觸發的是DispatchWrite
派遣例程。
我們首先從核心中讀出前五個位元組並放入緩衝區內,輸出該緩衝區內的資料,然後在呼叫寫入,將hello lyshark
寫回到核心裡裡面,這段程式碼可以這樣來寫。
#include <iostream> #include <Windows.h> #include <winioctl.h> int main(int argc, char *argv[]) { HANDLE hDevice = CreateFileA("\\.\LySharkDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { CloseHandle(hDevice); return 0; } // 從核心讀取資料到本地 char buffer[128] = { 0 }; ULONG length; // 讀入到buffer長度為5 // By:lyshark.com ReadFile(hDevice, buffer, 5, &length, 0); for (int i = 0; i < (int)length; i++) { printf("讀取位元組: %c", buffer[i]); } // 寫入資料到核心 char write_buffer[128] = "hello lyshark"; ULONG write_length; WriteFile(hDevice, write_buffer, strlen(write_buffer), &write_length, 0); system("pause"); CloseHandle(hDevice); return 0; }
使用驅動工具安裝我們的驅動,然後執行該應用層程式,實現通訊,效果如下所示:
到此這篇關於C語言驅動開發之通過ReadFile與核心層通訊的文章就介紹到這了,更多相關C語言 ReadFile核心層通訊內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45