DPL
DPL存储在段描述符中,规定访问该段的权限级别(Descriptor Privilege Level)
CPL
CPL是当前进程的权限级别(Current Privilege Level),是当前正在指向的代码段所在段的成绩,也就是CS段的DPL
RPL
RPL说明的是进程对段访问的请求权限(Request Privilege Level)
为了更好的加深印象,我们来尝试操作这几个位
对数据段的影响
首先还是得到现在GDT表,然后把index为4的段描述符放到index为9的地方,并且改变其DPL为0环,00cff3000000ffff改为00cf9300
0000ffff
0: kd> eq 807d4c68 0000000 00000000
WriteVirtual: 807d4c68 not properly sign extended
WriteVirtual: 807d4c70 not properly sign extended
0: kd> dq 807d4c20
ReadVirtual: 807d4c20 not properly sign extended
807d4c20 00000000`00000000 00cf9b00`0000ffff
807d4c30 00cf9300`0000ffff 00cffb00`0000ffff
807d4c40 00cff300`0000ffff 80008b7c`f75020ab
807d4c50 8040937c`c0003748 0040f300`00004000
807d4c60 0000f200`0400ffff 00000000`00000000
807d4c70 00000000`00000000 8000897d`1b300068
807d4c80 00000000`00000000 00000000`00000000
807d4c90 800092b9`900003ff 00000000`00000000
这是修改后的样子
0: kd> eq 807d4c68 00cf9300`0000ffff
WriteVirtual: 807d4c68 not properly sign extended
0: kd> dq 807d4c20
ReadVirtual: 807d4c20 not properly sign extended
807d4c20 00000000`00000000 00cf9b00`0000ffff
807d4c30 00cf9300`0000ffff 00cffb00`0000ffff
807d4c40 00cff300`0000ffff 80008b7c`f75020ab
807d4c50 8040937c`c0003748 0040f300`00004000
807d4c60 0000f200`0400ffff 00cf9300`0000ffff
807d4c70 00000000`00000000 8000897d`1b300068
807d4c80 00000000`00000000 00000000`00000000
807d4c90 800092b9`900003ff 00000000`00000000
这时候我们打开某个程序,用寄存器将ds的值换为48(0100 1000),也就是RPL为0环
再继续向下执行,没有任何影响
同理,如果我们将ds的值改为4b(0100 1011),也就是RPL为R3
也是能够正常执行的
所以,综上所述,我们得出结论在普通数据段下,RPL没有效果,是可以让我们随便改的
对堆栈段的影响
我们继续进行实验,这次要修改的是ss寄存器,之前我们已经将DPL改为了R0。所以我们在这里可以把ss改为R3,也就是4b,多余的过程就不截图了
这时候我们继续向下执行,这时候就又进入了错误分发,也就是报错
这时候我们将index号为9的段描述符DPL改为R3
1: kd> dq 807d4c20
ReadVirtual: 807d4c20 not properly sign extended
807d4c20 00000000`00000000 00cf9b00`0000ffff
807d4c30 00cf9300`0000ffff 00cffb00`0000ffff
807d4c40 00cff300`0000ffff 80008b7c`f75020ab
807d4c50 8040937c`c0003748 0040f300`00004000
807d4c60 0000f200`0400ffff 00cf9300`0000ffff
807d4c70 00000000`00000000 8000897d`1b300068
807d4c80 00000000`00000000 00000000`00000000
807d4c90 800092b9`900003ff 00000000`00000000
1: kd> eq 807d4c68 00cff300`0000ffff
WriteVirtual: 807d4c68 not properly sign extended
1: kd> dq 807d4c20
ReadVirtual: 807d4c20 not properly sign extended
807d4c20 00000000`00000000 00cf9b00`0000ffff
807d4c30 00cf9300`0000ffff 00cffb00`0000ffff
807d4c40 00cff300`0000ffff 80008b7c`f75020ab
807d4c50 8040937c`c0003748 0040f300`00004000
807d4c60 0000f200`0400ffff 00cff300`0000ffff//在这里
807d4c70 00000000`00000000 8000897d`1b300068
807d4c80 00000000`00000000 00000000`00000000
807d4c90 800092b9`900003ff 00000000`00000000
这时候重新启动,还是一样将ss修改为4b,这时候就可以正常执行了
所以,综上所述,对于ss堆栈段来说,需要DPL和RPL保持一致,再由CS和SS必须保持一致的原则我们可以知道 对于堆栈来说,只有DPL== RPL==CPL,那么代码才能正常执行
对于代码段的影响
先说在前面,由于编译器的影响,将我的jmp far segement:offset 语句错误的翻译成了jmp dword ptr [offset],导致我光是排错就思考了2小时。这个大坑点后面的人一定不要再踩上去
上网查阅资料,果然,jmp far 这种被认为是16位时期的指令,不过我也是第一次知道原来万能的编译器也会乱翻译(笑
正确的我的能够运行的代码如下
#include "stdafx.h"
#include<Windows.h>
void __declspec(naked) test(){
__asm{
ret;
}
}
int _tmain(int argc,_TCHAR* argv[]){
printf("%x\r\n",test());
char bufcode[6] = {0,0,0,0,0x48,0};
*(int *)&bufcode[0] = (int)test;
printf("bufcode: %02X %02X %02X %02X %02X %02X\n",
(ungigned char)bufcode[0],
(ungigned char)bufcode[1]
(ungigned char)bufcode[2]
(ungigned char)bufcode[3]
(ungigned char)bufcode[4]
(ungigned char)bufcode[5]);
__asm{
jmp fword ptr bufcode;//
}
}
赘述不多说,运行到跳转的这一步,此时cs的值是1b
然后继续向下运行,此时CS被改了
但是随着我们继续运行,CS又被改了回来
综上所述,CPL == DPL,和RPL无关,CPU会有处理机制自动帮助我们纠错