2.[保護模式]段寄存器


1.段寄存器結構

 

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

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


其中紅色部分就是段選擇子(就是做段權限檢測的)Selector比如:2B拆分如下 0010 1011 -》0010 1 0 11

00101查找GDT表里面的位置索引5

0 查GDT表,如果為1則查LDT表(LDT能有多張表)
11 所處的請求級別RPL ,3是三環 0 是0環


HEX=轉成16進制
那么索引公式是:GDT表首地址(通過 r gdtr獲取)+HEX[索引值(5)*8(字節寬度)]

2.段寄存器的讀寫:

  讀段寄存器:

    比如:MOV AX,ES  只能讀16位的可見部分

    讀寫LDTR 的指令為:SLDT/LLDT

    讀寫TR的指令為:STR/LTR

  寫段寄存器:

    比如:MOV DS,AX 寫的時候是寫96位

 

除了CS 都是可讀可寫屬性。

 

3.既然只有16位可見位那怎么判讀另外的80位是存在的呢?接下來我們進行探查

 一、探測Attribute

    attr =0cf3   第一位沒有用使用所以補0 

#include "stdafx.h"
//兩個可讀可寫段寄存器互換沒影響
int var = 0;
int main()
{
    
    __asm
    {
        mov ax,ss   //將SS的值讀出來
        mov ds,ax    //將AX寫入,此時ds已經是SS了
        mov dword ptr ds:[var],eax  //實際上已經是ss:[var]
    return 0;
}  

 

  //以下代碼報錯證明Attribute屬性起作用了!

 

#include "stdafx.h"

int var = 0;
int main()
{
    
    __asm
    {
        mov ax,cs   //將CS的值讀出來  ,但是CS是可讀可執行,並不可寫
        mov ds,ax    //將AX寫入,此時就會報錯
        mov dword ptr ds:[var],eax  //兩個不同屬性的並不能轉換
    return 0;
}

 

 2.探測BASE:

 1 #include "stdafx.h"
 2 
 3 int var = 0;
 4 int main()
 5 {
 6     __asm
 7     {
 8         mov ax,fs     
 9         mov gs,ax      //此處如果換成ds則會出現編譯不過的問題
10         mov eax,gs:[0]  //對0地址進行讀的操作(如果是0地址不能讀也不能寫,此時gs已經是fs)
11         //相當於
12         //mov edx,dword ptr ds:[0x7FFDF000]
13         mov dword ptr ds:[var],eax
14     }
15     
16 }

  3.探測Limit

limt:(fffff+1)*4k -1 =ffffffff

4k = 4096

fffff是從0開始所以應該+1

 

#include "stdafx.h"
//報錯,fs訪問越界,證明Limit真實存在
int var = 0;
int main()
{
    __asm
    {
        mov ax,fs     
        mov gs,ax      //此處如果換成ds則會出現編譯不過的問題
        mov eax,gs:[1000]  //fs的limit是FFF 但是讀0x1000則越界了
        //訪問的地址相當於下面的 但是DS的Limit是0xFFFFFFFF
        //mov eax,dword ptr ds:[0x7FFDF000+0x1000]
        mov dword ptr ds:[var],eax
    }
    
}

4.段寄存器有96位,那剩下的80位從哪來的?

數據是從GDT表里面來的,在線程和進程沒有切換的情況下:讀取后會把它弄進一個緩沖區,只會讀取GDT表一次

  1.GDT(全局描述符表) LDT(局部描述符表)

      當我們執行類似MOV DS,AX 指令時,CPU會在系統中查表,根據AX的值來決定查找GDT表還是LDT表,查找表的什么位置

查出多少數據;

在WinDbg中 使用 r gdtr  命令來查找gdtr寄存器里的地址,r 則是查看寄存器的意思;

使用 r gdtl 指令則是查看這張表有多大!

使用dd 查看表內容

1: kd> r gdtr
gdtr=fffff8800470b4c0
1: kd> r gdtl
gdtl=007f
1: kd> dd fffff8800470b4c0
fffff880`0470b4c0 00000000 00000000 00000000 00000000
fffff880`0470b4d0 00000000 00209b00 0000ffff 00cf9300
fffff880`0470b4e0 0000ffff 00cffb00 0000ffff 00cff300
fffff880`0470b4f0 00000000 0020fb00 00000000 00000000
fffff880`0470b500 4ec00067 04008b70 fffff880 00000000
fffff880`0470b510 e0007c00 ff40f3f9 00000000 00000000
fffff880`0470b520 0000ffff 00cf9a00 00000000 00000000
fffff880`0470b530 00000000 00000000 00000000 00000000

 
   

GDT表內存儲的元素稱之為:“段描述符”

每個段描述符占8個字節

段描述符結構(必背):

看一個段首先看P為是否可用,然后看S位 -TYPE 看看描述的是個什么東西,其次看D/B  ,再看G位

 

 

 

dq指令 則是查看8字節;

如果想要查看更多 則可以使用 dq 地址  L數量

nt!RtlpBreakWithStatusInstruction:
fffff800`03ec7fb0 cc int 3
1: kd> r gdtr
gdtr=fffff8800470b4c0
1: kd> r gdtl
gdtl=007f
1: kd> dd fffff8800470b4c0
fffff880`0470b4c0 00000000 00000000 00000000 00000000
fffff880`0470b4d0 00000000 00209b00 0000ffff 00cf9300
fffff880`0470b4e0 0000ffff 00cffb00 0000ffff 00cff300
fffff880`0470b4f0 00000000 0020fb00 00000000 00000000
fffff880`0470b500 4ec00067 04008b70 fffff880 00000000
fffff880`0470b510 e0007c00 ff40f3f9 00000000 00000000
fffff880`0470b520 0000ffff 00cf9a00 00000000 00000000
fffff880`0470b530 00000000 00000000 00000000 00000000
1: kd> dq fffff8800470b4c0
fffff880`0470b4c0 00000000`00000000 00000000`00000000
fffff880`0470b4d0 00209b00`00000000 00cf9300`0000ffff
fffff880`0470b4e0 00cffb00`0000ffff 00cff300`0000ffff
fffff880`0470b4f0 0020fb00`00000000 00000000`00000000
fffff880`0470b500 04008b70`4ec00067 00000000`fffff880
fffff880`0470b510 ff40f3f9`e0007c00 00000000`00000000
fffff880`0470b520 00cf9a00`0000ffff 00000000`00000000
fffff880`0470b530 00000000`00000000 00000000`00000000
1: kd> dq fffff8800470b4c0 L50
fffff880`0470b4c0 00000000`00000000 00000000`00000000
fffff880`0470b4d0 00209b00`00000000 00cf9300`0000ffff
fffff880`0470b4e0 00cffb00`0000ffff 00cff300`0000ffff
fffff880`0470b4f0 0020fb00`00000000 00000000`00000000
fffff880`0470b500 04008b70`4ec00067 00000000`fffff880
fffff880`0470b510 ff40f3f9`e0007c00 00000000`00000000
fffff880`0470b520 00cf9a00`0000ffff 00000000`00000000
fffff880`0470b530 00000000`00000000 00000000`00000000
fffff880`0470b540 03ec8e00`0010cf00 00000000`fffff800
fffff880`0470b550 03ec8e00`0010d000 00000000`fffff800
fffff880`0470b560 03ec8e03`0010d1c0 00000000`fffff800
fffff880`0470b570 03ecee00`0010d540 00000000`fffff800
fffff880`0470b580 03ecee00`0010d640 00000000`fffff800
fffff880`0470b590 03ec8e00`0010d740 00000000`fffff800
fffff880`0470b5a0 03ec8e00`0010d840 00000000`fffff800
fffff880`0470b5b0 03ec8e00`0010da80 00000000`fffff800
fffff880`0470b5c0 03ec8e01`0010db40 00000000`fffff800
fffff880`0470b5d0 03ec8e00`0010dc00 00000000`fffff800
fffff880`0470b5e0 03ec8e00`0010dcc0 00000000`fffff800
fffff880`0470b5f0 03ec8e00`0010dd80 00000000`fffff800
fffff880`0470b600 03ec8e00`0010dec0 00000000`fffff800
fffff880`0470b610 03ec8e00`0010e000 00000000`fffff800
fffff880`0470b620 03ec8e00`0010e140 00000000`fffff800
fffff880`0470b630 04008e00`001090f0 00000000`fffff800
fffff880`0470b640 03ec8e00`0010e500 00000000`fffff800
fffff880`0470b650 03ec8e00`0010e680 00000000`fffff800
fffff880`0470b660 03ec8e02`0010e780 00000000`fffff800
fffff880`0470b670 03ec8e00`0010eb00 00000000`fffff800
fffff880`0470b680 04008e00`00109140 00000000`fffff800
fffff880`0470b690 04008e00`00109150 00000000`fffff800
fffff880`0470b6a0 04008e00`00109160 00000000`fffff800
fffff880`0470b6b0 04008e00`00109170 00000000`fffff800
fffff880`0470b6c0 04008e00`00109180 00000000`fffff800
fffff880`0470b6d0 04008e00`00109190 00000000`fffff800
fffff880`0470b6e0 04008e00`001091a0 00000000`fffff800
fffff880`0470b6f0 04008e00`001091b0 00000000`fffff800
fffff880`0470b700 04008e00`001091c0 00000000`fffff800
fffff880`0470b710 04008e00`001091d0 00000000`fffff800
fffff880`0470b720 04008e00`001091e0 00000000`fffff800
fffff880`0470b730 03f18e00`0010af10 00000000`fffff800

 
   

 

 

段選擇子:

段選擇子是一個16位的段描述符,該描述符指向了定義該段的段描述符。 

如: 1B (001B)00一般省略 拆分后為 0000 0000 0001 1011

0000 0000 0001 1 (這里拼接起來為3則查找GDT表第3相)   0(TI)11(RPL)

加載段描述符至段寄存器:

 這里的RPL<=DPL不准確,數值上應該是RPL>=DPL

2019-07-21

三環讀取GDT表首地址

unsigned char buf[6]={0};
_asm
{
  sgdt buf;  
}
printf("%x,%x",*((unsingned int*)&(buf[2])),
*((unsingned short*)&(buf[0])));
)

 每次執行代碼都要經過CS段!CPL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM