首页
社区
课程
招聘
[求助]CPL,RPL.DPL问题
发表于: 2018-1-3 17:48 3736

[求助]CPL,RPL.DPL问题

2018-1-3 17:48
3736
为什么  直接转移(far call 及 far jmp)后,无论是一致码段还是非一致码段当前特权级都不发生改变?
当前cs中的内容是xxxxxxxxxxxxxx11
执行完后要放入cs中的内容是 xxxxxxxxxxxxxx00
执行后cs中的内容是 xxxxxxxxxxxxxx00
如果这样成功,CPL不就是00了吗,为什么说当前特权级不发生改变,还是这样的情况就不会出现.
还是只把选择子中的前14位复制到cs寄存器


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (11)
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这个问题一直纠结了我很久,曾经学习到此差点噶然止步~不过看了Intel的手册之后,就恍然大悟了。

原因很简单,也很操逼~那就是:Intel就是这么设计的。。。。。。
2018-1-3 19:13
0
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
;转移至一致代码段
       CONFORMING-CODE-SEGMENT:
               
               ;检查1:
               ;如果段描述符的L位=1、D位=1、长模式处于开启激活状态
               ;L位=1表示这个一个64代码段
               ;D位=1表示默认32位偏移地址或者操作数
               ;IA32_EFER.LMA=1表示长模式处于激活状态
               ;如果上述三种条件成立,则终止当前操作,获取新的代码段选择子。
               IF 
                       L-Bit  =  1  and  D-BIT  =  1  and  IA32_EFER.LMA  =  1
               THEN 
                       GP(new  code  segment  selector)
               ;  FI;
               
               ;检查2:
               ;如果指令的当前特权级CPL小于读取的段描述符的DPL
               ;表明当前特权级高于要访问的段特权级
               ;引发异常。
               IF 
                       DPL  >  CPL
               THEN 
                       #GP(segment  selector)
               ;  FI;
               
               ;检查3:
               ;如果要访问的段不存在
               ;引发异常
               IF 
                       segment  not  present
               THEN 
                       #NP(segment  selector)
               ;  FI;
               
               ;上述所有检查都通过后,
               ;将目标操作数的偏移地址(偏移量)给临时EIP。
               tempEIP  ←  DEST(Offset);
               
               ;如果操作数类型是16位的,
               ;则将32位临时偏移量的高16位清零
               IF 
                       OperandSize  =  16
               THEN 
                       tempEIP  ←  tempEIP  AND  0000FFFFH
               ;FI;
               
               ;如果临时EIP数值超过代码段的界限
               ;并且长模式未激活、目标模式为兼容模式这两个条件有一个成立
               ;引发异常
               IF 
                       (IA32_EFER.LMA  =  0  or  target  mode  =  Compatibility  mode)  and  tempEIP  outside  code  segment  limit
               THEN 
                       #GP(0)
               ;  FI
               
               ;如果临时EIP数值不规范
               ;引发异常
               IF 
                       tempEIP  is  non-canonical
               THEN 
                       #GP(0)
               ;  FI;
               
               ;当上述检查全部通过
               ;则将目标段选择子加载到CS段选择器
               ;段描述符的信息也加载到CS段选择器的不可见部分
               ;将当前指令的特权级数值写入CS段选择器的RPL部分
               ;将临时EIP数值传送给真正的EIP寄存器
               ;指令从新的CS:EIP处开始执行。
               ;第155行,可以看到跳转后的CPL仍是跳转前的CPL。
               CS  ←  DEST[segment  selector];  (*  Segment  descriptor  information  also  loaded  *)
               CS(RPL)  ←  CPL
               EIP  ←  tempEIP;
       END;
