当读写段寄存器的时候,只需要给一个16位的段选择子,但是段寄存器的96位的属性都是真实存在,那剩下的80位怎么填充?这个16位的选择子到底应该怎么写?
- 当我们执行MOV DS,AX这种指令的时候,CPU会根据AX的值来查找GDT表或者LDT表,查表的什么位置
全局描述符表GDT(Global Descriptor Table)在整个系统中,全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限
在WinDbg中按Ctrl+Break中断到内核,输入
0: kd> r gdtr //得到GDT表的基址 gdtr=8003f000 0: kd> r gdtl //得到GDT表的长度 gdtl=000003ff 0: kd> dq 8003f000 //读取GDT表的内容 8003f000 00000000`00000000 00cf9b00`0000ffff 8003f010 00cf9300`0000ffff 00cffb00`0000ffff 8003f020 00cff300`0000ffff 80008b04`200020ab 8003f030 ffc093df`f0000001 0040f300`00000fff ... //这里可以简写成dq gdtr 0: kd> dq gdtr 8003f000 00000000`00000000 00cf9b00`0000ffff 8003f010 00cf9300`0000ffff 00cffb00`0000ffff 8003f020 00cff300`0000ffff 80008b04`200020ab 8003f030 ffc093df`f0000001 0040f300`00000fff 8003f040 0000f200`0400ffff 00000000`00000000 8003f050 80008955`87000068 80008955`87680068 8003f060 00009302`2f40ffff 0000920b`80003fff 8003f070 ff0092ff`700003ff 80009a40`0000ffff
- 0: kd>: WinDbg的命令行等待输入区
- dd: DWORD
- dq:QWORD
- db:string
GDT表的第一个段描述符为00000000`00000000,第二个为00cf9b00`0000ffff…
通用段描述符结构
---段选择子结构
- RPL:请求特权级别
- TI:
- TI=0查GDT表
- TI=1查LDT表(Windows没有使用)
- INDEX: 处理器将索引值乘以8再加上GDT表的基址,就是要加载的段描述符
加载段描述符到段寄存器
除了MOV指令,我们还可以使用LES、LSS、LDS、LFS、LGS指令修改寄存器.
CS不能通过上述的指令进行修改,CS为代码段,CS的改变会导致EIP的改变,要改CS,必须要保证CS与EIP一起
char buff[6]; __asm { les ecx,fword ptr ds:[buff] //高两个字节给es,低四个字节给ecx char buffer[6] = {0, 0, 0, 0, 0x48, 0};//段选择子0x48 }//RPL<=DPL