Windows內核分析索引目錄:https://www.cnblogs.com/onetrainee/p/11675224.html
GDT表與段描述符
一、介紹
如果之前學習過“實模式”,那很明白“段”的意義,在實模式中采用“段+偏移”的機制尋址。
現在,我們使用“保護模式”,內存對於我們來說是平坦的。此時,"段"對於我們來說,還有什么意義呢?
這時,"段"相當於一個管理者的角色,它有自己的Base,但往往從0開始計算,這時,更多的充當自己的權限功能。
“每個段”可以存儲在寄存器中,比如你訪問局部變量,其內存地址為 [a],其實際訪問是 sp:[a],雖然不同的段Base都為0開始,但權限是不同的,零環的段是不允許被三環的權限訪問的。
二、段選擇子 與 GDT表
我們在實際使用過程中直觀的看到段?答案是通過段寄存器(FS···)。
段寄存器中存儲的是什么呢(顯然不是段描述符)?實際上存儲的是 段選擇子。
段選擇子指明了該指明:讀取段申請的權限、查哪一張表、在表中的索引位置。(注意,不要誤解段選擇子只表明位置)
1. 拆分段選擇子:
我們查看寄存器時會發現各種段寄存器的值,我們使用如下方式進行拆分:如果想獲取段選擇子,直接右移3位,selector >> 3。
2. 搜索 gdt 表:
GDT表全程 Global Descriptor Table,段描述符表。
其存儲在 gdtr 寄存器中,我們在Windbg中使用 "r gdtr" 即可獲取該地址。
然后我們采用 dq address (一個段選擇子四字,八字節) 來顯示 gdt 表,如果知道索引想直接查看其地址,可以使用 dq address + (index * 8) 的公式來進行搜索。
三、段描述符的拆分
這個我們只挑幾個重點講,后續會補充其細節和有關實驗。
1. 段限長的換算公式
我們注意到,其段限長為 [0,15]、[24,31],但是如何仔細一看,其明顯是24位,少了8位。
這時,我們用到G位(23),顆粒度。
如果 G == 1 , 其顆粒度為 一頁,以4KB為單位,4KB。 4KB = 2 ^ 12 = 0x1000,但是,其是從零開始計數的,則應該后補 0xFFF。
如果 G == 0,則直接為原來的數值就好。
2. P位、S位與TYPE位
P位:0 - 無效段 、 1 - 有效段。(查看該段是否有效,最直接的就是查看該位)
S位:0 - 系統段、1 - 代碼段或數據段。
TYPE位:如果S位==1,則TYPE位進一步詳解其代碼段或數據段的有關屬性(可讀可寫可執行等等)。
如下圖,一個直觀判斷到底是代碼段還是數據段的方法:TYPE <= 7 數據段 ; TYPE >= 8 代碼段。
3. D/B位
該位對於數據段和代碼段有着不同的含義,但大體都是與位數大小有關。比如,如果我們使用32位操作系統,一次操作32位,又如何切換到對16位的操作,根本上就是使用這個位。
1)代碼段:在32位操作系統下,如果DB == 1,則默認操作數是32位,如果操作16位時,其會加上前綴指令66。
(66 50 push ax / 50 push eax)
2)數據段:該段作用與不同的數據段其含義不同。
(1)SS段:DB == 0 ,使用16位寄存器 sp; DB == 1,使用32位寄存器 esp。
(2) DS、ES、GS、FS:表示界限(Limit),DB == 0 ,Limit 64KB;DB == 1,Limit 0xFFFFFFFF。
4. 段權限檢查
1)三個概念:
(1)RPL(Request Privilege Level) 請求特權級別,段選擇子的后兩位。
(2)DPL(Descriptor Privilege Level) 段描述特權級別,13位與14位。
(3)CPL(Current Privilege Level)當前特權級別,當前工作在CS\SS段的RPL。
2)權限檢查:
簡單解釋下上面的概念就很好理解,像 mov ,eax,3bh ; mov ds,eax 。 這種就會進行有關段權限檢查,如果不通過賦值會失敗。
首先,CPL表示當前工作的環境(0環或3環),如果CPL為3環,其段選擇子后兩位不可能為0(不用訪問,請求都請求不了)。
而即使你生成請求,其還會和段描述符中的DPL校驗,如果校驗不通過,你依然無法生成。