上面是JMP语句跳转一致代码的逻辑过程说明,倒数第3行,处理器用当前特权级CPL刷新了CS中的RPL值。
2018-1-3 19:15
0
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
;跳转到非一致代码段
       NONCONFORMING-CODE-SEGMENT:
               
               ;检查1:
               ;如果段描述符的L位=1、D位=1、长模式处于开启激活状态
               ;L位=1表示这个一个64代码段
               ;D位=1表示默认32位偏移地址或者操作数
               ;IA32_EFER.LMA=1表示长模式处于激活状态
               ;如果上述三种条件成立,则终止当前操作,获取新的代码段选择子。
               IF 
                       L-Bit  =  1  and  D-BIT  =  1  and  IA32_EFER.LMA  =  1
               THEN 
                       GP(new  code  segment  selector);  FI;
               
               ;检查2:
               ;如果条件1:指令的当前特权级CPL小于段选择子的请求特权级(说明请求权限不够)
               ;或者条件2:当前特权级CPL不等于目标段描述符特权级DPL(非一致代码段只能同特权级访问,否则不能访问)
               ;条件1、条件2有1个成立,则会引发异常。
               IF 
                       (RPL  >  CPL)  OR  (DPL  ≠  CPL)
               THEN 
                       #GP(code  segment  selector);  FI;
               
               ;检查3:
               ;如果要访问的段不存在
               ;引发异常
               IF 
                       segment  not  present
               THEN 
                       #NP(segment  selector);  FI;
               
               ;上述所有检查都通过后,
               ;将目标操作数的偏移地址(偏移量)给临时EIP。
               tempEIP  ←  DEST(Offset);
               
               ;如果操作数类型是16位的,
               ;则将32位临时偏移量的高16位清零
               IF 
                       OperandSize  =  16
               THEN 
                       tempEIP  ←  tempEIP  AND  0000FFFFH;  FI;
               
               ;如果临时EIP数值超过代码段的界限
               ;并且长模式未激活、目标模式为兼容模式这两个条件有一个成立
               ;引发异常
               IF 
                       (IA32_EFER.LMA  =  0  OR  target  mode  =  Compatibility  mode)and  tempEIP  outside  code  segment  limit
               THEN 
                       #GP(0);  FI
               
               ;如果临时EIP数值不规范
               ;引发异常
               IF 
                       tempEIP  is  non-canonical 
               THEN 
                       #GP(0);  FI;
               
               ;当上述检查全部通过
               ;则将目标段选择子加载到CS段选择器,段描述符的信息也加载到CS段选择器的不可见部分
               ;将当前指令的特权级数值写入CS段选择器的RPL部分
               ;将临时EIP数值传送给真正的EIP寄存器
               ;指令从新的CS:EIP处开始执行。
               ;第223行,可以看到跳转后的CPL仍是跳转前的CPL。
               CS  ←  DEST[segment  selector];  (*  Segment  descriptor  information  also  loaded  *)
               CS(RPL)  ←  CPL;
               EIP  ←  tempEIP;
       END;
