Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)
生活随笔
收集整理的這篇文章主要介紹了
Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Windows驅動開發學習筆記(四)—— 3環與0環通信(常規方式)
- 設備對象
- 創建設備對象
- 設置數據交互方式
- 創建符號鏈接
- IRP與派遣函數
- IRP的類型
- 其它類型的IRP
- 派遣函數
- 派遣函數注冊位置
- 注冊派遣函數
- 派遣函數的格式
- 實驗
- Ring 0代碼
- Ring 3代碼
- 第一步:運行Ring 0代碼
- 第二步:運行Ring3代碼
設備對象
描述:
創建設備對象
//創建設備名稱 UNICODE_STRING Devicename; RtlInitUnicodeString(&Devicename,L"\\Device\\MyDevice"); //"\\Device\\MyDevice"這個名字不要隨便改 //因為在這個樹形結構中存儲著所有內核對象 //若改變,將會把這個設備對象掛到其它樹中//創建設備對象 NTSTATUS status = IoCreateDevice(pDriver, //當前設備所屬的驅動對象(PDRIVER_OBJECT)0,&Devicename, //設備對象的名稱FILE_DEVICE_UNKNOWN, //設備對象類型FILE_DEVICE_SECURE_OPEN,FALSE,&pDeviceObj //設備對象指針(PDEVICE_OBJECT) );if( STATUS_SUCCESS != status ) {DbgPrint("創建設備失敗! . \r\n");return status; }設置數據交互方式
pDeviceObj->Flags |= DO_BUFFERED_IO; /*緩沖區方式讀寫(DO_BUFFERED_IO) :操作系統將應用程序提供緩沖區的數據復制到內核模式下的地址中。*優點:方便;缺點:效率低*適合數據量較小時使用**直接方式讀寫(DO_DIRECT_IO) :操作系統會將用戶模式下的緩沖區鎖住。*然后操作系統將這段緩沖區在內核模式地址再次映射一遍。*這樣,用戶模式的緩沖區和內核模式的緩沖區指向的是同一區域的物理內存。*優點:效率高;缺點:單獨占用物理頁面,無法再進行其它操作(例如文件讀寫)*適合數據量較大時使用**其他方式讀寫(默認為其他方式):*在使用其他方式讀寫設備時,派遣函數直接讀寫應用程序提供的緩沖區地址。*在驅動程序中,直接操作應用程序的緩沖區地址是很危險的。*只有驅動程序與應用程序運行在相同線程上下文的情況下,才能使用這種方式。*/創建符號鏈接
/**特別說明:*1. 設備名稱的作用是給內核對象用的,如果要在Ring3訪問,必須要有符號鏈接* 其實就是一個別名,沒有這個別名,在Ring3不可見。*2. 內核模式下,符號鏈接是以“\??\”開頭的,如C盤就是“\??\C:”*3. 而在用戶模式下,則是以“\\.\”開頭的,如C盤就是“\\.\C: *///Ring3用CreateFile打開設備時,用"\\\\.\\MyTestDriver" #define SYMBOLICLINK_NAME L"\\??\\MyTestDriver"//創建符號鏈接名稱 RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINK_NAME);//創建符號鏈接 status = IoCreateSymbolicLink(&SymbolicLinkName, &Devicename);if( STATUS_SUCCESS != status ) {DbgPrint("創建設備失敗! . \r\n");IoDeleteDevice(pDeviceObj);return status; }IRP與派遣函數
描述:
IRP的類型
描述:當應用層通過CreateFile,ReadFile,WriteFile,CloseHandle等函數對設備進行打開、讀取、寫入、關閉的時候,會使操作系統產生出IRP_MJ_CREATE,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_CLOSE等不同的IRP
其它類型的IRP
派遣函數
派遣函數注冊位置
ntdll!_DRIVER_OBJECT+0x034 DriverUnload : Ptr32 void //卸載函數+0x038 MajorFunction : [28] Ptr32 long //派遣函數注冊派遣函數
NTSTATUS DriverEntry( 。。。。) { //設置派遣函數 pDriverObject->MajorFunction[IRP_MJ_CREATE] // 派遣函數1; pDriverObject->MajorFunction[IRP_MJ_CLOSE] // 派遣函數2; pDriverObject->MajorFunction[IRP_MJ_WRITE] // 派遣函數3; pDriverObject->MajorFunction[IRP_MJ_READ] // 派遣函數4; pDriverObject->MajorFunction[IRP_MJ_CLEANUP] // 派遣函數5; pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] // 派遣函數6; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] // 派遣函數7; pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] // 派遣函數8; pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] // 派遣函數9;//IRP_MJ_MAXIMUM_FUNCTION 派遣函數的最大值//設置卸載函數 pDriverObject->DriverUnload = 卸載函數; }派遣函數的格式
NTSTATUS MyDispatchFunction(PDEVICE_OBJECT pDevObj, PIRP pIrp) {//處理自己的業務...//設置返回狀態pIrp->IoStatus.Status = STATUS_SUCCESS; //getlasterror()得到的就是這個值pIrp->IoStatus.Information = 0; //返回給3環多少數據 沒有填0IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS; }實驗
Ring 0代碼
#include <ntddk.h> #include <ntstatus.h>#define DEVICE_NAME L"\\Device\\MyDevice" // Ring3用CreateFile打開設備時,用"\\\\.\\MyTestDriver" #define SYMBOLICLINK_NAME L"\\??\\MyTestDriver"// 0-2047是保留的 2048~4095 #define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)// 卸載函數 VOID DriverUnload(PDRIVER_OBJECT pDriver) {UNICODE_STRING SymbolicLinkName = {0};DbgPrint("驅動程序停止運行了 . \r\n");// 刪除符號鏈接 刪除設備RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINK_NAME);IoDeleteSymbolicLink(&SymbolicLinkName);IoDeleteDevice(pDriver->DeviceObject); }// IRP_MJ_CREATE處理函數 NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {DbgPrint("DispatchCreate ... \n");// 返回狀態如果不設置 Ring3返回的是失敗pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS; }// IRP_MJ_CLOSE處理函數 NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {DbgPrint("DispatchClose ... \n");pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS; }// IRP_MJ_DEVICE_CONTROL處理函數 用來處理與Ring3交互 NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;PIO_STACK_LOCATION pIrpStack;ULONG uIoControlCode;PVOID pIoBuffer;ULONG uInLength;ULONG uOutLength;ULONG uRead;ULONG uWrite;// 設置臨時變量的值pIrpStack = IoGetCurrentIrpStackLocation(pIrp);// 獲取控制碼uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 獲取緩沖區地址(輸入和輸出的緩沖區都是一個)pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;// Ring3 發送數據的長度uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// Ring0 發送數據的長度uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;switch(uIoControlCode){case OPER1:{DbgPrint("IrpDeviceControlProc -> OPER1 ... \n");pIrp->IoStatus.Information = 0;status = STATUS_SUCCESS;break;}case OPER2:{DbgPrint("IrpDeviceControlProc -> OPER2 接收字節數:%d \n", uInLength);DbgPrint("IrpDeviceControlProc -> OPER2 輸出字節數:%d \n", uOutLength);// Read From Buffermemcpy(&uRead, pIoBuffer, 4);DbgPrint("IrpDeviceControlProc -> OPER2 ... %x \n", uRead);// Write To Buffermemcpy(&pIoBuffer, &uWrite, 4);// Set StatuspIrp->IoStatus.Information = 2;status = STATUS_SUCCESS;break;}}// 設置返回狀態pIrp->IoStatus.Status = status;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return status; }// 入口函數 相當于Main函數 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path) {NTSTATUS status = 0;ULONG uIndex = 0;PDEVICE_OBJECT pDeviceObj = NULL;UNICODE_STRING Devicename;UNICODE_STRING SymbolicLinkName;DbgPrint("驅動程序開始運行了 . \r\n");// 創建設備名稱RtlInitUnicodeString(&Devicename, DEVICE_NAME);// 創建設備status = IoCreateDevice(pDriver, 0, &Devicename,FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObj);if(status != STATUS_SUCCESS){DbgPrint("創建設備失敗! \r\n");return status;}//設置交互數據的方式pDeviceObj->Flags |= DO_BUFFERED_IO;// 創建符號鏈接名稱RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINK_NAME);// 創建符號鏈接status = IoCreateSymbolicLink(&SymbolicLinkName, &Devicename);if(status != STATUS_SUCCESS){DbgPrint("創建符號鏈接失敗! \r\n");IoDeleteDevice(pDeviceObj);return status;}// 設置分發函數和卸載函數pDriver->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;pDriver->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceControlProc;pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS; }Ring 3代碼
#include <stdio.h> #include <windows.h> #include <winioctl.h>#define IN_BUFFER_MAXLENGTH 0x10 //輸入緩存最大長度 #define OUT_BUFFER_MAXLENGTH 0x10 //輸出緩存最大長度 #define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS) #define SYMBOLICLINK_NAME "\\\\.\\MyTestDriver"HANDLE g_hDevice; //驅動句柄/***************************************************************************/ //打開驅動服務句柄 //打開三環鏈接名:\\\\.\\Driver /***************************************************************************/ BOOL Open(PCHAR pLinkName) {TCHAR szBuffer[10] = {0};//在3環獲取驅動程序g_hDevice = CreateFile(pLinkName, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);DWORD err = GetLastError();sprintf(szBuffer, "%d\n", err);if(g_hDevice != INVALID_HANDLE_VALUE)return TRUE;elsereturn FALSE; }/***************************************************************************/ //與驅動通信的函數 /***************************************************************************/ BOOL IoControl(DWORD dwIoCode, PVOID InBuff, DWORD InBuffLen, PVOID OutBuff, DWORD OutBuffLen) {DWORD dw;//驅動句柄/操作碼/輸入緩沖區地址/輸入緩沖區長度/輸出緩沖區地址/輸出緩沖區長度/返回長度/指向OVERLAPPED 此處為NULLDeviceIoControl(g_hDevice, dwIoCode, InBuff, InBuffLen, OutBuff, OutBuffLen, &dw, NULL);return TRUE; }int main() {DWORD dwInBuffer = 0x11223344;TCHAR szOutBuffer[OUT_BUFFER_MAXLENGTH] = {0};//1. 通過符號鏈接,打開設備Open(SYMBOLICLINK_NAME);//2. 測試通信IoControl(OPER2, &dwInBuffer, IN_BUFFER_MAXLENGTH, szOutBuffer, OUT_BUFFER_MAXLENGTH);printf("%s", szOutBuffer);//3. 關閉設備CloseHandle(g_hDevice);getchar();return 0; }第一步:運行Ring 0代碼
第二步:運行Ring3代碼
總結
以上是生活随笔為你收集整理的Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows驱动开发学习笔记(三)——
- 下一篇: Windows驱动开发学习笔记(五)——