zoukankan      html  css  js  c++  java
  • 17 保护模式中的特权级(下)

    参考

    https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/

    https://blog.51cto.com/13475106/category6.html

    问题:

      使用调用门如何实现不同特权级代码之间的跳转(如:从高特权级到低特权级)?

    不幸的事实:

      调用门只支持从低特权级到高特权级执行

      无法利用调用门从高特权级到低特权级执行

    从高特权级的代码段通过return  far可以返回到低特权级的代码段执行。这时return  far是一个跳转指令,完成从高特权级到低特权级的跳转,这正是我们想要的。

    return的本质是做跳转的,而不是我们根深蒂固的做返回的。只是最常用的方式是做返回使用。

    思路整理:

      调用门的特权级跳转:

        1、通过远调用(call  far),低特权级 -> 高特权级

        2、通过远返回(retf),高特权级 -> 低特权级

    retf的本质就是恢复cs和eip的值,因此,我们需要首先将cs和eip的值放入栈中。

    需要提前知道的事实:

      x86处理器对于不同的特权级需要使用不同的栈

      每一个特权级对应一个私有的栈(最多四个栈)

      特权级跳转变化之前必须指定好相应的栈

    解决方案(高特权级 -> 低特权级)

      1、指定目标栈段选择子(push)

      2、指定栈顶指针位置(push)

      3、指定目标代码段选择子(push)

      4、指定目标代码段偏移(push)

      5、跳转(retf)

    实验1:

    %include "inc.asm"
    
    org 0x9000
    
    jmp ENTRY_SEGMENT
    
    [section .gdt]
    ; GDT definition
    ;                                 段基址,       段界限,       段属性
    GDT_ENTRY       :     Descriptor    0,            0,           0
    CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32 + DA_DPL3
    VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32 + DA_DPL3
    DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32 + DA_DPL3
    STACK32_DESC    :     Descriptor    0,      TopOfStack16,    DA_DRW + DA_32 + DA_DPL3
    ; GDT end
    
    GdtLen    equ   $ - GDT_ENTRY
    
    GdtPtr:
              dw   GdtLen - 1
              dd   0
    
    
    ; GDT Selector
    
    Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL3
    VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL3
    Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL3
    Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL3
    
    ; end of [section .gdt]
    
    TopOfStack16    equ  0x7c00
    
    [section .s16]
    [bits 16]
    ENTRY_SEGMENT:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, TopOfStack16
    
        ; initialize GDT for 32 bits code segment
        mov esi, CODE32_SEGMENT
        mov edi, CODE32_DESC
    
        call InitDescItem
    
        mov esi, DATA32_SEGMENT
        mov edi, DATA32_DESC
    
        call InitDescItem
    
        mov esi, STACK32_SEGMENT
        mov edi, STACK32_DESC
    
        call InitDescItem
    
        ; initialize GDT pointer struct
        mov eax, 0
        mov ax, ds
        shl eax, 4
        add eax, GDT_ENTRY
        mov dword [GdtPtr + 2], eax
    
        ; 1. load GDT
        lgdt [GdtPtr]
    
        ; 2. close interrupt
        cli
    
        ; 3. open A20
        in al, 0x92
        or al, 00000010b
        out 0x92, al
    
        ; 4. enter protect mode
        mov eax, cr0
        or eax, 0x01
        mov cr0, eax
    
        ; 5. jump to 32 bits code
        ; jmp dword Code32Selector : 0
        push Stack32Selector    ; mu biao zhan duan xuan ze zi
        push TopOfStack32       ; zhan ding zhi zhen wei zhi
        push Code32Selector     ; mu biao dai ma duan xuan ze zi
        push 0                     ; mu bioa dai ma duan pian yi
        retf
    
    
    
    ; esi    --> code segment label
    ; edi    --> descriptor label
    InitDescItem:
        push eax
    
        mov eax, 0
        mov ax, cs
        shl eax, 4
        add eax, esi
        mov word [edi + 2], ax
        shr eax, 16
        mov byte [edi + 4], al
        mov byte [edi + 7], ah
    
        pop eax
    
        ret
    
    [section .dat]
    [bits 32]
    DATA32_SEGMENT:
        DTOS                db    "D.T.OS!",0
        DTOS_OFFSET            equ    DTOS - $$
    
    Data32SegLen    equ        $ - DATA32_SEGMENT
    
    
    [section .s32]
    [bits 32]
    CODE32_SEGMENT:
        mov ax, VideoSelector
        mov gs, ax
    
        mov ax, Data32Selector
        mov ds, ax
    
        mov ax, Stack32Selector
        mov ss, ax
    
        mov ax, Data32Selector
        mov ds, ax
    
        mov ebp, DTOS_OFFSET
        mov bx, 0x0C
        mov dh, 12
        mov dl, 33
    
        call PrintString
    
        jmp $
    
    
    ; ds:ebp   --> string address
    ; bx       --> attribute
    ; dx       --> dh : row, dl : col
    PrintString:
        push ebp
        push eax
        push edi
        push cx
        push dx
    
    print:
        mov cl, [ds:ebp]
        cmp cl, 0
        je end
        mov eax, 80
        mul dh
        add al, dl
        shl eax, 1
        mov edi, eax
        mov ah, bl
        mov al, cl
        mov [gs:edi], ax
        inc ebp
        inc dl
        jmp print
    
    end:
        pop dx
        pop cx
        pop edi
        pop eax
        pop ebp
    
        ret
    
    Code32SegLen    equ    $ - CODE32_SEGMENT
    
    [section .gs]
    [bits 32]
    STACK32_SEGMENT:
        times 1024 * 4 db 0
    
    Stack32SegLen    equ    $ - STACK32_SEGMENT
    TopOfStack32    equ    Stack32SegLen - 1
    

    11-14行我们给每一个段加上了特权级DA_DPL3,同时26-29行也必须加上DA_RPL3。85-89是我们新添加的代码,运行结果如下:

    成功的从高特权级跳到了低特权级。

     将程序改成下面的样子可以得到同样的结果:

    %include "inc.asm"
    
    org 0x9000
    
    jmp ENTRY_SEGMENT
    
    [section .gdt]
    ; GDT definition
    ;                                 段基址,       段界限,       段属性
    GDT_ENTRY       :     Descriptor    0,            0,           0
    CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32 + DA_DPL0
    VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32 + DA_DPL0
    DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32 + DA_DPL0
    STACK32_DESC    :     Descriptor    0,      TopOfStack16,    DA_DRW + DA_32 + DA_DPL0
    ; GDT end
    
    GdtLen    equ   $ - GDT_ENTRY
    
    GdtPtr:
              dw   GdtLen - 1
              dd   0
    
    
    ; GDT Selector
    
    Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
    VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
    Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
    Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
    
    ; end of [section .gdt]
    
    TopOfStack16    equ  0x7c00
    
    [section .s16]
    [bits 16]
    ENTRY_SEGMENT:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, TopOfStack16
    
        ; initialize GDT for 32 bits code segment
        mov esi, CODE32_SEGMENT
        mov edi, CODE32_DESC
    
        call InitDescItem
    
        mov esi, DATA32_SEGMENT
        mov edi, DATA32_DESC
    
        call InitDescItem
    
        mov esi, STACK32_SEGMENT
        mov edi, STACK32_DESC
    
        call InitDescItem
    
        ; initialize GDT pointer struct
        mov eax, 0
        mov ax, ds
        shl eax, 4
        add eax, GDT_ENTRY
        mov dword [GdtPtr + 2], eax
    
        ; 1. load GDT
        lgdt [GdtPtr]
    
        ; 2. close interrupt
        cli
    
        ; 3. open A20
        in al, 0x92
        or al, 00000010b
        out 0x92, al
    
        ; 4. enter protect mode
        mov eax, cr0
        or eax, 0x01
        mov cr0, eax
    
        ; 5. jump to 32 bits code
        ; jmp dword Code32Selector : 0
        ; push Stack32Selector    ; mu biao zhan duan xuan ze zi
        ; push TopOfStack32       ; zhan ding zhi zhen wei zhi
        push Code32Selector     ; mu biao dai ma duan xuan ze zi
        push 0                     ; mu bioa dai ma duan pian yi
        retf
    
    
    
    ; esi    --> code segment label
    ; edi    --> descriptor label
    InitDescItem:
        push eax
    
        mov eax, 0
        mov ax, cs
        shl eax, 4
        add eax, esi
        mov word [edi + 2], ax
        shr eax, 16
        mov byte [edi + 4], al
        mov byte [edi + 7], ah
    
        pop eax
    
        ret
    
    [section .dat]
    [bits 32]
    DATA32_SEGMENT:
        DTOS                db    "D.T.OS!",0
        DTOS_OFFSET            equ    DTOS - $$
    
    Data32SegLen    equ        $ - DATA32_SEGMENT
    
    
    [section .s32]
    [bits 32]
    CODE32_SEGMENT:
        mov ax, VideoSelector
        mov gs, ax
    
        mov ax, Data32Selector
        mov ds, ax
    
        mov ax, Stack32Selector
        mov ss, ax
    
        mov ax, Data32Selector
        mov ds, ax
    
        mov ebp, DTOS_OFFSET
        mov bx, 0x0C
        mov dh, 12
        mov dl, 33
    
        call PrintString
    
        jmp $
    
    
    ; ds:ebp   --> string address
    ; bx       --> attribute
    ; dx       --> dh : row, dl : col
    PrintString:
        push ebp
        push eax
        push edi
        push cx
        push dx
    
    print:
        mov cl, [ds:ebp]
        cmp cl, 0
        je end
        mov eax, 80
        mul dh
        add al, dl
        shl eax, 1
        mov edi, eax
        mov ah, bl
        mov al, cl
        mov [gs:edi], ax
        inc ebp
        inc dl
        jmp print
    
    end:
        pop dx
        pop cx
        pop edi
        pop eax
        pop ebp
    
        ret
    
    Code32SegLen    equ    $ - CODE32_SEGMENT
    
    [section .gs]
    [bits 32]
    STACK32_SEGMENT:
        times 1024 * 4 db 0
    
    Stack32SegLen    equ    $ - STACK32_SEGMENT
    TopOfStack32    equ    Stack32SegLen - 1
    

    这个实验告诉我们:

    1、retf就是一个跳转指令,87-89行的代码与84行是等价的。

    2、在相同的特权级之间跳转时不需要栈发生变化的。

    3、特权级改变时一定要指定栈,要不然程序就会发生崩溃

    单步实验:

     首先用ndisasm -o 0x9000 loader > loader.txt进行反汇编,找到retf的断点位置0x90A6。

    启动bochs开始执行。

    运行到0x90A6时结果如下:

    可以看到此时cs寄存器的最后两位是0,这正是默认的特权级,继续执行。

    执行了retf过后,结果如下:

    此时cs的最后一个字节为b,可以算出最后两位为11,确实跳转到了特权级为3的代码段了。

    小结:

    调用门只支持从低特权级跳转到高特权级

    利用远返回(retf)可以从高特权级转移到低特权级

    x86处理器每一个特权级对应一个私有的栈

    特权级跳转变化之前必须指定好相应的栈

    补充:关于特权级变化时,栈的保存及切换的内容,参考《x86汇编语言_从实模式到保护模式》中

              14.5.1中的完整描述。

      

      

  • 相关阅读:
    朴素贝叶斯分类算法原理
    DevExpress控件学习总结
    Nginx + Tomcat 配置负载均衡集群
    DotNet Core全新认识
    为何梯度反方向是函数值下降最快的方向
    理解矩阵
    C#版-Redis缓存服务器在Windows下的使用
    文本情感分类:分词 OR 不分词(3)
    文本情感分类:深度学习模型(2)
    文本情感分类:传统模型(1)
  • 原文地址:https://www.cnblogs.com/lh03061238/p/14131752.html
Copyright © 2011-2022 走看看