上面是JMP语句跳转非一致代码的逻辑过程说明,倒数第3行,处理器同样用当前特权级CPL刷新了CS中的RPL值。
2018-1-3 19:16
0
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
IF  far  call  and  (PE  =  1  and  VM  =  0)  (*  Protected  mode  or  IA-32e  Mode,  not  virtual-8086  mode*)
       THEN
               IF  segment  selector  in  target  operand  NULL
               THEN  #GP(0);  FI;
               
               IF  segment  selector  index  not  within  descriptor  table  limits
               THEN  #GP(new  code  segment  selector);  FI;
               
               Read  type  and  access  rights  of  selected  segment  descriptor;

               IF  IA32_EFER.LMA  =  0
               THEN
                       IF  segment  type  is  not  a  conforming        or  nonconforming  code  segment,  call  gate,  task  gate,  or  TSS
                       THEN  #GP(segment  selector);  FI;
               ELSE
                       IF  segment  type  is  not  a  conforming  or  nonconforming  code  segment  or  64-bit  call  gate,
                       THEN  #GP(segment  selector);  FI;
               FI;

               Depending  on  type  and  access  rights:
               GO  TO  CONFORMING-CODE-SEGMENT;
               GO  TO  NONCONFORMING-CODE-SEGMENT;
               GO  TO  CALL-GATE;
               GO  TO  TASK-GATE;
               GO  TO  TASK-STATE-SEGMENT;
       FI;
   
    CONFORMING-CODE-SEGMENT:
        IF  L  bit  =  1  and  D  bit  =  1  and  IA32_EFER.LMA  =  1
            THEN  GP(new  code  segment  selector);  FI;
       
       IF  DPL  >  CPL
            THEN  #GP(new  code  segment  selector);  FI;

       IF  segment  not  present
            THEN  #NP(new  code  segment  selector);  FI;
       
       IF  stack  not  large  enough  for  return  address
            THEN  #SS(0);  FI;
       
       tempEIP  ←  DEST(Offset);
       
       IF  OperandSize  =  16
            THEN
                tempEIP  ←  tempEIP  AND  0000FFFFH;  FI;  (*  Clear  upper  16  bits  *)
       
       IF  (EFER.LMA  =  0  or  target  mode  =  Compatibility  mode)  and  (tempEIP  outside  new  code  segment  limit)
            THEN  #GP(0);  FI;

       IF  tempEIP  is  non-canonical
            THEN  #GP(0);  FI;
       
       IF  OperandSize  =  32
            THEN
                Push(CS);  (*  Padded  with  16  high-order  bits  *)
                Push(EIP);
                CS  ←  DEST(CodeSegmentSelector);
                (*  Segment  descriptor  information  also  loaded  *)
                CS(RPL)  ←  CPL;
                EIP  ←  tempEIP;
            ELSE
                IF  OperandSize  =  16
                    THEN
                        Push(CS);
                        Push(IP);
                        CS  ←  DEST(CodeSegmentSelector);
                        (*  Segment  descriptor  information  also  loaded  *)
                        CS(RPL)  ←  CPL;
                        EIP  ←  tempEIP;
                    ELSE  (*  OperandSize  =  64  *)
                        Push(CS);  (*  Padded  with  48  high-order  bits  *)
                        Push(RIP);
                        CS  ←  DEST(CodeSegmentSelector);
                        (*  Segment  descriptor  information  also  loaded  *)
                        CS(RPL)  ←  CPL;
                        RIP  ←  tempEIP;
                FI;
        FI;
    END;
       
    NONCONFORMING-CODE-SEGMENT:
       IF  L-Bit  =  1  and  D-BIT  =  1  and  IA32_EFER.LMA  =  1
           THEN  GP(new  code  segment  selector);  FI;
       
       IF  (RPL  >  CPL)  or  (DPL  ≠  CPL)
           THEN  #GP(new  code  segment  selector);  FI;
       
       IF  segment  not  present
           THEN  #NP(new  code  segment  selector);  FI;

       IF  stack  not  large  enough  for  return  address
           THEN  #SS(0);  FI;

       tempEIP  ←  DEST(Offset);

       IF  OperandSize  =  16
           THEN  tempEIP  ←  tempEIP  AND  0000FFFFH;  FI;  (*  Clear  upper  16  bits  *)

       IF  (EFER.LMA  =  0  or  target  mode  =  Compatibility  mode)  and  (tempEIP  outside  new  code  segment  limit)
           THEN  #GP(0);  FI;

       IF  tempEIP  is  non-canonical
           THEN  #GP(0);  FI;
       
       IF  OperandSize  =  32
           THEN
               Push(CS);  (*  Padded  with  16  high-order  bits  *)
               Push(EIP);
               CS  ←  DEST(CodeSegmentSelector);
               (*  Segment  descriptor  information  also  loaded  *)
               CS(RPL)  ←  CPL;
               EIP  ←  tempEIP;
           ELSE        
               IF  OperandSize  =  16
                   THEN
                       Push(CS);
                       Push(IP);
                       CS  ←  DEST(CodeSegmentSelector);
                       (*  Segment  descriptor  information  also  loaded  *)
                       CS(RPL)  ←  CPL;
                       EIP  ←  tempEIP;
                   ELSE  (*  OperandSize  =  64  *)
                       Push(CS);  (*  Padded  with  48  high-order  bits  *)
                       Push(RIP);
                       CS  ←  DEST(CodeSegmentSelector);
                       (*  Segment  descriptor  information  also  loaded  *)
                       CS(RPL)  ←  CPL;
                       RIP  ←  tempEIP;
               FI;
       FI;
    END;
