最初发在QQ空间里,Windows 7下的段和门

这段时间看了保护模式的一些文章,零零碎碎一大堆概念,什么代码段,数据段,LDT,TSS,还有各种各样的门。,心血来潮写了个windbg的脚本,分析Windows系统的使用情况。先看看运行的结果吧,令人surprise。

不带参数的运行,打印命令的说明,相当于help。

0: kd> $$>a< f:\sync\gdt.txt

First argument (0) ...
 0x1 is to output code segment {00011000}.
 0x2 is to output data segment {00010000}. 
 0x4 is to output LDT {00000010}. 
 0x8 is to output TSS {0000x0y1 (x: 16/32 bit, y: avl/busy)}. 
 0x10 is to output call gate {0000x100 (x: 16/32 bit)}. 
 0x20 is to output task gate {00000101}. 
 0x40 is to output trap gate {0000x111 (x: 16/32 bit)}. 
 0x80 is to output interrupt gate {0000x110 (x: 16/32 bit)}. 
 0x4000 is to output items with DPL 3. 
 0x8000 is to output reserved items {0, 8, 0x0a, 0x0d}. 
 
Second argument (3)...
 0x1 is from GDT.
 0x2 is from IDT. 

先看看代码段,GDT表中有3个,IDT表中没有,也不可能有。3个代码段分别是0x8(内核态下的代码段),0x1B(用户态下的代码段)和0xF0(用来调用Bios中断的代码KiI386CallAbios,属性 Execute Only)。

0: kd> $$>a< f:\sync\gdt.txt 1
Implicit thread is now 8a4586e8
====================================================================================
========================== G D/B L AVL .... P DPL S Type ===========================
GDT base address: 80b95000, Number of items: 128

Index:0001, Attribute:c09b, DPL=0, Type=001B(InternalType:10001), Selector:8
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P  Nl 00000c9b

Index:0003, Attribute:c0fb, DPL=3, Type=001B(InternalType:10001), Selector:1b
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
001B 00000000 ffffffff Code RE Ac 3 Bg Pg P  Nl 00000cfb

Index:001E, Attribute:  98, DPL=0, Type=0018(InternalType:10001), Selector:f0
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
00F0 8484896c 000003b2 Code EO    0 Nb By P  Nl 00000098

There are total 3 item(s).

IDT base address: 80b95400, Number of items: 256

There are total 0 item(s).

====================================================================================
再来看看数据段,IDT表中没有,GDT表中有8个,0x10是内核的数据段,0x23是用户态的,0x30,0x3B分别是内核态和用户态下的FS段,0x70是GDT表本身,0x43段很奇怪,从1K到64K,DPL=3,给用户态用的?0xE8和0xF8这2个段属性一样,地址范围也一样,为什么需要2个呢?

0: kd> $$>a< f:\sync\gdt.txt 2
Implicit thread is now 8a4586e8
====================================================================================
========================== G D/B L AVL .... P DPL S Type ===========================
GDT base address: 80b95000, Number of items: 128

Index:0002, Attribute:c093, DPL=0, Type=0013(InternalType:10001), Selector:10
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0010 00000000 ffffffff Data RW Ac 0 Bg Pg P  Nl 00000c93

Index:0004, Attribute:c0f3, DPL=3, Type=0013(InternalType:10001), Selector:23
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0023 00000000 ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

Index:0006, Attribute:4093, DPL=0, Type=0013(InternalType:10001), Selector:30
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0030 8493ac00 00003748 Data RW Ac 0 Bg By P  Nl 00000493

Index:0007, Attribute:40f3, DPL=3, Type=0013(InternalType:10001), Selector:3b
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
003B 7ffdf000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3

Index:0008, Attribute:  f2, DPL=3, Type=0012(InternalType:10001), Selector:43
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0043 00000400 0000ffff Data RW    3 Nb By P  Nl 000000f2

Index:000E, Attribute:  92, DPL=0, Type=0012(InternalType:10001), Selector:70
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0070 80b95000 000003ff Data RW    0 Nb By P  Nl 00000092

Index:001D, Attribute:  92, DPL=0, Type=0012(InternalType:10001), Selector:e8
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
00E8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092

Index:001F, Attribute:  92, DPL=0, Type=0012(InternalType:10001), Selector:f8
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
00F8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092

There are total 8 item(s).

IDT base address: 80b95400, Number of items: 256

There are total 0 item(s).

====================================================================================

0x4000是个特别的option,用来观察所有DPL=3的项。我的系统上有1个代码段,3个数据段,还有7个中断门,对应着7个系统服务。DPL=3,意味着可以在用户态下直接访问它们。

