天天看點

驅動篇——正常的0環與3環通信

驅動篇之正常的0環與3環通信,詳細介紹正常的0環與3環通信。

  此系列是本人一個字一個字碼出來的,包括示例和實驗截圖。由于系統核心的複雜性,故可能有錯誤或者不全面的地方,如有錯誤,歡迎批評指正,本教程将會長期更新。 如有好的建議,歡迎回報。碼字不易,如果本篇文章有幫助你的,如有閑錢,可以打賞支援我的創作。如想轉載,請把我的轉載資訊附在文章後面,并聲明我的個人資訊和本人部落格位址即可,但必須事先通知我。

你如果是從中間插過來看的,請仔細閱讀 羽夏看Win系統核心——簡述 ,友善學習本教程。

  看此教程之前,問個問題,你明确學驅動的目的了嗎?你的開發環境準備好了嗎?上一節的内容學會了嗎? 沒有的話就不要繼續了,請重新學習前面驅動篇的教程内容繼續。

🔒 華麗的分割線 🔒

本次答案均為參考,可以與我的答案不一緻,但必須成功通過。

1️⃣ 周遊核心子產品,輸出子產品名稱,基址以及大小。

🔒 點選檢視答案 🔒

  此題目不難,就是一個循環雙向連結清單的周遊,代碼見下面的折疊,效果如下:

驅動篇——正常的0環與3環通信

🔒 點選檢視代碼 🔒

2️⃣ 編寫一個函數,找到一個未導出的函數,并調用。(例子:找到<code>PspTerminateProcess</code>,通過調用這個函數結束記事本程序)

  根據<code>PE</code>的知識,我們可以通過基址+偏移的方式定位該函數,這個是最簡潔的方式。當然可以通過特征碼的方式,不過效率低,特征碼找不好還不準确。

  我們先在<code>WinDbg</code>找找這個函數在哪裡:

  這個函數是在核心檔案導出,分頁不同,導出的函數偏移可能不同,下面是在<code>2-9-9-12</code>分頁模式下做的實驗,如果在<code>10-10-12</code>分頁可能函數的位置不同:

  我們隻需要擷取函數偏移,擷取基位址,加起來即是函數位址,然後調用即可,代碼見折疊,必要位置具有注釋。

  好了,我們嘗試一下能不能終止程序,先在<code>WinDbg</code>找到<code>EPROCESS</code>結構體的位址:

  <code>89cb7918</code>就是我們需要的位址,修改調用<code>PspTerminateProcess</code>的第一個參數的數值,然後編譯。在虛拟機進行注冊啟動驅動效果如下:

驅動篇——正常的0環與3環通信

  由于這個函數很底層,可以幹掉很多流氓軟體,甚至殺軟都不放過。比如火絨(已将該情況上報給火絨官方,亂搞後果自負):

驅動篇——正常的0環與3環通信

3️⃣ 通過斷鍊實作隐藏驅動子產品。

  此題目不難,就是一個連結清單斷鍊,效果如下:

驅動篇——正常的0環與3環通信

  <code>PCHunter</code>這個<code>ARK</code>工具仍能發現我們的子產品,指明為隐藏驅動。但是你用普通的<code>API</code>試試,你絕對發現不了它。

  我們在開發視窗程式的時候,消息被封裝成一個結構體:<code>MSG</code>。在核心開發時,消息被封裝成另外一個結構體:<code>IRP</code>,英文全稱:<code>I/O Request Package</code>。在視窗程式中,能夠接收消息的隻能是視窗對象。在核心中,能夠接收<code>IRP</code>消息的隻能是裝置對象。示意圖如下所示:

驅動篇——正常的0環與3環通信

  為了實作3環程式與驅動程式正常的通信功能,微軟提供了一系列的<code>API</code>。我們可以通過它來實作正常的通信。我們的硬碟、鍵盤、顯示卡想要工作,在<code>Windows</code>平台都需要用此實作通信,來實作想要的功能。下面我來介紹具體流程。

  如果<code>MSG</code>需要傳遞,就必須建立一個窗體,因為隻有窗體才有消息隊列這個東西,才嗯那個接收消息。如果想要驅動實作通信,就必須有一個裝置對象。我們可以用下面的代碼實作建立裝置:

  既然裝置對象建立好了,我們需要規定一個“協定”,就是3環程式與驅動互動的協定。具體有如下幾個方式:

  緩沖區方式讀寫(<code>DO_BUFFERED_IO</code>) :作業系統将應用程式提供緩沖區的資料複制到核心模式下的位址中。

  直接方式讀寫<code>(DO_DIRECT_IO</code>) :作業系統會将使用者模式下的緩沖區鎖住。然後作業系統将這段緩沖區在核心模式位址再次映射一遍。這樣,使用者模式的緩沖區和核心模式的緩沖區指向的是同一區域的實體記憶體。缺點就是要單獨占用實體頁面。

  其他方式讀寫(在調用<code>IoCreateDevice</code>建立裝置後對<code>pDevObj-&gt;Flags</code>即不設定<code>DO_BUFFERED_IO</code>也不設定<code>DO_DIRECT_IO</code>此時就是其他方式。在使用其他方式讀寫裝置時,派遣函數直接讀寫應用程式提供的緩沖區位址。在驅動程式中,直接操作應用程式的緩沖區位址是很危險的。隻有驅動程式與應用程式運作在相同線程上下文的情況下,才能使用這種方式。如果<code>CPU</code>中的任務切換了,即<code>CR3</code>切換掉了,在高<code>2GB</code>的驅動仍在使用該方式讀取低<code>2GB</code>記憶體,導緻讀到的資料和實際不符,導緻錯誤,故強烈不推薦此方式。

  用代碼設定互動資料的方式舉例如下:

  裝置對象建立好了,通信方式也約定好了,但3環的程式仍找不到你的驅動對象。裝置名稱的作用是給核心對象用的,如果要在3環通路,必須要有符号連結。其實就是一個别名,沒有這個别名,在3環不可見。用代碼實作如下:

  有些細節需要特别注意:核心模式下,符号連結是以<code>\??\</code>開頭的,如C槽就是<code>\??\C:</code>。而在使用者模式下,則是以<code>\\.\</code>開頭的,如C槽就是<code>\\.\C:</code>。

  前面的代碼都寫好的,驅動與3環的通信的基礎就搭建好了。但是,如果真正實作通信,還得需要注冊派遣函數。

驅動篇——正常的0環與3環通信

  如上圖所示,我們在編寫<code>Win32</code>窗體程式時。假設我在窗體點選了滑鼠,作業系統就會産生一個消息,用<code>MSG</code>這個結構體封裝一下,派發給窗體對象。目标窗體對象接受到後發現它是滑鼠單擊消息。窗體對象中注冊了很多回調函數:滑鼠點選回調、滑鼠輕按兩下回調、鍵盤鍵按下回調等等。然後進一步處理是單擊,就調用單擊回調函數。同理,我們在3環調用<code>CreateFile</code>函數,作業系統就會産生一個<code>IRP</code>派發給裝置對象,目标裝置對象處理方式和窗體消息沒啥差别。接下來我們看看<code>IRP</code>的類型:

  當應用層通過<code>CreateFile</code>、<code>ReadFile</code>、<code>WriteFile</code>、<code>CloseHandle</code>等函數打開、從裝置讀取資料、向裝置寫入資料、關閉裝置的時候,會使作業系統分别産生出<code>IRP_MJ_CREATE</code>、<code>IRP_MJ_READ</code>、<code>IRP_MJ_WRITE</code>、<code>IRP_MJ_CLOSE</code>等不同的<code>IRP</code>。值得注意的是,我們之前使用<code>CreateFile</code>這個東西隻是為了建立檔案,其實它的本質是與裝置對象建立通路,我們3環程式想要通過符号連結與驅動建立通訊,就必須通過這個函數。

  當然<code>IRP</code>不止上面的這幾種,我們再給出常見的<code>IRP</code>:

IRP類型

來源

IRP_MJ_DEVICE_CONTROL

使用 DeviceControl 函數時産生

IRP_MJ_POWER

在作業系統處理電源消息時産生

IRP_MJ_SHUTDOWN

關閉系統前時産生

  我們最常用的<code>IRP</code>有<code>IRP_MJ_DEVICE_CONTROL</code>、<code>IRP_MJ_CREATE</code>和<code>IRP_MJ_CLOSE</code>,以實作互動、建立通路、關閉通路的功能。

  了解了上面的東西,我們如何注冊派遣函數呢?我們再看一下<code>DRIVER_OBJECT</code>這個東西:

  有沒有注意到<code>MajorFunction</code>這個成員,它是一個數組,具有28個,我們的派遣函數都會在這裡面,如何注冊我們用如下代碼形式:

  回調函數都有自己的格式,派遣函數也不例外,它的格式如下:

本節的答案将會在下一節進行講解,務必把本節練習做完後看下一個講解内容。不要偷懶,實驗是學習本教程的捷徑。

  俗話說得好,光說不練假把式,如下是本節相關的練習。如果練習沒做好,就不要看下一節教程了,越到後面,不做練習的話容易夾生了,開始還明白,後來就真的一點都不明白了。本節練習不多,請保質保量的完成。

1️⃣ 實作一個工具,利用未導出的函數<code>PspTerminateProcess</code>殺死軟體(驅動的加載可不用代碼實作,使用本教程工具進行加載)。

  驅動篇——總結與提升

驅動篇——正常的0環與3環通信
驅動篇——正常的0環與3環通信

本作品采用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協定 進行許可

本文來自部落格園,作者:寂靜的羽夏 ,一個熱愛計算機技術的菜鳥

轉載請注明原文連結:https://www.cnblogs.com/wingsummer/p/15516178.html

驅動篇——正常的0環與3環通信