上面是CALL跳转到一致代码和非一致代码的逻辑说明。同样都是用当前特权级CPL刷新了CS寄存器中最低2位RPL的值。
2018-1-3 19:18
0
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
下面是CALL通过调用门提权的逻辑过程,这个就是真正提升了当前特权级。
CALL-GATE:
        IF  call  gate  (DPL  <  CPL)  or  (RPL  >  DPL)
            THEN  #GP(call-gate  selector);  FI;
       
       IF  call  gate  not  present
            THEN  #NP(call-gate  selector);  FI;
       
       IF  call-gate  code-segment  selector  is  NULL
            THEN  #GP(0);  FI;
       
       IF  call-gate  code-segment  selector  index  is  outside  descriptor  table  limits
            THEN  #GP(call-gate  code-segment  selector);  FI;
       
       Read  call-gate  code-segment  descriptor;
       
       IF  call-gate  code-segment  descriptor  does  not  indicate  a  code  segment
              or  call-gate  code-segment  descriptor  DPL  >  CPL
            THEN  #GP(call-gate  code-segment  selector);  FI;
       
       IF  IA32_EFER.LMA  =  1  AND  (call-gate  code-segment  descriptor  is
              not  a  64-bit  code  segment  or  call-gate  code-segment  descriptor  has  both  L-bit  and  D-bit  set)
            THEN  #GP(call-gate  code-segment  selector);  FI;
       
       IF  call-gate  code  segment  not  present
            THEN  #NP(call-gate  code-segment  selector);  FI;
       
       IF  call-gate  code  segment  is  non-conforming  and  DPL  <  CPL
            THEN  go  to  MORE-PRIVILEGE;
            ELSE  go  to  SAME-PRIVILEGE;
        FI;
    END;
   
   
    MORE-PRIVILEGE:
        IF  current  TSS  is  32-bit
            THEN
                TSSstackAddress  ←  (new  code-segment  DPL*8)  +  4;
                IF  (TSSstackAddress  +  5)  >  current  TSS  limit
                    THEN  #TS(current  TSS  selector);  FI;
                NewSS  ←  2  bytes  loaded  from  (TSS  base  +  TSSstackAddress  +  4);
                NewESP  ←  4  bytes  loaded  from  (TSS  base  +  TSSstackAddress);
            ELSE
                IF  current  TSS  is  16-bit
                    THEN
                        TSSstackAddress  ←  (new  code-segment  DPL*4)  +  2
                        IF  (TSSstackAddress  +  3)  >  current  TSS  limit
                            THEN  #TS(current  TSS  selector);  FI;
                        NewSS  ←  2  bytes  loaded  from  (TSS  base  +  TSSstackAddress  +  2);
                        NewESP  ←  2  bytes  loaded  from  (TSS  base  +  TSSstackAddress);
                    ELSE  (*  current  TSS  is  64-bit  *)
                        TSSstackAddress  ←  (new  code-segment  DPL*8)  +  4;
                        IF  (TSSstackAddress  +  7)  >  current  TSS  limit
                            THEN  #TS(current  TSS  selector);  FI;
                        NewSS  ←  new  code-segment  DPL;  (*  NULL  selector  with  RPL  =  new  CPL  *)
                        NewRSP  ←  8  bytes  loaded  from  (current  TSS  base  +  TSSstackAddress);
                FI;
        FI;
        IF  IA32_EFER.LMA  =  0  and  NewSS  is  NULL
            THEN  #TS(NewSS);  FI;
        Read  new  code-segment  descriptor  and  new  stack-segment  descriptor;
        IF  IA32_EFER.LMA  =  0  and 
             (NewSS  RPL  ≠  new  code-segment  DPL  or 
             new  stack-segment  DPL  ≠  new  code-segment  DPL  or 
             new  stack  segment  is  not  a  writable  data  segment)
            THEN  #TS(NewSS);  FI
        IF  IA32_EFER.LMA  =  0  and  new  stack  segment  not  present
            THEN  #SS(NewSS);  FI;
        IF  CallGateSize  =  32
            THEN
                IF  new  stack  does  not  have  room  for  parameters  plus  16  bytes
                    THEN  #SS(NewSS);  FI;
                IF  CallGate(InstructionPointer)  not  within  new  code-segment  limit
                    THEN  #GP(0);  FI;
                SS  ←  newSS;  (*  Segment  descriptor  information  also  loaded  *)
                ESP  ←  newESP;
                CS:EIP  ←  CallGate(CS:InstructionPointer);
                (*  Segment  descriptor  information  also  loaded  *)
                Push(oldSS:oldESP);  (*  From  calling  procedure  *)
                temp  ←  parameter  count  from  call  gate,  masked  to  5  bits;
                Push(parameters  from  calling  procedure’s  stack,  temp)
                Push(oldCS:oldEIP);  (*  Return  address  to  calling  procedure  *)
            ELSE
                IF  CallGateSize  =  16
                    THEN
                        IF  new  stack  does  not  have  room  for  parameters  plus  8  bytes
                            THEN  #SS(NewSS);  FI;
                        IF  (CallGate(InstructionPointer)  AND  FFFFH)  not  in  new  code-segment  limit
                            THEN  #GP(0);  FI;
                        SS  ←  newSS;  (*  Segment  descriptor  information  also  loaded  *)
                        ESP  ←  newESP;
                        CS:IP  ←  CallGate(CS:InstructionPointer);
                        (*  Segment  descriptor  information  also  loaded  *)
                        Push(oldSS:oldESP);  (*  From  calling  procedure  *)
                        temp  ←  parameter  count  from  call  gate,  masked  to  5  bits;
                        Push(parameters  from  calling  procedure’s  stack,  temp)
                        Push(oldCS:oldEIP);  (*  Return  address  to  calling  procedure  *)
                    ELSE  (*  CallGateSize  =  64  *)
                        IF  pushing  32  bytes  on  the  stack  would  use  a  non-canonical  address
                            THEN  #SS(NewSS);  FI;
                        IF  (CallGate(InstructionPointer)  is  non-canonical)
                            THEN  #GP(0);  FI;
                        SS  ←  NewSS;  (*  NewSS  is  NULL)
                        RSP  ←  NewESP;
                        CS:IP  ←  CallGate(CS:InstructionPointer);
                        (*  Segment  descriptor  information  also  loaded  *)
                        Push(oldSS:oldESP);  (*  From  calling  procedure  *)
                        Push(oldCS:oldEIP);  (*  Return  address  to  calling  procedure  *)
                FI;
        FI;
        CPL  ←  CodeSegment(DPL)
        CS(RPL)  ←  CPL
