Windows XP 段保护(一)

ʕ •ᴥ•ʔ ɔ:

1 什么是保护模式

R3--SDK

R0--WDK

X86 CPU的3个工作模式:实模式保护模式虚拟8086模式
现在的操作系统都是基于保护模式
保护模式的两个重要机制:段的机制、页的机制。

保护模式:保护对内存的访问、保护某些指令的执行(特权指令 )

段的机制非常复杂,了解段机制就要先了解段寄存器

2 段寄存器

段寄存器一共有八个:ES、CS、SS、DS、FS、GS、LDTR(Windows没有使用)、TR。

  • 每个段寄存器有96位其中GS、LDTR这两寄存器Windows没有使用。
  • LDT表Windows也没有使用。
  • 只有16位的可见部分:Selecter

2.1 段寄存器的结构

1.png

可以通过结构体表示为如下:

1
2
3
4
5
6
7
struct SegMent
{
WORD Selecter; //16位的可见部分(段选择子)
WORD Atrributes; //16位的属性(可读可写可执行)
DWORD Base; //32位的Base(当前段的起始地址)
DWORD Limit; //32位的Limit(当前段的长度)
}

汇编读写一个地址:

1
mov dword ptr ds:[0x00123456],eax

读写的地址实际上是ds.Base+0x123456

实际所有地址的读写都是这个结构XS.Base+Offset

2.2 段寄存器的属性

2.png

段寄存器的读写:

  • mov ax,ds //只能读16位可见部分
  • mov ds,ax //写入是96位
  • 可以通过MOV指令进行读写(LDTR和TR除外)
  • CS是可读、可执行、但不可写

探测Base示例:

1
2
3
4
5
6
7
8
9
10
int var = 1;					
__asm
{
mov ax,fs
mov gs,ax //等价于fs.base+0
mov eax,gs:[0] //不要用DS 否则编译不过去
mov dword ptr ds:[var],eax
//mov edx,dword ptr ds:[0x7FFDF000]
//常规来说,地址0x00是不允许读的,但是FS.Base!=0,所以这里可以编译并执行
}

这里的GS就是FS。

3 段描述符

GDT表存的是段描述符,每个段描述符是64位(8字节)

这里涉及到两张表:GDT(全局描述符表)与 LDT(局部描述符表)。Windows用的是GDT表,LDT表几乎没用。

段描述符结构:(Intel手册卷3A)

3.png

段描述符表的位置、大小信息存在GDTR位寄存器中,GDTR寄存器共6字节:

  • 低2字节:段描述符表的大小

  • 高4字节:段描述符表的起始地址

    4.png

    L8:表示输出的组数为8。

    53.png

3.1 段描述符属性所在位置

Atrribute:高4字节中,8~23位

Base

  • 高4字节中,24~31位,0~7位
  • 低4字节中,16~31位

Limit

  • 高4字节中,16~19位
  • 低4字节中,0~15位

9.png

3.2 段描述查找练习

1
2
3
4
5
6
7
8
9
10
11
kd> r gdtr
gdtr=8003f000
kd> dq 8003f000
8003f000 00000000`00000000 00cf9b00`0000ffff
8003f010 00cf9300`0000ffff 00cffa00`0000ffff
8003f020 00cff300`0000ffff 80008b04`200020ab
8003f030 ffc093df`f0000001 0040f300`00000fff
8003f040 0000f200`0400ffff 00000000`00000000
8003f050 80008955`27000068 80008955`27680068
8003f060 00009302`2f40ffff 0000920b`80003fff
8003f070 ff0092ff`700003ff 80009a40`0000ffff

10.png

4 段选择子

段选择子是一个16位数,该数决定了取gdt表中查哪一个数据。这个值就是MOV DS,AX给的AX的值,从这个值中取赋值剩下的80位(96-16)。

5.png

RPL共2位,值越小权限越大。值为0x00、0x11,对应于Windows使用的0环、3环。

6.png

加载段描述符至段寄存器(其他几个汇编指令修改段寄存器)

除了MOV指令,我们还可以使用LES、LSS、LDS、LFS、LGS指令修改寄存器。

