(34)内核编程基础
一、未文檔化函數、未導出函數
未文檔化就是WDK文檔里搜不到,但是在導出表里的函數,要使用這種函數可以使用GetProcAddress函數獲取函數地址;
未導出函數就是不在導出表的函數,可以通過特征碼搜索或者解析內核PDB的方式找到函數地址,通過函數指針調用。
二、WDK數據類型
WDK數據類型在ntdef.h中定義,下面列舉部分,注意,并沒有UINT
typedef unsigned char UCHAR; typedef unsigned short USHORT; typedef unsigned long ULONG;三、NTSTATUS 返回值
很多內核函數的返回值都是 NTSTATUS,這是一個4字節整型。
例如:
四、內核異常處理
在內核中,一個小小的錯誤就可能導致藍屏,比如:讀寫一個無效的內存地址。為了讓自己的內核程序更加健壯,強烈建議大家在編寫內核程序時,使用異常處。
Windows提供了結構化異常處理機制,一般的編譯器都是支持的,如下:
出現異常時,可根據filter_value的值來決定程序該如果執行,當filter_value的值為:
EXCEPTION_EXECUTE_HANDLER(1),代碼進入except塊
EXCEPTION_CONTINUE_SEARCH(0),不處理異常,由上一層調用函數處理
EXCEPTION_CONTINUE_EXECUTION(-1),回去繼續執行錯誤處的代碼
用一段代碼演示:
__try {PULONG ptr = NULL;*ptr = 0x1234; } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("非法訪問內存.\r\n"); }五、常用的內核內存函數
| malloc | ExAllocatePool |
| memset | RtlFillMemory |
| memcpy | RtlMoveMemory |
| free | ExFreePool |
六、內核字符串及常用字符串函數
為了提高安全性,內核中的字符串不再是字符串首地址指針作為開始,0作為結尾,而是采用了以下兩個結構體:
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;下面的表格列出了常用的字符串函數:
| 創建 | RtlInitAnsiString | RtlInitUnicodeString |
| 復制 | RtlCopyString | RtlCopyUnicodeString |
| 比較 | RtlCompareString | RtlCompareUnicoodeString |
| 轉換 | RtlAnsiStringToUnicodeString | RtlUnicodeStringToAnsiString |
七、課后練習
1、申請一塊內存,并在內存中存儲GDT、IDT的所有數據。然后在debugview中顯示出來,最后釋放內存。
#include <ntddk.h> #include <ntdef.h>// 卸載函數 VOID DriverUnload(PDRIVER_OBJECT driver) {DbgPrint("驅動程序停止運行了.\r\n"); }// 入口函數,相當于main NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) { UCHAR GDT[6];UCHAR IDT[6];ULONG GdtAddr,GdtLen,IdtAddr,IdtLen;PUCHAR pBuffer = NULL;ULONG i;// 設置一個卸載函數,便于退出driver->DriverUnload = DriverUnload;// 讀取GDT, IDT__asm{sgdt fword ptr GDTsidt fword ptr IDT}GdtAddr = *(PULONG)(GDT+2);GdtLen = *(PUSHORT)GDT;IdtAddr = *(PULONG)(IDT+2);IdtLen = *(PUSHORT)IDT;// DbgPrint("GDT: %08X size: %04X\r\n", GdtAddr, GdtLen);// DbgPrint("IDT: %08X size: %04X\r\n", IdtAddr, IdtLen);// 申請內存pBuffer = (PUCHAR)ExAllocatePool(PagedPool, GdtLen + IdtLen);// 檢查申請是否成功if (NULL == pBuffer){DbgPrint("申請內存失敗.\r\n");return STATUS_UNSUCCESSFUL;}// 拷貝GDT, IDT數據RtlMoveMemory(pBuffer, (PUCHAR)GdtAddr, GdtLen);RtlMoveMemory(pBuffer + GdtLen, (PUCHAR)IdtAddr, IdtLen);// 打印數據DbgPrint("打印GDT\r\n");for (i = 0; i < GdtLen; i += 16){DbgPrint("%08X %08X %08X %08X %08X\r\n", GdtAddr + i, ((PULONG)(GdtAddr + i))[0],((PULONG)(GdtAddr + i))[1],((PULONG)(GdtAddr + i))[2],((PULONG)(GdtAddr + i))[3]);}DbgPrint("打印IDT\r\n");for (i = 0; i < IdtLen; i += 16){DbgPrint("%08X %08X %08X %08X %08X\r\n", IdtAddr + i, ((PULONG)(IdtAddr + i))[0],((PULONG)(IdtAddr + i))[1],((PULONG)(IdtAddr + i))[2],((PULONG)(IdtAddr + i))[3]);}// 釋放內存ExFreePool(pBuffer); return STATUS_SUCCESS; }2、編寫代碼,實現如下功能:
<1> 初始化一個字符串
<2> 拷貝一個字符串
<3> 比較兩個字符串是否相等
<4> ANSI_STRING與UNICODE_STRING字符串相互轉換
不知為何,Unicode字符串中如果有中文,dbgview和windbg打印出來是空白。
#include <ntddk.h> #include <ntdef.h>// 卸載函數 VOID DriverUnload(PDRIVER_OBJECT driver) {DbgPrint("驅動程序停止運行了.\r\n"); }// 入口函數,相當于main NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) { // 創建字符串ANSI_STRING AnsiSrc;ANSI_STRING AnsiDst;UNICODE_STRING UnicodeString;// 初始化字符串 RtlInitAnsiString(&AnsiSrc,"my first ANSI_STRING");RtlInitUnicodeString(&UnicodeString,L"my first UNICODE_STRING");// 打印字符串DbgPrint("%s Length: %d MaximumLength: %d\r\n", AnsiSrc.Buffer, AnsiSrc.Length, AnsiSrc.MaximumLength);DbgPrint("%ws Length: %d MaximumLength: %d\r\n", UnicodeString.Buffer, UnicodeString.Length, UnicodeString.MaximumLength);// 拷貝字符串RtlCopyString(&AnsiDst, &AnsiSrc);// 比較字符串if (RtlCompareString(&AnsiSrc, &AnsiDst, TRUE) == 0){DbgPrint("字符串相等.\r\n");}else{DbgPrint("字符串不相等.\r\n");}// Unicode轉AnsiDbgPrint("Unicode轉Ansi\r\n");RtlUnicodeStringToAnsiString(&AnsiDst,&UnicodeString,TRUE); DbgPrint("%s Length: %d MaximumLength: %d\r\n", AnsiDst.Buffer, AnsiDst.Length, AnsiDst.MaximumLength);// 設置一個卸載函數,便于退出driver->DriverUnload = DriverUnload;return STATUS_SUCCESS; }總結
以上是生活随笔為你收集整理的(34)内核编程基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (33)调试驱动程序
- 下一篇: (35)3环PEB断链