1.证明属性位的存在
int G;
int main(int argc, char* argv[])
{
_asm {
mov AX, SS
MOV DS, AX
mov dword ptr ds : [G] , eax//将值写到ds段寄存器中 证明了属性位的存在如果是CS段那么运行会失败
}
return 0;
}
2.探测base的存在,同时也探测了base的存在
探测base的存在
int G;
int main(int argc, char* argv[])
{
_asm {
mov AX, FS//不能换成ds
MOV GS, AX
mov EAX, GS: [0]//真正读取的是fs.base+0,如果把0改成1000那么就会导致越界,因为fs.base=7ffde000 超过7FFFFFFF就表示越界
mov dword ptr ds : [G] , eax
}
return 0;
3.段寄存器只看到了16位那么剩下的80位怎么来呢,首先了解一下P位和G位
在段寄存器中依赖两张表,全局描述符表(GDT)和局部描述符表(LDT),做个比方:当我们执行指令MOV DS,AX时,cpu会查表,会根据ax的值来查GDT表还是IDT表,表中所存在的就是段描述符。
1.段描述符中的P=1那么就代表段描述符是有效的,P=0就等于无效
2.那么段描述符一共才64位那么还有16位填写什么呢,那么这就取决于G位
G=0:那么limit的单位是字节,可以在前面补三个0,大小是5个F。
G=1:那么limit单位是kb,在limit后面补三个0,大小是8个F。
段描述符
当s=0代表是系统段描述符,s位是索引12
当s=1时,代表的是数据段或者数据段的描述符,
DPL:被访问权限,只能是11或者是0 位于13和14位
总结当S-DPL-P这几位组合的值是9或者F的时候代表的就是代码段或者数据段,在段描述符中的表现就是从左往右数第五位,当第6位大于等于8那么久代表是代码段,因为代码段TYPE位最高位是1
在TYPE中重要的三个位是WEA 从右往左含义就是,是否访问过,可读或者可写,扩展位---为0向上扩展,为1向下扩展
段描述符属性DB位
67作用就是将原本32位寻址方式改成16位的寻址方式,反过来也是一样的
段权限检查
1.判断一个段描述符是否能够被三环或者0环访问,我们只需要看DPL就行,因为DPL意味着段描述符的被访问权限。
2.mov DS,AX:我们知道这里面的AX存的是一个段选择子,这句汇编语句就是将AX所指向的段描述符加载到DS段寄存器中。
DPL和CPL以及RPL
1.DPL表示的是描述符的特权访问级别,主要规定了访问该描述符需要什么样的权限
2.RPL:以什么样的权限去访问段描述符,存在段选择子中
比如mov ax,0008和mov ax,000B 这两个段选择子所指向的段描述符是完全一样的,但是RPL不一样,也就是说执行访问权限不一样
3.CPL:当前程序执行属于几环,这也就代表了CPU的权限,看CS段寄存器的后两位,CS和SS最后两位必须一致
举例说明
_asm {
mov DS,AX
}如果AX指向的段描述符DPL=0,当前执行程序CPL=3,那么这个指令是不会执行成功的,想要执行成功那么就必须将CPL改成0才可以
数据段的权限检查比较
CPL<=DPL,RPL<=DPL(数值上比较)
代码的跨段执行-----本质就是修改CS段寄存器也就是CPL
同时改变CS和EIP的指令 JMP FAR /CALL FAR/ RENT / INT /IRETED
只改变EIP的指令
JMP/CALL/JCC/RET