Windows中0環與3環通訊(常規方式)

  • 2019 年 10 月 15 日
  • 筆記

Windows內核分析索引目錄:https://www.cnblogs.com/onetrainee/p/11675224.html

一、知識點講解

1. 設備對象

  我們在開發窗口程式的時候,消息被封裝成一個結構體:MSG,在內核開發時,消息被封裝成另外一個結構體:IRP(I/O Request Package I/O請求包)。

 

  在窗口程式中,能夠接收消息的只能是窗口對象(由窗口對象將消息分發給各個窗口過程)。

  在內核中,能夠接收IRP消息的只能時設備對象。

    

 

2. 創建設備對象

  調用 IoCreateDevice API 來創建設備對象,其中需要傳入設備名稱(R3依據這個找到),需要初始化字元串。

 1 //創建設備名稱   2 UNICODE_STRING Devicename;   3 RtlInitUnicodeString(&Devicename,L"\Device\MyDevice");   4   5 //創建設備   6 IoCreateDevice(   7 pDriver,                //當前設備所屬的驅動對象   8 0,   9 &Devicename,            //設備對象的名稱  10 FILE_DEVICE_UNKNOWN,  11 FILE_DEVICE_SECURE_OPEN,  12 FALSE,  13 &pDeviceObj            //設備對象指針  14 );

 

3. 設置數據交互方式

  pDeviceObj->Flags |= DO_BUFFERED_IO (注意: I= 表示按位或的含義)

  其存在三種讀寫方式:

  1)緩衝區讀寫方式(DO_BUFFERED_IO):作業系統將應用程式提供緩衝區的數據複製到內核模式下的地址中。

  2)  直接方式讀寫(DO_DIRECT_IO):作業系統會將用戶模式下的緩衝區鎖住。然後作業系統將這段緩衝區在內核模式地址再次映射一遍。這樣,用戶模式的緩衝區和內核模式的緩衝區指向的時同一區域的物理記憶體。缺點就是要單獨佔用物理頁面。

  3)其他方式讀寫(不設置Flags):很危險,直接讀寫緩衝區地址,很容易出現藍屏並且很可能數據丟失(讀取過程中掛起頁置換)。

 

4. 創建符號鏈接

  //創建符號鏈接名稱

  RtlInitUnicodeString(&SymbolicLinkName,L”\??\MyTestDriver”);

  // 創建符號鏈接

  IoCreateSymbolicLink(&SymbolicLinkName,&Devicename);

 

  特別說明:

  1)設備名稱的作用就是給內核對象用的,如果要在R3訪問,必須要有符號鏈接。其實就是一個別名,沒有這個別名,在R3不可見

  2)在內核模式下,符號鏈接是以 ‘??’開頭的,如果C盤就是 “??C:”

  3)  在用戶模式下,則是以 ‘\.’ 開頭的,如果是C盤就是 “\.C:”

 

5. IRP與派遣函數

  如下圖,在R3層面上,其由窗口對象負責將消息發送給對應的回調函數;而在內核層,將IRP發送給設備對象,由設備對象轉發給對應的派遣函數。

  

6、IRP的類型

  微軟文檔 :IRP structure

  1)  當應用層通過CreateFile,ReadFile,WriteFile,CloseHandle等函數打開、從設備讀取數據、向設備寫入數據、關閉設備的時候,會時作業系統產生出IRP_MJ_CREATE、IRP_MJ_READ、IRP_MJ_CLOSE等不同的IRP。

  2)其他的IRP類型

    IRP_MJ_DEVICE_CONTROL    DeviceControl函數會產生此IRP

    IRP_MJ_POWER        在作業系統處理電源消息時,產生次IRP

    IRP_MJ_SHUTDOWN      關閉系統前會產生此IRP

 

7、派遣函數在哪裡註冊呢?

  其在 _DRIVER_OBJECT 函數最後一個數組中。其派遣函數的種類及其有限(由IRP消息類型限制),可以看出一共有29種。

  關於 _DRIVER_OBJECT的介紹可以查看之前這篇部落格:內核空間與內核地址

  

 

8. 註冊派遣函數

  如下圖,我們直接採取對數組賦值的形式來設置派遣函數。

  

 9. 派遣函數格式

  一定要設置其返回狀態 NTSTATUS,三環程式判斷API是否調用成功就是根據這個狀態,如果不設置,則可能會出錯。