內核知識第六講,內核編寫規范,以及獲取GDT表
一丶內核驅動編寫規范
我們都知道,在ring3下,如果我們的程序出錯了.那么就崩潰了.但是在ring0下,只要我們的程序崩潰了.那么直接就藍屏了.
那么有那些規范?
1.最基本的檢查要有. 比如檢查指針是否為NULL,基本的校驗錯誤必須有
2.對內存進行操作的時候,要進行內存判斷.下面提供內存判斷的API
BOOLEAN
MmIsAddressValid(
IN PVOID VirtualAddress
);
給定一個緩沖區,然后檢查其內存是否有效
VOID ProbeForWrite( IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment );
給定一個緩沖區.然后檢查是否可以寫. 但是注意,檢測的是ring3下的內存地址.
3.盡量不要使用太大變量,因為在內核中.內存地址都是共享的.如果你使用了很大.那么相應的內核空間就會變少.
比如不能這樣寫 char szBuf[0x1000];這樣是使用棧內存了.但是編譯是不通過了.操作系統不讓你這樣使用.
但是你可以寫成 char szBuf1[0x500], char szBuf2[0x500]; 但是沒有任何意義.
4.ring0下不能直接訪問ring3的內存
這個是有原因的.因為ring0知道一塊物理內存.但是不知道是那個進程的.所以不能直接訪問.
二丶分頁內存與非分頁內存管理
我們在內核下申請空間的API:
PVOID
ExAllocatePool(
IN POOL_TYPE PoolType, //指定內存的類型
IN SIZE_T NumberOfBytes //申請的字節數
);
但是第一個參數是我們制定內存的內容是一個結構體
typedef enum _POOL_TYPE { NonPagedPool, //非分頁管理 PagedPool, //分頁管理 NonPagedPoolMustSucceed, DontUseThisType, NonPagedPoolCacheAligned, PagedPoolCacheAligned, NonPagedPoolCacheAlignedMustS } POOL_TYPE;
然后類型中有個非分頁管理以及分頁管理,什么意思?
意思就是在內核中申請一塊內存,這塊內存可否與磁盤交互.
非分頁內存: 不可以進行交互.申請了這塊內存就不能動了.
分頁內存: 可以進行交互.當內存資源緊張的是否,而這塊內存很少是否.可以暫時放到磁盤.
操作系統的代碼都是放到非分頁內存中的.
三丶設置分頁內存
了解了分頁內存和非分頁內存.那么此時就產生了一個新的問題.
我們的代碼.有的只調用一次,不該占着這個空間不放.那么我們就要設置為分頁內存中.
關鍵字:
總共兩種方式:
1.#pragma code_seg("PAGE") //每個函數都加上,設置到PAGE節中
例如:
但是這種方式,很麻煩,且每寫一個函數都要設置.那么此時就有第二種方式
2.#pragma Alloc_text("PAGE",函數名,.....) //類似於一個數組一樣,可以設置多個.
但是此時就要注意了.我們就需要一個頭文件了.把我們的函數聲明都放到頭文件中.
然后下方設置.
Page節,和INIT節. 內核中,我們編寫的sys驅動程序,其實也是一個PE文件. 類似於我們的ring3下的DLL, ring3的DLL是給應用程序使用的.而sys則是給操作系統使用的. 只不過一個是3環一個是0環
Page節: 這個節則是我們說的分頁內存節. 我們給了函數指針.那么就代表這塊內存很自由了.操作系統可以在資源緊張的時候使用.
INIT節: 這個節則是初始化的節.例如我們的入口函數,只用一次初始化而已,不用占着內存.所以給INIT節中.那么操作系統會初始化之后釋放這塊內存.這樣可以留給其它驅動使用.
四丶設置內核代碼運行的CPU在那個核心上跑.並獲取出來每個核心的GDT表.
代碼:
int shift = 1; char szGDT[6]; nCount = KeQueryActiveProcessors();//獲取CUP核心個數,按位來算. while(shift != 0x80000000) { if (nCount & shift) { KeSetSystemAffinityThread(nCount & shift);//設置在那個線程跑 __asm { sgdt szGDT } KdPrint(("limit:%p GDT:%p\n", *(short*)szGDT, *(int*)(szGDT + 2))); } shift <<= 1; }