日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)

發布時間:2025/3/21 windows 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Windows驅動開發學習筆記(四)—— 3環與0環通信(常規方式)

    • 設備對象
      • 創建設備對象
      • 設置數據交互方式
      • 創建符號鏈接
    • IRP與派遣函數
      • IRP的類型
      • 其它類型的IRP
    • 派遣函數
      • 派遣函數注冊位置
      • 注冊派遣函數
      • 派遣函數的格式
    • 實驗
      • Ring 0代碼
      • Ring 3代碼
      • 第一步:運行Ring 0代碼
      • 第二步:運行Ring3代碼

設備對象

描述

  • 我們在開發窗口程序的時候,消息被封裝成一個結構體:MSG
  • 內核開發時,消息被封裝成另外一個結構體:IRP(I/O Request Package)
  • 窗口程序中,能夠接收消息的只能是窗口對象
  • 內核中,能夠接收IRP消息的只能是設備對象
  • 創建設備對象

    //創建設備名稱 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與派遣函數

    描述

  • 當對窗口對象傳遞消息時,窗口對象會根據我們所傳入的消息類型執行對應的回調函數
  • 當調用CreateFile等函數時,操作系統會將它們封裝成一個結構體,此時就可以傳遞給設備對象,設備對象根據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环通信(常规方式)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。