zoukankan      html  css  js  c++  java
  • 高特权级代码段转向低特权级代码段(利用 ret(retf) 指令实现 jmp from ring0 to ring3)

    【0】写在前面

    • 0.1)本代码旨在演示 从 ring0 转移到 ring3(即,从高特权级 转移到 低特权级)
    • 0.2)本文 只对 与 门相关的 代码进行简要注释,言简意赅;
    • 0.3)文末的个人总结是干货,前面代码仅供参考的,且source code from orange’s implemention of a os.

    ; ==========================================
    ; pmtest5a.asm
    ; 编译方法:nasm pmtest5a.asm -o pmtest5a.com
    ; ==========================================
    
    %include    "pm.inc"    ; 常量, 宏, 以及一些说明
    
    org 0100h
     jmp    LABEL_BEGIN
    

    ;[SECTION .gdt]

    ; GDT
    ;                           段基址,       段界限     , 属性
    LABEL_GDT:             Descriptor 0,                0, 0         ; 空描述符
    LABEL_DESC_NORMAL:     Descriptor 0,           0ffffh, DA_DRW    ; Normal 描述符
    LABEL_DESC_CODE32:     Descriptor 0,   SegCode32Len-1, DA_C+DA_32; 非一致代码段,32
    LABEL_DESC_CODE16:     Descriptor 0,           0ffffh, DA_C      ; 非一致代码段,16
    LABEL_DESC_CODE_DEST:  Descriptor 0, SegCodeDestLen-1, DA_C+DA_32; 非一致代码段,32
    

    ; ring3的代码段描述符的定义 [add]

    LABEL_DESC_CODE_RING3: Descriptor 0,SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3
    LABEL_DESC_DATA:       Descriptor 0,        DataLen-1, DA_DRW    ; Data
    LABEL_DESC_STACK:      Descriptor 0,       TopOfStack, DA_DRWA+DA_32;Stack, 32 位
    

    ; ring3的堆栈段描述符的定义 [add]

    LABEL_DESC_STACK3:     Descriptor 0,      TopOfStack3, DA_DRWA+DA_32+DA_DPL3
    LABEL_DESC_LDT:        Descriptor 0,         LDTLen-1, DA_LDT    ; LDT
    

    ; ring3的视频段描述符的DPL属性设置为 3 [add]

    LABEL_DESC_VIDEO:      Descriptor 0B8000h,     0ffffh, DA_DRW+DA_DPL3
    
    ; 门                               目标选择子,偏移,DCount, 属性
    LABEL_CALL_GATE_TEST: Gate SelectorCodeDest,   0,     0, DA_386CGate+DA_DPL0
    ; GDT 结束
    
    GdtLen   equ    $ - LABEL_GDT  ; GDT长度
    GdtPtr   dw GdtLen - 1  ; GDT界限
      dd    0    ; GDT基地址
    
    ; GDT 选择子
    SelectorNormal   equ    LABEL_DESC_NORMAL   - LABEL_GDT
    SelectorCode32   equ    LABEL_DESC_CODE32   - LABEL_GDT
    SelectorCode16   equ    LABEL_DESC_CODE16   - LABEL_GDT
    SelectorCodeDest    equ LABEL_DESC_CODE_DEST    - LABEL_GDT
    

    ; ring3的代码段描述符的选择子定义 [add]

    SelectorCodeRing3   equ LABEL_DESC_CODE_RING3   - LABEL_GDT + SA_RPL3
    
    SelectorData     equ    LABEL_DESC_DATA  - LABEL_GDT
    SelectorStack    equ    LABEL_DESC_STACK    - LABEL_GDT
    

    ; ring3的堆栈段描述符的选择子定义 [add]

    SelectorStack3   equ    LABEL_DESC_STACK3   - LABEL_GDT + SA_RPL3
    
    SelectorLDT  equ    LABEL_DESC_LDT   - LABEL_GDT
    

    ;ring3的视频段描述符(DPL==3)的选择子定义 [add]

    SelectorVideo    equ    LABEL_DESC_VIDEO    - LABEL_GDT
    
    SelectorCallGateTest    equ LABEL_CALL_GATE_TEST    - LABEL_GDT
    ; END of [SECTION .gdt]
    

    [SECTION .data1] ; 数据段

    ALIGN   32
    [BITS   32]
    LABEL_DATA:
    SPValueInRealMode   dw  0
    ; 字符串
    PMMessage:   db "In Protect Mode now. ^-^", 0   ; 进入保护模式后显示此字符串
    OffsetPMMessage  equ    PMMessage - $$
    	StrTest:	 db	"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
    	OffsetStrTest	 equ	StrTest - $$
    DataLen  equ    $ - LABEL_DATA
    ; END of [SECTION .data1]
    

    ; 全局堆栈段
    [SECTION .gs]

    ALIGN   32
    [BITS   32]
    LABEL_STACK:
     times 512 db 0
    
    TopOfStack  equ $ - LABEL_STACK - 1
    
    ; END of [SECTION .gs]
    

    ; 堆栈段ring3的定义
    [SECTION .s3]

    ALIGN   32
    [BITS   32]
    LABEL_STACK3:
     times 512 db 0
    TopOfStack3 equ $ - LABEL_STACK3 - 1
    ; END of [SECTION .s3]
    

    [SECTION .s16]

    [BITS   16]
    LABEL_BEGIN:
     mov    ax, cs
     mov    ds, ax
     mov    es, ax
     mov    ss, ax
     mov    sp, 0100h
    
     mov    [LABEL_GO_BACK_TO_REAL+3], ax
     mov    [SPValueInRealMode], sp
    
     ; 初始化 16 位代码段描述符
     mov    ax, cs
     movzx  eax, ax
     shl    eax, 4
     add    eax, LABEL_SEG_CODE16
     mov    word [LABEL_DESC_CODE16 + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_CODE16 + 4], al
     mov    byte [LABEL_DESC_CODE16 + 7], ah
    
     ; 初始化 32 位代码段描述符
     xor    eax, eax
     mov    ax, cs
     shl    eax, 4
     add    eax, LABEL_SEG_CODE32
     mov    word [LABEL_DESC_CODE32 + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_CODE32 + 4], al
     mov    byte [LABEL_DESC_CODE32 + 7], ah
    
     ; 初始化测试调用门的代码段描述符
     xor    eax, eax
     mov    ax, cs
     shl    eax, 4
     add    eax, LABEL_SEG_CODE_DEST
     mov    word [LABEL_DESC_CODE_DEST + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_CODE_DEST + 4], al
     mov    byte [LABEL_DESC_CODE_DEST + 7], ah
    
     ; 初始化数据段描述符
     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_DATA
     mov    word [LABEL_DESC_DATA + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_DATA + 4], al
     mov    byte [LABEL_DESC_DATA + 7], ah
    
     ; 初始化堆栈段描述符
     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_STACK
     mov    word [LABEL_DESC_STACK + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_STACK + 4], al
     mov    byte [LABEL_DESC_STACK + 7], ah
    

    ; 初始化堆栈段描述符(Ring3) [add]

     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_STACK3
     mov    word [LABEL_DESC_STACK3 + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_STACK3 + 4], al
     mov    byte [LABEL_DESC_STACK3 + 7], ah
    
     ; 初始化 LDT 在 GDT 中的描述符
     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_LDT
     mov    word [LABEL_DESC_LDT + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_LDT + 4], al
     mov    byte [LABEL_DESC_LDT + 7], ah
    
     ; 初始化 LDT 中的描述符
     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_CODE_A
     mov    word [LABEL_LDT_DESC_CODEA + 2], ax
     shr    eax, 16
     mov    byte [LABEL_LDT_DESC_CODEA + 4], al
     mov    byte [LABEL_LDT_DESC_CODEA + 7], ah
    

    ; 初始化Ring3描述符 [add]

     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_CODE_RING3
     mov    word [LABEL_DESC_CODE_RING3 + 2], ax
     shr    eax, 16
     mov    byte [LABEL_DESC_CODE_RING3 + 4], al
     mov    byte [LABEL_DESC_CODE_RING3 + 7], ah
    
     ; 为加载 GDTR 作准备
     xor    eax, eax
     mov    ax, ds
     shl    eax, 4
     add    eax, LABEL_GDT   ; eax <- gdt 基地址
     mov    dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
    
     ; 加载 GDTR
     lgdt   [GdtPtr]
    
     ; 关中断
     cli
    
     ; 打开地址线A20
     in al, 92h
     or al, 00000010b
     out    92h, al
    
     ; 准备切换到保护模式
     mov    eax, cr0
     or eax, 1
     mov    cr0, eax
    
     ; 真正进入保护模式
     jmp    dword SelectorCode32:0  ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    LABEL_REAL_ENTRY:    ; 从保护模式跳回到实模式就到了这里
     mov    ax, cs
     mov    ds, ax
     mov    es, ax
     mov    ss, ax
    
     mov    sp, [SPValueInRealMode]
    
     in al, 92h  ; ┓
     and    al, 11111101b   ; ┣ 关闭 A20 地址线
     out    92h, al  ; ┛
    
     sti     ; 开中断
    
     mov    ax, 4c00h   ; ┓
     int    21h  ; ┛回到 DOS
    ; END of [SECTION .s16]
    

    [SECTION .s32]; 32 位代码段. 由实模式跳入.

    [BITS   32]
    
    LABEL_SEG_CODE32:
     mov    ax, SelectorData
     mov    ds, ax   ; 数据段选择子
     mov    ax, SelectorVideo
     mov    gs, ax   ; 视频段选择子
    
     mov    ax, SelectorStack
     mov    ss, ax   ; 堆栈段选择子
    
     mov    esp, TopOfStack
    
    
     ; 下面显示一个字符串
     mov    ah, 0Ch  ; 0000: 黑底    1100: 红字
     xor    esi, esi
     xor    edi, edi
     mov    esi, OffsetPMMessage    ; 源数据偏移
     mov    edi, (80 * 10 + 0) * 2  ; 目的数据偏移。屏幕第 10 行, 第 0 列。
     cld
    .1:
     lodsb
     test   al, al
     jz .2
     mov    [gs:edi], ax
     add    edi, 2
     jmp    .1
    .2: ; 显示完毕
    
     call   DispReturn
    

    ; ; 以下代码分步骤演示了如何将A的堆栈拷贝到B的堆栈(A==调用者,B=被调用者)
    ; 1.将ring3的堆栈段描述符的选择子压栈 [add]

     push   SelectorStack3
    

    ; 2.将ring3的堆栈压栈 [add]

     push   TopOfStack3 
    

    ; 3.将ring3的堆栈值 压栈 [add]

     push   SelectorCodeRing3
     push   0   
    

    ; 4.retf 弹出ip + 弹出cs;此时ip==0, cs==SelectorCodeRing3,然后CPU自动解析出SelectorCodeRing3 索引(定位)的段描述符, 该描述符存储有
    ; 4.ring3下代码段LABEL_CODE_RING3 的基地址, 让我们转向 代码末尾的 LABEL_CODE_RING3 代码段吧;

     retf
    
     ; 测试调用门(无特权级变换),将打印字母 'C'
     call   SelectorCallGateTest:0
     ;call  SelectorCodeDest:0
    
     ; Load LDT
     mov    ax, SelectorLDT
     lldt   ax
    
     jmp    SelectorLDTCodeA:0  ; 跳入局部任务,将打印字母 'L'。
    
    ; ------------------------------------------------------------------------
    DispReturn:
     push   eax
     push   ebx
     mov    eax, edi
     mov    bl, 160
     div    bl
     and    eax, 0FFh
     inc    eax
     mov    bl, 160
     mul    bl
     mov    edi, eax
     pop    ebx
     pop    eax
    
     ret
    ; DispReturn 结束---------------------------------------------------------
    
    SegCode32Len    equ $ - LABEL_SEG_CODE32
    ; END of [SECTION .s32]
    

    [SECTION .sdest]; 调用门目标段

    [BITS   32]
    
    LABEL_SEG_CODE_DEST:
     mov    ax, SelectorVideo
     mov    gs, ax   ; 视频段选择子(目的)
    
     mov    edi, (80 * 12 + 0) * 2  ; 屏幕第 12 行, 第 0 列。
     mov    ah, 0Ch  ; 0000: 黑底    1100: 红字
     mov    al, 'C'
     mov    [gs:edi], ax
    
     retf
    
    SegCodeDestLen  equ $ - LABEL_SEG_CODE_DEST
    ; END of [SECTION .sdest]
    

    ; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
    [SECTION .s16code]

    ALIGN   32
    [BITS   16]
    LABEL_SEG_CODE16:
     ; 跳回实模式:
     mov    ax, SelectorNormal
     mov    ds, ax
     mov    es, ax
     mov    fs, ax
     mov    gs, ax
     mov    ss, ax
    
     mov    eax, cr0
     and    al, 11111110b
     mov    cr0, eax
    
    LABEL_GO_BACK_TO_REAL:
     jmp    0:LABEL_REAL_ENTRY  ; 段地址会在程序开始处被设置成正确的值
    
    Code16Len   equ $ - LABEL_SEG_CODE16
    
    ; END of [SECTION .s16code]
    

    ; LDT
    [SECTION .ldt]

    ALIGN   32
    LABEL_LDT:
    ;                                         段基址       段界限     ,   属性
    LABEL_LDT_DESC_CODEA:   Descriptor         0,     CodeALen - 1,   DA_C + DA_32  ; Code, 32 位
    
    LDTLen   equ    $ - LABEL_LDT
    
    ; LDT 选择子
    SelectorLDTCodeA    equ LABEL_LDT_DESC_CODEA    - LABEL_LDT + SA_TIL
    ; END of [SECTION .ldt]
    

    ; CodeA (LDT, 32 位代码段)
    [SECTION .la]

    ALIGN   32
    [BITS   32]
    LABEL_CODE_A:
     mov    ax, SelectorVideo
     mov    gs, ax   ; 视频段选择子(目的)
    
     mov    edi, (80 * 13 + 0) * 2  ; 屏幕第 13 行, 第 0 列。
     mov    ah, 0Ch  ; 0000: 黑底    1100: 红字
     mov    al, 'L'
     mov    [gs:edi], ax
    
     ; 准备经由16位代码段跳回实模式
     jmp    SelectorCode16:0
    CodeALen    equ $ - LABEL_CODE_A
    ; END of [SECTION .la]
    

    ; CodeRing3的定义(ring3下的代码段)
    ; 显然, ring3 中的任务执行完后, jmp $ 这句代码使得程序 就会 永久停留在该处;

    [SECTION .ring3]
    ALIGN   32
    [BITS   32]
    LABEL_CODE_RING3:
     mov    ax, SelectorVideo
     mov    gs, ax
    
     mov    edi, (80 * 14 + 0) * 2
     mov    ah, 0Ch
     mov    al, '3'
     mov    [gs:edi], ax
    
     jmp    $
    SegCodeRing3Len equ $ - LABEL_CODE_RING3
    ; END of [SECTION .ring3]
    



    【总结-Conclusion】

    • C1)实现ring0 jmp 到ring3, 使用的是ret 指令,代码如下:(核心代码)

      ; 以下代码分步骤演示了如何将A的堆栈拷贝到B的堆栈(A==调用者,B=被调用者)
      ; 1.将ring3的堆栈段描述符的选择子压栈 [add](堆栈段描述符 存储有新堆栈的基地址ss)

      push    SelectorStack3
      

      ; 2.将ring3的堆栈压栈[add](新栈顶指针esp压栈)

      push    TopOfStack3
      

      ; 3.将ring3的堆栈值 压栈 [add] (将ring3 下的任务代码段基地址cs 压栈)

      push    SelectorCodeRing3
      ;   (偏移量ip == 0 压栈)
       push   0  
      

    ; 4.retf 弹出ip + 弹出cs;此时ip==0, cs==SelectorCodeRing3,然后CPU自动解析出SelectorCodeRing3 索引(定位)的段描述符, 该描述符存储有
    ; 4.ring3下代码段LABEL_CODE_RING3 的基地址;

     retf
    

    要知道: retf == [ pop cs, pop ip ] , ret == pop ip

    • C2)指令ret 用于执行近返回、同特权级远返回和不同特权级的远返回;
    • C2.1)近返回仅在当前代码段中转移程序控制权, 因此CPU 仅仅进行界限检查;
    • C2.2)对于同特权级远返回, CPU同时从堆栈中弹出返回代码段的选择子和返回指令指针;
    • C2.3)会发生特权级改变的远返回仅允许返回到低特权级程序中, 即返回到的代码段DPL要大于CPL;

    • 当执行远返回时, CPU执行以下步骤(也即是上述过程的第4步——指令retf):

    • 1)检查保存的cs 中的RPL 以判断返回时是否要变换特权级;
    • 2)加载被调用者堆栈上的cs 和eip;
    • 3)如果ret 指令含有参数,则增加esp 跳过参数,然后esp 将指向被保存过的调用者ss 和 esp ;ret的参数个数对应 调用门中的 Param Count的值;
    • 4)加载ss 和 esp , 切换到调用者堆栈,被调用者的ss 和 esp 被丢弃;
    • 5)如果ret 指令含有参数, 增加esp 的值以跳过参数;
    • 6)检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL 小于CPL(此规则不适用于一致代码段),那么一个空描述符会被加载到该寄存器;


      这里写图片描述
  • 相关阅读:
    CNN comprehension
    Gradient Descent
    Various Optimization Algorithms For Training Neural Network
    gerrit workflow
    jenkins job配置脚本化
    Jenkins pipeline jobs隐式传参
    make words counter for image with the help of paddlehub model
    make words counter for image with the help of paddlehub model
    git push and gerrit code review
    image similarity
  • 原文地址:https://www.cnblogs.com/pacoson/p/4893162.html
Copyright © 2011-2022 走看看