0: kd> $$>a< f:\sync\gdt.txt 4000
Implicit thread is now 8a4586e8
====================================================================================
========================== G D/B L AVL .... P DPL S Type ===========================
GDT base address: 80b95000, Number of items: 128

Index:0003, Attribute:c0fb, DPL=3, Type=001B(InternalType:20001), Selector:1b
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
001B 00000000 ffffffff Code RE Ac 3 Bg Pg P  Nl 00000cfb

Index:0004, Attribute:c0f3, DPL=3, Type=0013(InternalType:20001), Selector:23
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0023 00000000 ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

Index:0007, Attribute:40f3, DPL=3, Type=0013(InternalType:20001), Selector:3b
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
003B 7ffdf000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3

Index:0008, Attribute:  f2, DPL=3, Type=0012(InternalType:20001), Selector:43
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0043 00000400 0000ffff Data RW    3 Nb By P  Nl 000000f2

There are total 4 item(s).

IDT base address: 80b95400, Number of items: 256

Index:0003, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484F5D0
(8484f5d0)   nt!KiTrap03   |  (8484f6b0)   nt!Dr_kit4_a
Exact matches:
    nt!KiTrap03 = <no type information>

Index:0004, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484F758
(8484f758)   nt!KiTrap04   |  (8484f810)   nt!Dr_kit5_a
Exact matches:
    nt!KiTrap04 = <no type information>

Index:002A, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484E64A
(8484e64a)   nt!KiGetTickCount   |  (8484e74c)   nt!Dr_kcb_a
Exact matches:
    nt!KiGetTickCount = <no type information>

Index:002B, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484E7D0
(8484e7d0)   nt!KiCallbackReturn   |  (8484e864)   nt!Dr_kira_a
Exact matches:
    nt!KiCallbackReturn = <no type information>

Index:002C, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484E90C
(8484e90c)   nt!KiRaiseAssertion   |  (8484e994)   nt!Dr_kui_a
Exact matches:
    nt!KiRaiseAssertion = <no type information>

Index:002D, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484F4A8
(8484f4a8)   nt!KiDebugService   |  (8484f528)   nt!Dr_kit3_a
Exact matches:
    nt!KiDebugService = <no type information>

Index:002E, Attribute:  ee, DPL=3, Type=000E(InternalType:20004), Selector:0008, Offset:8484DFFE
(8484dffe)   nt!KiSystemService   |  (8484e082)   nt!KiFastCallEntry2
Exact matches:
    nt!KiSystemService = <no type information>

There are total 7 item(s).

====================================================================================

直接说下其它的一些结果,Task gate有3个,TSS有4个,3个对应着Task gate,1个是所有任务共用的。没有LDT,没有Call gate,没有Trap gate。

看过OS的基本数据后,想到一些不明白地方,

1. PE的文件加载时,各个节(如.text,.data)和保护模式的段是怎么对应的?从用户态进入内核态时,段(代码段,数据段等)的切换是怎么做的?int 2e或者.sysenter一条指令就够了嘛?

