天天看點

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

    • 基礎知識
    • 驅動調試
      • PDB(Program Debug Database)
      • WinDbg 加載 PDB
      • 實驗:調試 .sys 檔案
        • 第一步:編譯代碼
        • 第二步:将 .sys 檔案拷貝到虛拟機中
        • 第三步:添加 pdb 檔案路徑
        • 第四步:部署 .sys 檔案并運作
    • 核心程式設計基礎
      • 核心API的使用
      • 未導出函數的使用
      • 基本資料類型
      • 傳回值
      • 核心中的異常處理
      • 常用核心函數(記憶體操作)
      • 核心字元串種類
      • 核心字元串常用函數

基礎知識

  1. 驅動程式無法在目前系統中進行調試,否則會導緻系統卡死
  2. 可以采用雙機調試的方式調試驅動程式

驅動調試

當我們使用 windbg 檢視某一個位址的反彙編時,例如:

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

windbg 能夠自動幫我們識别出該位址屬于哪個函數(紅框部分)

思考:windbg 是如何識别出該位址對應的函數的?

PDB(Program Debug Database)

  1. PDB檔案是在我們編譯工程的時候産生的,它是和對應的子產品(exe或dll)一起生成出來的
  2. 每個子產品編譯的時候都可以生成自己的PDB檔案,比如

    .exe

    /

    .dll

    /

    .sys

    等等
  3. 0環調試器(例如 WinDbg)正是通過解析pdb檔案來找到函數與位址之間的對應關系

WinDbg 加載 PDB

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎
Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎
Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

實驗:調試 .sys 檔案

第一步:編譯代碼

#include "ntddk.h"

//解除安裝函數
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("驅動程式已停止.\r\n");
}

//驅動程式入口函數,相當于控制台的main函數
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{

	__asm
	{
		int 3
		mov eax, eax
		mov eax, eax
		mov eax, eax
	}

	DbgPrint("驅動程式已運作.\r\n");

	//設定一個解除安裝函數  便于退出
	DriverObject->DriverUnload = DriverUnload;

	return STATUS_SUCCESS;
}
           

第二步:将 .sys 檔案拷貝到虛拟機中

第三步:添加 pdb 檔案路徑

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎
Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

第四步:部署 .sys 檔案并運作

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

WinDbg 成功截獲中斷即可

Windows驅動開發學習筆記(二)—— 驅動調試&核心程式設計基礎

核心程式設計基礎

核心API的使用

  1. 在應用層程式設計時,可以使用WINDOWS提供的各種API函數,隻要導入頭檔案<windows.h>就可以了。但是在核心程式設計的時候,不能像在Ring3那樣直接使用
  2. 微軟為核心程式提供了專用的API,隻要在程式中包含相應的頭檔案就可以使用了,如:#include <ntddk.h> (前提是已經正确安裝了WDK)
  3. 在應用層程式設計的時候,我們通過MSDN來了解函數的詳細資訊,在核心程式設計的時候,要使用WDK自己的幫助文檔
    Windows驅動開發學習筆記(二)—— 驅動調試&amp;核心程式設計基礎

未導出函數的使用

描述:

  1. WDK說明文檔中隻包含了核心子產品導出的函數,對于未導出的函數,則不能直接使用。
  2. 如果要使用未導出的函數,隻要自己定義一個函數指針,為函數指針提供正确的函數位址就可以使用了

擷取未導出的函數位址:

  1. 特征碼搜尋
  2. 解析核心PDB檔案

基本資料類型

在核心程式設計的時候,強烈建議大家遵守WDK的編碼習慣,不要這樣寫:

unsigned long length;

WDK類型:

ULONG(unsigned long)		PULONG(unsigned long *)
UCHAR(unsigned char)		PUCHAR(unsigned char *)
UINT(unsigned int)			PUNIT(unsigned int *)	
VOID(void)					PVOID(void *)
           

傳回值

大部分核心函數的傳回值都是NTSTATUS類型,如:

NTSTATUS PsCreateSystemThread();    
NTSTATUS ZwOpenProcess();
NTSTATUS ZwOpenEvent();
           

這個值能說明函數執行的結果,如:

STATUS_SUCCESS				0x00000000	成功		
STATUS_INVALID_PARAMETER	0xC000000D	參數無效	
STATUS_BUFFER_OVERFLOW		0x80000005	緩沖區長度不夠	
           

當調用的核心函數時,如果傳回的結果不是STATUS_SUCCESS,就說明函數執行中遇到了問題,具體是什麼問題,可以在ntstatus.h檔案中檢視

核心中的異常處理

描述:

  1. 在核心中,一個小小的錯誤就可能導緻藍屏,比如:讀寫一個無效的記憶體位址
  2. 為了讓自己的核心程式更加健壯,強烈建議大家在編寫核心程式時,使用異常處理

Windows提供了結構化異常處理機制,一般的編譯器都是支援的,如下:

__try{
	//可能出錯的代碼
}
__except(filter_value) {
	//出錯時要執行的代碼
}
           

filter_value:

EXCEPTION_EXECUTE_HANDLER(1)		//代碼進入except塊
EXCEPTION_CONTINUE_SEARCH(0)		//不處理異常,由上一層調用函數處理
EXCEPTION_CONTINUE_EXECUTION(-1)	//回去繼續執行錯誤處的代碼
           

常用核心函數(記憶體操作)

Windows驅動開發學習筆記(二)—— 驅動調試&amp;核心程式設計基礎

核心字元串種類

ANSI_STRING字元串:

typedef struct _STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PCHAR Buffer;
}STRING;
           

UNICODE_STRING字元串:

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaxmumLength;
    PWSTR Buffer;
} UNICODE_STRING;
           

核心字元串常用函數

Windows驅動開發學習筆記(二)—— 驅動調試&amp;核心程式設計基礎

繼續閱讀