前言:段描述符和段选择子的学习
知识点: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