要点回顾:
上一篇段属性探测2中,我知道了当写一个段寄存器的时候,只给了16位的数,但段寄存器有96位,那剩下的80位从哪里来的?,这16位数是随便写的码?
GDT(Global Descriptor Table)全局描述符表和LDT(局部描述符表)
当我们执行类似MOV DS,AX指令时,CPU会查表,根据AX的值来决定查找GDT还是LDT,查找表的什么位置,查出多少数据。
window并没有使用LDT,我们主要是查询的是gdtr,这里需要虚拟机和windbg调试环境。
用来查看gdtr寄存器的位置:
r gdtr 用来查看寄存器(48位=32(表的起始地址)+16(表的大小))
r gdtl 用来查看表的大小
dd dd 8003f000 用来查看表的数据
2.段描述符:
我们都知道段寄存器有96位但是我们只给16位剩余的值就是从这张表里面查出来的数据放进去,每次需要查询8个字节(64位),因为GDT里面存放的每一个元素称为段描述符
因为段描述符占8个字节(64位),dq命令可以帮助我们一次读取8个字节的数据(低位在前,高位在后)
段选择子
当我们执行 MOV DS,AX指令时就是查找GDT这张表,查GDT表的那个位置由源操作数(AX)来决定,一旦查到它就会把段描述符8个字节放到段寄存器中,每个原操作数使用的段描述符都不一样所以我们要学习段选择子。
段选择子共有16位,该描述符指向了定义该段的描述符
第0-1位:RPL(请求特权级别,段权限检查)
第2位:TI位 分为两种情况 TI=0 查GDT表 ,TI = 1查找LDT表(一般TI=0代表windows)windows没有使用LDT表
第3-15位:就是一个索引,我们到底查找那个段描述符就是由第3位到第15位
比如 段选择子 1B = 001B = 0000 0000 00001 1011(对这十六位按段选择子的位数进行拆分)
RPL = 11 =3(最后两位)
TI = 0(第最后末三位)(gdt表)
最后剩下的为:0000 0000 00001 1 = 3 查找的就是第三个字节的
加载段描述符至段寄存器
除了MOV指令,我们还可以使用LES、LSS、LDS、LFS、LGS指令修改寄存器(其中l为加载的意思)
CS不能通过上述的指令进行修改,CS为代码段,CS的改变会导致EIP的改变,要改变CS,必须保证CS和EIP一起改,后面再说。
char buffer[6];
__asm
{
les ecx,fword ptr ds:[buffer]//高两个字节给了es,低四个字节给ecx
}
注意RPL<=DPL(DPL在高四个字节的第13-14位上,一定要熟练段描述表)(在数值上)
总结
1.记住段描述符与段选择子(必须要记住)
2.使用LES、LDS等指令修改段寄存器
思考:段描述符共有64位,但是需要填充80位,怎么填呢
段寄存器(96位) = 16位的Selector+64位的段描述符+?