2. 象int 0,int 1,int 3(对应的异常码是#DE,#DB,#BP)通常都认为是异常,为什么OS中却是使用中断门,而不是陷阱门来表示?

不知道答案,也不知道从哪下手。

  • 标 题:答复
  • 作 者:XPoy
  • 时 间:2011-08-28 01:34:31

支持,学习
保护模式中,已经不再需要让各个节(如.text,.data)和保护模式的段对应了

int 2e或者.sysenter一条指令,
做的事情就是修改代码段CS的值为一个GDT中合适的R0执行权限的值,SS段寄存器,这时也会被修改成合CS一样的值。EIP也修改成为要执行的被操作系统指定的调度接下来怎么执行的代码。同时ESP也会被修改成为新的ESP,也就是R0的ESP,就当systen它做一个特殊用途中断,操作系统的R0代码就当是在异常处理里面执行的,win98时就可以这样进入R0的。当然,还是要一般而言下,sysenter修改之后,代码段CS包含的新的段描述的DPL位的值是0的。
那个陷阱和中断的,我自己的机子上是对劲的,vmware里的XP SP3
kd> !idt 0;!idt 1;!idt 3;
Dumping IDT:
00:  8053f19c nt!KiTrap00
Dumping IDT:
01:  8053f314 nt!KiTrap01
Dumping IDT:
03:  8053f6e4 nt!KiTrap03

kd> !pcr
KPCR for Processor 0 at ffdff000:
    Major 1 Minor 1
  NtTib.ExceptionList: 8054a4b0
      NtTib.StackBase: 8054acf0
     NtTib.StackLimit: 80547f00
   NtTib.SubSystemTib: 00000000
        NtTib.Version: 00000000
    NtTib.UserPointer: 00000000
        NtTib.SelfTib: 00000000

              SelfPcr: ffdff000
                 Prcb: ffdff120
                 Irql: 00000000
                  IRR: 00000000
                  IDR: ffffffff
        InterruptMode: 00000000
                  IDT: 8003f400
                  GDT: 8003f000
                  TSS: 80042000

kd> dyd 8003f400
           3          2          1          0
          10987654 32109876 54321098 76543210
          -------- -------- -------- --------
8003f400  00000000 00001000 11110001 10011100  0008f19c
8003f404  10000000 01010011 1000|1110| 00000000  80538e00
8003f408  00000000 00001000 11110011 00010100  0008f314
8003f40c  10000000 01010011 1000|1110| 00000000  80538e00
8003f410  00000000 01011000 00010001 00111110  0058113e
8003f414  00000000 00000000 1000|0101| 00000000  00008500
8003f418  00000000 00001000 11110110 11100100  0008f6e4
8003f41c  10000000 01010011 1110|1110| 00000000  8053ee00
除了第三个是?101的中断类型的元素的。其他的都是1110的trap元素

上面那句话是错的,只要能够修改CS段寄存器的指令,都会影响的。因为现在所用的DPL就保存在段寄存器中啊。CS决定代码的执行权限,是因为执行代码时,默认所用的是cs作为段寄存器的,也就说,有可能ES段中保存一个R0的段描述符,然后你就可以通过ES:0x80004000来访问内核的地址,而正常的访问还是DS段寄存器,不能访问到内核的范围 :P 当然那样有点无厘头。

  • 标 题:答复
  • 作 者:zyqqyz
  • 时 间:2011-08-31 10:27:38

你们都想多了,数据段等的特权级即ds、es等寄存器是不会变的,他们还是R3,因为进入R0,CS中的CPL就是最高级别,他可以访问一切特权级的代码和数据包括R3的,数据访问的保护主要比较CPL与数据段的DPL。例如在内核空间ds指向一个R3级别的数据段描述符,只要该数据段的段长为4G,即可用ES:[80008000h]一类的了,因为此时的CPL已经是0。
其实在R3空间中,cs和es都指向的是r3的段,那么用ES:[80008000h]在段保护一级上也可以通过,因为是CPL为3来访问DPL为3的数据段。但是之所以会失败是因为页保护,内核的页面有U/S位的限制,限制了只有CPL为0的权限才能访问。所以是只有通过了段保护和页保护才能成功。
所以也不需要更改ds、es等寄存器了。
至于楼主说的更改DPL为0,也不是办不到只需在GDT找到DPL为0的段的索引,用mov ax,***    mov ds,ax即可,只不过需要写个patch来修改PE加载器。但是这样程序就完蛋了,因为在R3中执行时,你要求CPL为3来访问DPL为0的段,肯定是通不过的。

  • 标 题:答复
  • 作 者:ronging
  • 时 间:2011-08-31 14:29:08

CS中的CPL就是最高级别,他可以访问一切特权级的代码和数据包括R3的

我觉得CPL=0的代码段访问DPL=3的数据段没有问题,但CPL=0的代码段应该是不能访问DPL=3的代码段的。

另外,ds,es在进入Ring0后是会变的,只不过数值还是0x23,和用户态下的一样。KiTrap**大多是这么实现的。不知道为什么有这样的代码,可能为变化作准备。

引用:
最初由 zyqqyz发布 查看帖子
你们都想多了,数据段等的特权级即ds、es等寄存器是不会变的,他们还是R3,因为进入R0,CS中的CPL就是最高级别,他可以访问一切特权级的代码和数据包括R3的,数据访问的保护主要比较CPL与数据段的DPL。例如在内核空间ds指向一个R3级别的数据段描述符,只要该数据段的段长为4G,即可用ES:[8...
这段话给了我些启发,只要段是4G的,不管DPL=0还是DPL=3,80008000这个线性地址都是唯一的,因为是段页式内存管理,所以相应的存在双重保护,既要检查段的安全属性,也会检查页的安全属性。

  • 标 题:答复
  • 作 者:zyqqyz
  • 时 间:2011-08-31 16:50:01

请牢记,在flat模式下内存中是没有数据段代码段之分的,通过段寄存器查GDT表得到的段基本上都是4g的平坦地址,至于你说R0代码段访问R3代码段这个说法本身就不准确。你可能说的是在R0中执行R3空间的代码吧,这个是没有问题的,而且有些内核漏洞的利用就是这样的。通过在R3地址下写入一些shellcode,然后利用内核漏洞以R0的模式执行R3的代码完成对IDT,SSDT,GDT等关键数据的修改。因为在R0模式下是可以执行一切的代码访问一切数据的除了cr寄存器中的写保护除外。另外既然ds,es的数值没变,GDT没变,那么它们所代表的段及属性能变吗?建议楼主看一些linux、windows源码的相关资料,再加强一下对IA-32手册第三卷的阅读。

  • 标 题:答复
  • 作 者:ronging
  • 时 间:2011-08-31 18:55:04

引用:
最初由 zyqqyz发布 查看帖子
请牢记,在flat模式下内存中是没有数据段代码段之分的,通过段寄存器查GDT表得到的段基本上都是4g的平坦地址,至于你说R0代码段访问R3代码段这个说法本身就不准确。你可能说的是在R0中执行R3空间的代码吧,这个是没有问题的,而且有些内核漏洞的利用就是这样的。通过在R3地址下写入一些shellcod...
你的说法很给力啊,我还是头一次听到。内存中没有数据段代码段之分。,你的意思应该是指代码段和数据段是混在一起的,共享一个4G的地址空间吧。

另外,JMP指令还是CALL指令,代码段之间切换时的要求都是当前代码段的CPL=目标代码段的DPL,只有通过门时可以用CPL>=DPL。不知道你说的代码段之间的跳转是通过什么样的跳转方式,允许当前代码段的CPL<目标代码段的DPL?

  • 标 题:答复
  • 作 者:ronging
  • 时 间:2011-08-31 22:16:00

引用:
最初由 ronging发布 查看帖子
CS中的CPL就是最高级别,他可以访问一切特权级的代码和数据包括R3的

我觉得CPL=0的代码段访问DPL=3的数据段没有问题,但CPL=0的代码段应该是不能访问DPL=3的代码段的。

另外,ds,es在进入Ring0后是会变的,只不过数值还是0x23,和用户态下的一样。KiTrap**...
又想起了另一个例子,用户模式下CS段的DPL=3,但也是4G空间,(和内核模式下的CS段是共享地址空间的),因此代码是可能直接访问80000000以上的地址处的代码的,如直接使用JMP或者CAll一个内核的API,不能访问的原因不是因为DPL通不过,而应该也是U/S标志位的限制。

  • 标 题:答复
  • 作 者:zyqqyz
  • 时 间:2011-09-01 10:13:49

你的思维囿于了8086的段模式,冯诺依曼结构的数据与代码本来就是不区分的,否则缓冲区溢出就很难了,intel也就不搞什么DEP了;哈佛结构类似于51单片机才有数据代码的区分。
至于你说的R0访问R3,当然从CPL为0的远跳到DPL为3的肯定办不到。但是为什么要跳呢,在R0下除了FS,其余的段寄存器都是4g的属性,直接用CPL为0的cs访问不就行了。在flat模式下一定要忘记段的概念,因为windows这样设计就是为了简化段的作用的。

  • 标 题:答复
  • 作 者:ronging
  • 时 间:2012-05-13 13:17:34

引用:
最初由 ronging发布 查看帖子
CS中的CPL就是最高级别,他可以访问一切特权级的代码和数据包括R3的

我觉得CPL=0的代码段访问DPL=3的数据段没有问题,但CPL=0的代码段应该是不能访问DPL=3的代码段的。

另外,ds,es在进入Ring0后是会变的,只不过数值还是0x23,和用户态下的一样。KiTrap**...
第2篇在这里:Win7下的段和门 (2) 

最近看了下手册

从R3到R0,DS,ES可以使用DPL=3的,SS必须使用新的。

Before the processor loads a segment selector into a segment register, it performs a privilege check by comparing the privilege levels of the currently running program or task (the CPL), the RPL of the segment selector, and the DPL of the segment’s segment descriptor. The processor loads the segment selector into the segment register if the DPL is numerically greater than or equal to both the CPL and the RPL. Otherwise, a general-protection fault is generated and the segment register is not loaded.

CPL=0的代码段可以加载DPL=3的数据段,

PRIVILEGE LEVEL CHECKING WHEN LOADING THE SS REGISTER
Privilege level checking also occurs when the SS register is loaded with the segment selector for a stack segment. Here all privilege levels related to the stack segment must match the CPL; that is, the CPL, the RPL of the stack-segment selector, and the DPL of the stack-segment descriptor must be the same. If the RPL and DPL are not equal to the CPL, a general-protection exception (#GP) is generated.

CPL=0的代码段只能加载DPL=0的栈段。

关于CPL,RPL和DPL参考:保护模式下的保护