代码跨段,本质就是修改段寄存器
段寄存器有ES,CS,SS,DS,FS,GS,LDTR,TR
段寄存器读写:
除CS外,其他的段寄存器都可以通过
MOV,LES,LSS,LDS,LFS,LGS指令修改
CS为什么不能直接修改,cs的值改变意味着Eip的改变,改变cs的同时必须修改eip,所以我们无法用上面
的指令来修改
1.代码间的跳转(段间跳转吗,非调用门之类)
段间跳转,有两种情况,即要跳转的段是一致代码段还是非一致代码段(如何区分)
同时修改cs与eip的指令
jmp far/call far/retf/int/ireted
注意:
只改变eip的指令
jmp/call/jcc/ret
在各种指令中,能具有同时修改CS与EIP的指令有以下几个:
JMP FAR / CALL FAR / RETF / INT / IRETED
注意 只改变EIP的指令 JMP/CALL/JCC/RET
JMP FAR 指令格式:
JMP 0x20:0x004183D7
CPU执行该代码的流程如下:
-
-
-
执行流程:
- 段选择子拆分
- 查表得到段描述符 [仅限于 代码段,调用门,TSS任务段,任务门]
- 权限检查 {如果是非一致代码段 要求CPL == DPL 并且 RPL <= DPL}{如果是一直代码段,要求CPL>=DPL}
- 加载段描述符 通过上面的权限检查后,CPU会将段描述符加载到CS段寄存器中
- 代码执行 CPU将CS.Base + Offset 的值写入EIP 然后执行CS:EIP处的代码,段间跳转结束~
-
-
段选择子的查分:
例子 0x48 = 0000 0000 0100 1000
RPL = 0
TI = 0
Index = 9
那么就是说 我们要从GDT表中找到下标为9的段描述符~
以下是我个人的一个测试:
我先按照段描述符构结构构造出一个描述符并加载到GDT表中
00CF9F00 0000FFFF (DPL = 0 的一个一致代码段)
kd> r gdtr
gdtr=8003f000
kd> dq 8003f000
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 80008954`a1000068 80008954`a1680068
8003f060 00009302`2f30ffff 0000920b`80003fff
8003f070 ff0092ff`700003ff 80009a40`0000ffff
kd> eq 8003f048 00CFFB00`0000FFFF
kd> dq 8003f000
8003f000 00000000`00000000 00cf9b00`0000ffff
8003f010 00cf9300`0000ffff 00cffb00`0000ffff
8003f020 00cff300`0000ffff 80008b04`200020ab
8003f030 ffc093df`f0000001 0040f300`00000fff
8003f040 0000f200`0400ffff 00cf9f00`0000ffff
8003f050 80008954`a1000068 80008954`a1680068
8003f060 00009302`2f30ffff 0000920b`80003fff
8003f070 ff0092ff`700003ff 80009a40`0000ffff
我在windbug中使用指令将所构建的描述符加载到 8003f048 的一个空白地址中
再使用od 随便调试一个程序 即可测试
如图,代码正确执行
总结:
对于一致代码段:也就是共享的段
特权级别搞的程序不允许访问特权级别低的数据:核心态不允许访问用户态的数据
特权级别低的程序可以访问到特权级别高的数据,但特权级别不会改变~ 用户态还是用户态
对于普通代码段:也就是非一致代码段
只允许同级访问
绝对禁止不同级别的访问:核心态不是用户态,用户态也不是核心态
直接对代码段进行JMP或者CALL的操作,无乱目标是一直代码段还是非一致代码段,CPL都不会发生改变,如果要提升CPL的权限,只能通过调用门