內核第三講,進入ring0,以及編寫第一個內核驅動程序.
PS: 請下配置雙機調試,下方有可能用到.如果不配置,則你可以不用調試, 博客連接: http://www.cnblogs.com/iBinary/p/8260969.html
一丶進入ring0之前的簡介
進入0環之前,我們要明白操作系統的設計,操作系統允許驅動程序使用In out等等特權指令來操作高2G的內存.那么必然會有接口.
圖示如下.
那么我們可以模擬一個驅動程序來進入0環.
而操作系統提供的接口的,有專門的名稱. 叫做DDK, 現在改名為WDK了.
DDK: Driver Development Kit 驅動程序開發包,例如我們寫的3環系統下,用到的SDK,也可以成為是API.只不過現在叫做內核方法(內核函數)了.
WDK:Windows Driver Kit
WDK是DDK升級而來的.操作系統為了支持熱插拔,所以對DDK升級了.熱插拔就是U盤插入系統.不用安裝驅動了.和U盤綁定在一起了.
WDK官方下載連接: https://developer.microsoft.com/zh-cn/windows/hardware/windows-driver-kit
我自己用的是WDK7.1.7600,會上傳到課堂資料中.有興趣的可以下載.
注意: 如果編寫驅動程序,請下載對應系統的WDK,因為驅動程序不兼容.只會跟着系統走.
二丶WDK的安裝.
下載之后直接下一步,下一步即可. 如果不會建議百度.
三丶進入0環,編寫第一個內核驅動程序
在進入ring0之前,我們要知道,不管是驅動程序,或者是應用程序,都會有一個入口點.
比如控制台的入口點是 main,窗口的是winmain.那么看下驅動程序的入口點是什么.
PS:安裝好WDK之后,會有幫助文檔.可以參考幫助文檔.
如果我們要編寫內核驅動,則要看內核驅動的入口點,也就是kerner mode,內核模型.
如果是編寫硬件驅動,則尋找WDM即可.
NTSTATUS DriverEntry( //驅動的入口點 __in struct _DRIVER_OBJECT *DriverObject, __in PUNICODE_STRING RegistryPath ) {...}
返回值: STATUS_SUCCESS
內核輸出的API
ULONG
DbgPrint(
IN PCHAR Format,
. . . . [arguments]
);
利用入口我們可以簡單編寫一個內核驅動了.
驅動我們可以用C語言去寫.也可以是C++
#include <Ntddk.h> //編寫內核驅動需要包含NTddk頭文件. NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT *DriverObject, __in PUNICODE_STRING RegistryPath) { int i = 0; DbgPrint("HelloWorld, %p\r\n",&i); return STATUS_SUCCESS; }
在編譯驅動程序的是否,我們需要一個sources 文件
格式:
TARGETNAME= MyFirstDrive //指明編譯的文件名 TARGETTYPE=DRIVER //指明編譯的類型 SOURCES= MyFirstDrive.c //指明編譯的文件
圖示:
編譯的時候找我們的開發包.
通過開始程序,找到我們的開發包中的編譯XP命令框.點開.
輸入編譯命令 build 文件名
回車就可以編譯我們的驅動程序了.
成功會生成一個sys后綴的文件.那么我們就可使用了.
四丶雙機調試,加載我們的驅動.
我們以調試系統啟動.然后使用加載驅動的工具,加載我們的驅動,那么就可以在調試器中看到我們的驅動代碼了.
當我們啟動之后,我們可以查看下調試器,可以調試我們的代碼.
請注意我們打印的地址,地址是高2G的空間.所以我們就進入了0環空間了.
五丶編寫驅動卸載功能.
我們的驅動現在可以加載.啟動.停止.但是不能卸載.原因就是我們沒有寫卸載的函數.
比如我們的DLL, DLL來的是否還分為4中情況.
很簡單.只需要把我們的驅動代碼改變一下即可.
#include <Ntddk.h> //編寫內核驅動需要包含NTddk頭文件. //卸載回調函數 VOID Unload(__in struct _DRIVER_OBJECT *DriverObject) { DbgPrint("Unload MyDrive\n"); } NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT *DriverObject, __in PUNICODE_STRING RegistryPath) { int i = 0; DbgPrint("HelloWorld, %p\r\n",&i); //注冊一下驅動卸載的函數 DriverObject->DriverUnload = Unload; return STATUS_SUCCESS; }
給個卸載的函數指針即可.注意啟動入口點的參數是一個結構體.啟動你想要支持卸載驅動.那么就寫上卸載驅動的函數指針即可.
六丶藍屏的出現.
編寫驅動代碼,不像我們編寫ring3下的應用程序,崩潰了就是崩潰了. 我們寫驅動程序恨不得寫一行,檢查500行.
看下藍屏的實現.只要我們的程序異常,那么就會藍屏.
代碼:
#include <Ntddk.h> //編寫內核驅動需要包含NTddk頭文件. //卸載回調函數 VOID Unload(__in struct _DRIVER_OBJECT *DriverObject) { DbgPrint("Unload MyDrive\n"); } NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT *DriverObject, __in PUNICODE_STRING RegistryPath) { int i = 0; int *p = NULL; //異常代碼.會造成C05訪問異常. DbgPrint("HelloWorld, %p\r\n",&i); *p = 1; //代碼會產生異常,系統會藍屏. //注冊一下驅動卸載的函數 DriverObject->DriverUnload = Unload; return STATUS_SUCCESS; }
很簡單,就加了一行C05訪問異常的代碼.
重新編譯一下.並且驅動加載.
因為家里電腦系統原因,藍屏了會緊接着重啟.所以來不及截圖.請大家自己嘗試.
課堂代碼資料:
內核工具下載: 鏈接:https://pan.baidu.com/s/1o9PjpUU 密碼:k5sp
課堂驅動代碼資料下載: 鏈接:https://pan.baidu.com/s/1kXiSluv 密碼:jnov
轉載請著名出處,謝謝.