1. 程式人生 > >保護模式1-段暫存器-基本屬性

保護模式1-段暫存器-基本屬性

段暫存器是什麼?
Segment Register 也可以稱作 Selector Register
當我們用匯編讀寫某個地址時
MOV DWORD PTR DS:[0X00401000],EAX

我們讀寫的地址其實是DS.BASE+0x00401000

0x00401000被稱為讀寫的有效地址
DS.BASE+0x00401000被稱為線性地址,這裡做了解即可

段暫存器有自己結構

段暫存器一共96位,但是可見部分只有16位

Struct SegMent
{
WORD Selector; //16位段選擇子
WORD Attributes; //16位屬性
DWORD Base; //32位基址
DWORD Limit; //32位段限長
}

其中不可見部分暫不理會,可見部分可以通過OD隨便開啟一個程式檢視
其中紅色部分就是段選擇子Select

段暫存器  Select  Attribute  Base      Limit
ES      002B    可讀/可寫   0         0xFFFFFFFF
CS      0023    可讀/可執行  0         0xFFFFFFFF
SS      002B    可讀/可寫   0         0xFFFFFFFF
DS      002B    可讀/可寫     0            0xFFFFFFFF
FS      0053     可讀/可寫  0x7FFDE000   0xFFF
GS - - - -

為了驗證段暫存器的屬性:

Selector:

MOV AX,ES

這裡的段選擇子為16位,只能使用16位AX暫存器,不能使用32位EAX暫存器

EAX 0000002B
ECX 00FF0000
...

通過讀取段暫存器,我們發現只能讀取16位,這可見部分就是段選擇子

Attribute:

int var = 0;
__asm
{
MOV AX,SS //SS可讀,可寫 CS可讀,可執行
MOV DS,AX
MOV DWORD PTR DS:[var],EAX
}

執行上面程式碼發現並沒有什麼用,因為DS修飾的段指向了SS,SS段暫存器可讀可寫
如果把SS換成CS,就會發現訪問錯誤,因為CS可讀可執行,但是並不可寫

Base:

int var = 0;
__asm
{
MOV AX,FS //不能換成DS
MOV GS,AX
MOV EAX,GS:[0]
MOV DWORD PTR DS:[VAR],EAX
//MOV DWORD PTR DS:[0X7FFDF000]
}

如果訪問地址0會報記憶體訪問錯誤0xC0000005錯誤這是常識,但是由於FS段暫存器的Base為0X7FFDF000
線性地址=FS.Base+有效地址 ---------------------- FS.0X7FFDF000+0x00000000
等於說直接訪問了0X7FFDF000這個位置,雖然我們程式碼裡寫的是0
如果換成其他Base為0的暫存器就會發現記憶體訪問錯誤

Limint:

int var = 0;
__asm
{
MOV AX,FS //不能換成DS
MOV GS,AX
MOV EAX,GS:[0x1000]
MOV EAX,DWORD PTR DS:[0X7FFDF000+0x1000]
MOV DWORD PTR DS:[var],EAX
}

0x0X7FFDF000+0x1000
FS段暫存器的段限長為FFF,但是我們讀取的是0x1000位置的資料,這就能證明段的Limint真實存在