前言:段描述符和段選擇子的學習
知識點:CPU的眼里只有GDT和IDT表,在windows中LDT沒有用到
當我們執行類似 MOV DS, AX 指令時,CPU會查表,根據AX的值來決定查找GDT還是LDT,查找表的什么位置,以及查出多少數據
GDT(全局描述符表)
gdtr是一個寄存器,存儲了GDT表所在位置
gdtr寄存器存儲了48位,正常的windbg命令r gdtr
展示的就只有其中的32位
gdtl也是一個寄存器,存儲了GDT表的大小
r gdtl
,該命令展示的是GDT表的大小,gdtl大小為4個字節,也就是16位
這里還可以通過windbg的命令是dd address,來進行展示,dd 8003f000,dd的意思是double dword,那么就是4個字節展示
LDT(局部描述符表)
對於windows來說,沒有用到LDT這個表,所以這里直接跳過
段描述符
GDT表中每8個字節的結構體稱作為段描述符
當mov ds,ax 的時候ax為16位,那么剩下的80位是哪里來的呢?其實就是在GDT表存儲的段描述符,每次查詢為8個字節(64位)
重點:下面的圖需要牢記!
DPL是段描述符的權限,數值越大權限越小, 因此當RPL=3時,只能訪問DPL=3的段描述符;當RPL=0時,可以訪問所有段描述符。
自己的問題:mov ds,ax 的時候賦值了16位,但是每次查詢一次GDT表也就8個字節,那么一共也就64(段描述符)+16(段選擇子)=80位,那剩下的16位又是在哪里?感覺是Attribute沒有看到,但是不知道在哪里去看
如何通過windbg來進行查詢段描述符?windbg的命令 dd GDT表的地址,每8個字節都描述着一個段描述符結構體中的數據
段選擇子
段選擇子是一個16位的段描述符,該描述符指向了定義該段的段描述符,其實就是我們在OD調試器中看到的,也就只有這個Selector能夠讓我們直接觀察到,這個selector就是段選擇子!
RPL:請求特權級別。
TI:TI=0(查GDT表) TI=1 (查LDT表)。
Index:處理器將索引值乘以8,再加上GDT或者LDT的基地址,就是要加載的段描述符。
RPL是段選擇子的權限,數值越大權限越小。
段選擇子與GDT表的關系
這里來講下段選擇子和GDT表的關系,之前一直有疑問,既然GDT表中這么多段描述符,那么和段選擇子之間是有什么聯系呢?
這里先講下段選擇子,段選擇子分成三個部分,其中index是索引,那么就代表當前這個段寄存器是跟GDT表中的第index索引有關系。
這里給個例子,比如段選擇子為1B,因為段選擇子是16位,所以實際上是001B,也就是 0000 0000 0001 1011,那么高13位則 0000 0000 0001 1,那么低位也就是0011,那么索引值則是3,那么這里在windbg中進行看的話,索引值為3的地方,那么偏移地址其實就是gdtr+3*8
,總結下其實就是gdtr+index*8
的偏移地址
實現段描述符到段寄存器
除了MOV指令,我們還可以使用LES、LSS、LDS、LFS、LGS指令修改寄存器.
CS不能通過上述的指令進行修改,CS為代碼段,CS的改變會導致EIP的改變,要改CS,必須要保證CS與EIP一起改,海哥后面會講。
小知識點:fword表示6個字節
LES指令示例如下
//char buffer[6] = {0x66,0x55,0x44, 0x33,0x00, 0xAA}; 無法運行,可能是高位的問題
char buffer[6] = {0x66,0x55,0x44, 0x33,0x11, 0x00}; // 可以運行,目前只感覺只能顯示低兩位
__asm
{
les ecx,fword ptr ds:[buffer] //高2個字節給es,低四個字節給ecx
}
注意:RPL<=DPL(在數值上)
段選擇子的訪問權限RPL和段描述符的DPL的關系
mov ds,ax ,這個指令一定可以成功嗎?答案是不一定的,跟ax此時的的值有關,此時ax就是段選擇子,如果賦值成功,那么ds的段選擇子當前就會變成ax的值。
那么繼續來講,為什么不一定能賦值成功,這個就跟當前ds中的段選擇子對應的段描述符的DPL 和 當前ds這個段選擇子之間RPL的關系
比如ds段選擇子的RPL為3,那么此時賦值成功的ds,那么ds的段描述符的DPL肯定是小於等於3,所以可以這樣說,RPL/DPL的值越小,權限越大!
課堂練習作業
作業一:在windbg查看GDT表的基址和長度
作業二:分別使用dd dq指令查看GDT表
作業三:段描述符查分實驗
拆前五個段描述符
8003f000 0000000000000000 00cf9b00
0000ffff
8003f010 00cf93000000ffff 00cffb00
0000ffff
8003f020 00cff300`0000ffff
第一段 00000000`00000000
高字節
Base 第31:24位 ----- 0
G位 第23位 ----- 0
D/B位 第22位 ----- 0
第21位 ----- 0
AVL 第20位 ----- 0
Segment Limit 第16-19位 ----- 0
P 第15位 ----- 0
DPL 第13-14位 ----- 0
S 第12位 ----- 0
Type 第8-11位 ----- 0
Base 第16-23位 ----- 0
低字節
Base Address 第16-31位 ----- 0
Segment Limit 第0-15位 ----- 0
第二段 00cf9b00`0000ffff
0000 0000 1100 1111 1001 1011 0000 0000`0000 0000 0000 0000 1111 1111 1111 1111
高字節
Base 第31:24位 ----- 0000 0000
G位 第23位 ----- 1
D/B位 第22位 ----- 1
默認為0 第21位 ----- 0
AVL 第20位 ----- 0
Segment Limit 第16-19位 ----- 1111
P 第15位 ----- 1
DPL 第13-14位 ----- 00
S 第12位 ----- 1
Type 第8-11位 ----- 1011
Base 第0-7位 ----- 0000 0000
低字節
Base Address 第16-31位 ----- 0000 0000 0000 0000
Segment Limit 第0-15位 ----- 1111 1111 1111 1111
自己再來個ham博客上的練習例子 其中一個段描述符的值為 00cf9b00 0000ffff
0000 0000 1100 1111 1001 1011 0000 0000`0000 0000 0000 0000 1111 1111 1111 1111
高字節:
Base 第31:24位 ----- 0000 0000
G位 第23位 ----- 1
D/B位 第22位 ----- 1
默認為0 第21位 ----- 0
AVL 第20位 ----- 0
Segment Limit 第16-19位 ----- 1111
P 第15位 ----- 1
DPL 第13-14位 ----- 00
S 第12位 ----- 1
Type 第8-11位 ----- 1011
Base 第0-7位 ----- 0000 0000
低字節
Base Address 第16-31位 ----- 0000 0000 0000 0000
Segment Limit 第0-15位 ----- 1111 1111 1111 1111
拆五個段選擇子
0x23 0x2B 0x30 0x3B 0x53
0x0023
0000000000100 0 11
Index: 0x4
TI: 0
RPL: 11
0x002B
0000000000101 0 11
Index: 0x5
TI: 0
RPL: 11
0x0030
0000000000001 1 00
Index: 0x1
TI: 1
RPL: 00
0x003B
0000000000111 0 11
Index: 0x7
TI: 0
RPL: 11
0X0053
0000000001010 0 11
Index: 0xA
TI: 0
RPL: 11