CS不能通过上述的指令进行修改,CS为代码段,CS的改变会导致EIP的改变,要改CS,必须要保证CS与EIP一起改。

1
2
3
4
5
char buffer[6];                    
__asm
{
les ecx,fword ptr ds:[buffer] //高2个字节给es,低四个字节给ecx
}

注意:RPL<=DPL(在数值上)

RPL是段选择子的权限,DPL是段描述符的权限,数值越大权限越小。

5 段描述符的P,G位

9.png

P位

  • P = 1 段描述符有效
  • P = 0 段描述符无效

通过指令将段描述符加载至段寄存器中,先检查P位,如果为0,那么该段描述符无效,其他检查都不做了

G位

G位决定Limit的大小范围。D/B位对数据段来说决定地址空间大小。

  • 当G=0时,Limit的范围是0x00000000-0x000FFFFF,其中,段描述符的20位在低位,高位补0
  • 当G=1时,Limit的范围是0x00000FFF-0xFFFFFFFF,其中,段描述符的20位在高位,低位补F

6 段描述符的S、Type域

9.png

分析一个段描述符:

  1. 先看P位
  2. 再看S位(S = 1 代码段或者数据段描述符,S = 0 系统段描述符)

6.1 S位

  • S=1,表示代码段/数据段;

  • S=0,表示系统段。

    S位决定着Type域的含义。

DPL两种情况:00、11

也就是 00cf9300`0000ffff 的十六进制高四字节第5个数只能为9或F才表示一个有效(P=1)的段描述符CODE/DATA

  • S = 1,CODE/DATA
    • 0x1001:DPL = 0x00
    • 0x1111:DPL = 0x11
  • S = 0,系统段描述符
    • 0x1000:DPL = 0x00
    • 0x1110:DPL = 0x11

6.2 Type域

TYPE域共4位,可以通过查表来确定其含义。(S=1,CODE/DTA、S=0系统段描述符)

  • 当S = 1时,段描述符表示CODE/DATA。
  • 当S = 0时,段描述符是一个系统段描述符。

S = 1,Type=0x1xxx,CODE代码段描述符

CODE:

  • A:段描述符是否被使用过
    • 1:使用过
    • 0:未使用过
  • R:是否可读
    • 1:可读
    • 0:不可读
  • C:一致位
    • 1:一致代码段
    • 0:非一致代码段

S = 0,Type=0x0xxx,DATA数据段描述符

DATA:

  • A:段描述符是否被使用过

    • 1:使用过
    • 0:未使用过
  • W:是否可写

    • 1:可写
    • 0:不可写
  • E:拓展位

    • 1:向下拓展,有效地址为右边红色(红色为64KB或4GB)

    • 0:向上拓展,有效地址为左边红色(Windows使用,红色为64KB或4GB)

      14.png

13.png

15.png

6.3 练习

1、判断哪些是系统段描述符?哪些是代码或者数据段描述符?

2、判断哪些是代码段描述符?哪些是数据段描述符?

3、查分几个数据段:EWA

4、查分几个代码段:CRA

5、查分几个系统段描述符,分析属性

先看P位,再看S位。

16.png

7 段描述符的D/B位

D/B位对数据段来说决定地址空间大小

  1. 情况一:对CS段的影响(加载:MOV CS, AX)

    D = 1 采用32位寻址方式

    D = 0 采用16位寻址方式

  2. 情况二:对SS段的影响(加载:MOV SS, AX)

    D = 1 隐式堆栈访问指令(如:PUSH POP CALL等会修改ESP) 使用32位堆栈指针寄存器ESP

    D = 0 隐式堆栈访问指令(如:PUSH POP CALL等会修改SP) 使用16位堆栈指针寄存器SP

    指令前缀67:改变默认寻址方式,但不是改D/B位,若默认是32寻址,则改为16位寻址。若默认是16寻址,则改为32位寻址。

  3. 情况三:对数据段DS、ES的影响(加载:MOV DS, AX)

    D = 1 段上限为4GB 0xFFFFFFFF

    D = 0 段上限为64KB 0xFFFF

    17.png

Windows XP 段保护(一)

Windows XP 段保护(二)

Windows XP 段保护(三)