END;
上面代码倒数第3行,处理器将目标代码段描述符的DPL给了CPL,并用这个CPL刷新了CS的最低2位RPL的值,也就是说,当前特权级真正到了目标代码特权级。这是所有的跳转里面唯一提升了当前特权级的。
当然,CALL通过调用门同样也可以不提升特权级,下面就是CALL通过调用门,但不提升当前特权级。
SAME-PRIVILEGE:
        IF  CallGateSize  =  32
            THEN
                IF  stack  does  not  have  room  for  8  bytes
                    THEN  #SS(0);  FI;
                IF  CallGate(InstructionPointer)  not  within  code  segment  limit
                    THEN  #GP(0);  FI;
                CS:EIP  ←  CallGate(CS:EIP)  (*  Segment  descriptor  information  also  loaded  *)
                Push(oldCS:oldEIP);  (*  Return  address  to  calling  procedure  *)
            ELSE
                If  CallGateSize  =  16
                    THEN
                        IF  stack  does  not  have  room  for  4  bytes
                            THEN  #SS(0);  FI;
                        IF  CallGate(InstructionPointer)  not  within  code  segment  limit
                            THEN  #GP(0);  FI;
                        CS:IP  ←  CallGate(CS:instruction  pointer);
                        (*  Segment  descriptor  information  also  loaded  *)
                        Push(oldCS:oldIP);  (*  Return  address  to  calling  procedure  *)
                    ELSE  (*  CallGateSize  =  64)
                        IF  pushing  16  bytes  on  the  stack  touches  non-canonical  addresses
                            THEN  #SS(0);  FI;
                        IF  RIP  non-canonical
                            THEN  #GP(0);  FI;
                        CS:IP  ←  CallGate(CS:instruction  pointer);
                        (*  Segment  descriptor  information  also  loaded  *)
                        Push(oldCS:oldIP);  (*  Return  address  to  calling  procedure  *)
                FI;
        FI;
        CS(RPL)  ←  CPL
    END;
倒数第2行,处理器还是用当前特权级(也就是旧特权级,因为此时还处于跳转过程处理,并未到目标代码段)刷新了CS中的RPL值。
2018-1-3 19:22
0
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
前面几个回复的帖子中有关逻辑过程说明的部分中文解释是我自己翻译的,并不是那种公开出版的标准翻译,如果有错误,请忽略。
2018-1-3 19:24
0
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
CALL指令的逻辑过程懒得翻译了,毕竟还是很容易看懂的~
2018-1-3 19:29
0
雪    币: 68
活跃值: (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
2018-1-31 00:20
0
雪    币: 68
活跃值: (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
2018-1-31 00:24
0
雪    币: 68
活跃值: (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
还有Call  任务门。。等等,待更新
2018-1-31 00:26
0
雪    币: 719
活跃值: (777)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
12
mark
2018-1-31 04:22
0
游客
登录 | 注册 方可回帖
返回
//