利用调用门实现特权级间跳转 — 实战篇

1. 引言

上一篇文章中,我们详细介绍了操作系统特权级,以及利用调用门、TSS 实现不同特权级之间的跳转。
利用调用门实现特权级间跳转 — 原理篇

经过上一篇文章对原理的深入剖析,我们从 Ring0 跳到 Ring3 再跳转回来的代码就已经呼之欲出了。
接下来,我们就先从此前代码中进入 Ring3,然后通过调用门,实现从 Ring3 到 Ring0 的跳转。

2. 原理回顾

这里我们再对特权级跳转的实现原理进行一个简要的介绍。

2.1. 从 Ring0 到 Ring3

毋庸置疑,操作系统是启动在最高特权级的 Ring0 下的,那么,在操作系统中如何实现从 Ring0 特权级跳转到应用程序所在的 Ring3 特权级的呢?
上一篇文章已经讲到,是通过先将目标地址对应的 cs、eip、ss、esp 四个寄存器压栈,模拟长调用,再通过长返回就可以实现到 Ring3 的跳转了。

2.2. 从 Ring3 到 Ring0

从 Ring3 特权级跳转到 Ring0 特权级,需要借助调用门,只要调用门描述符的 DPL 大于 CPL 与 RPL,就可以实现从低特权级跳转到门描述符所指定的高特权级目标代码了。
但是,在跳转的过程中,CPU 自动进行了栈空间的切换,每个特权级都必须对应不同的栈基址与栈指针,通过 TSS 来进行描述,只要在门描述符中指定参数数量,CPU 会自动完成栈切换以及在这一过程中的参数复制工作。

3. 创建 TSS

现在,我们已经有了用于 Ring0 的全局堆栈段,那么我们就可以直接创建 TSS 了。

3.1. TSS 内存结构定义

除了 0 级堆栈对应的堆栈基址、栈指针外,其他字段填写默认的 0 即可:

; ----------------------------- TSS --------------------------
[SECTION .tss]
ALIGN    32
[BITS    32]
LABEL_TSS:
        DD    0                    ; Back
        DD    TopOfStack            ; 0 级堆栈栈顶
        DD    SelectorStack        ; 0 级堆栈基址
        DD    0                    ; 1 级堆栈
        DD    0                    ; 
        DD    0                    ; 2 级堆栈
        DD    0                    ; 
        DD    0                    ; CR3
        DD    0                    ; EIP
        DD    0                    ; EFLAGS
        DD    0                    ; EAX
        DD    0                    ; ECX
        DD    0                    ; EDX
        DD    0                    ; EBX
        DD    0                    ; ESP
        DD    0                    ; EBP
        DD    0                    ; ESI
        DD    0                    ; EDI
        DD    0                    ; ES
        DD    0                    ; CS
        DD    0                    ; SS
        DD    0                    ; DS
        DD    0                    ; FS
        DD    0                    ; GS
        DD    0                    ; LDT
        DW    0                    ; 调试陷阱标志
        DW    $ - LABEL_TSS + 2    ; I/O位图基址
        DB    0ffh                ; I/O位图结束标志
TSSLen        equ    $ - LABEL_TSS

3.2. 在 GDT 中创建 TSS 对应的描述符与选择子

3.2.1. 描述符

LABEL_DESC_TSS:    Descriptor       0,         TSSLen-1, 89h        ; TSS

3.2.2. 选择子

SelectorTSS            equ    LABEL_DESC_TSS        - LABEL_GDT

3.2.3. 初始化 TSS 描述符段基址

; 初始化 TSS 描述符
xor    eax, eax
mov    ax, ds
shl    eax, 4
add    eax, LABEL_TSS
mov    word [LABEL_DESC_TSS + 2], ax
shr    eax, 16
mov    byte [LABEL_DESC_TSS + 4], al
mov    byte [LABEL_DESC_TSS + 7], ah

3.3. 加载 TSS

ltr 指令用于将 TSS 选择子载入 TSS 段寄存器 TR。

mov    ax, SelectorTSS
ltr    ax    ; 设置任务状态段寄存器 TR

4. 创建 Ring3 堆栈段

4.1. 开辟 512 字节内存空间

; Ring3 堆栈段
[SECTION .s3]
ALIGN    32
[BITS    32]
LABEL_STACK3:
    times 512 db 0
TopOfStack3    equ    $ - LABEL_STACK3 - 1

4.2. 创建描述符

在 GDT 中添加 Ring3 堆栈段描述符。

LABEL_DESC_STACK3: Descriptor 0, TopOfStack3, 4093h + 3  ; Ring3 堆栈段,DPL = 3

4.3. 创建选择子

SelectorStack3 equ LABEL_DESC_STACK3 - LABEL_GDT + 3 ; RPL = 3

4.4. 初始化 Ring3 堆栈段描述符基地址

; 初始化堆栈段描述符(ring3)
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

5. 将显示函数放入一致代码段

页面展示函数要在本次的程序中被 Ring0、Ring3 程序分别调用,最简单的方法就是让他成为 Ring0 的一致代码段。
我们做如下修改。

5.1. 创建代码段

[SECTION .display]    ; 32 位代码段. 由实模式跳入.
[BITS    32]
DISPLAY_STRING_LABEL:
    push eax
    mov    ah, 8Ch                    ; 0000: 黑底    1100: 红字
    cld
.loop_label:
    lodsb
    test al, al
    jz .over_print
    mov    [gs:edi], ax
    add    edi, 2
    jmp .loop_label

.over_print:
    pop eax
    retf
DisplayLen    equ    $ - DISPLAY_STRING_LABEL

5.2. 创建 GDT 描述符与选择子

LABEL_DESC_DISPLAY: Descriptor         0,   DisplayLen - 1, 409Ch      ; 一致代码段
SelectorDisplay        equ    LABEL_DESC_DISPLAY    - LABEL_GDT

5.3. 初始化描述符段基址

; 初始化一致代码段描述符
xor    eax, eax
mov    ax, cs
shl    eax, 4
add    eax, DISPLAY_STRING_LABEL
mov    word [LABEL_DESC_DISPLAY + 2], ax
shr    eax, 16
mov    byte [LABEL_DESC_DISPLAY + 4], al
mov    byte [LABEL_DESC_DISPLAY + 7], ah

5.4. 修改调用方式

原本的调用需要改为:

xor edi, edi
mov    edi, 80 * 2 * 2         ; 屏幕第 2 行, 第 0 列
xor esi, esi
mov esi, OffsetBootMessage
call SelectorDisplay:0

6. 编写调用门目标代码段

6.1. 目标代码编写

我们要通过调用门从 Ring3 跳转到 Ring0,然后打印一行字“Now I’m in Ring0 By CallGate”。
并从这里返回实地址模式,并退出程序。
如果我们不从这里返回实地址模式,而是返回到此前调用的 Ring3 再进行向实地址模式的跳转,就会因为 CPL 与 DPL 不同而报错:

check_cs(0x0020): non-conforming code seg descriptor dpl != cpl, dpl=0, cpl=3

[SECTION .sdest]; 调用门目标段
[BITS    32]
LABEL_SEG_CODE_DEST:
    xor edi, edi
    mov    edi, 80 * 4 * 2         ; 屏幕第 4 行, 第 0 列
    xor esi, esi
    mov esi, OffsetGateDestMessage
    call SelectorDisplay:0

    jmp SelectorCode16:0 ; 跳回实地址模式
SegCodeDestLen    equ    $ - LABEL_SEG_CODE_DEST

6.2. 在 GDT 中创建目标代码段描述符与选择子

LABEL_DESC_CODE_DEST:  Descriptor        0,  SegCodeDestLen-1, 4098h        ; 非一致代码段
SelectorCodeDest    equ    LABEL_DESC_CODE_DEST    - LABEL_GDT

6.3. 初始化描述符中目标段基址

; 初始化测试调用门的代码段描述符
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

7. 创建调用门

7.1. 创建调用门描述符宏

; ----------------- 门描述符宏 -----------------
; usage: Descriptor Base, Limit, Attr
;        Base:  dd
;        Limit: dd (low 20 bits available)
;        Attr:  dw (lower 4 bits of higher byte are always 0)
%macro Gate 4
    dw    (%2 & 0FFFFh)                        ; 偏移 1    (2 字节)
    dw    %1                                    ; 选择子    (2 字节)
    dw    (%3 & 1Fh) | ((%4 << 8) & 0FF00h)    ; 属性        (2 字节)
    dw    ((%2 >> 16) & 0FFFFh)                ; 偏移 2    (2 字节)
%endmacro ; 共 8 字节

7.2. 在 GDT 中创建门描述符与选择子

LABEL_CALL_GATE:    Gate          SelectorCodeDest,          0,      0,     0dch
SelectorCallGate    equ    LABEL_CALL_GATE    - LABEL_GDT + 3

8. 编写 Ring3 代码段

8.1. 编写 Ring3 执行代码

我们在 Ring3 代码中调用上面的显示函数,实现“Now, I’m in Ring3”字符串的打印。
为了读取到字符串,需要将全局数据段的 DPL 更改为 3,并添加对应的变量,这里就不赘述了。

[SECTION .ring3]
ALIGN    32
[BITS    32]
LABEL_CODE_RING3:
    xor edi, edi
    mov    edi, 80 * 4 * 2         ; 屏幕第 4 行, 第 0 列
    xor esi, esi
    mov esi, OffsetRing3Message
    call SelectorDisplay:0

    call    SelectorCallGate:0
SegCodeRing3Len    equ    $ - LABEL_CODE_RING3

8.2. 创建 GDT 描述符与选择子

LABEL_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1, 40e8h        ; Ring3 代码段
SelectorCodeRing3    equ    LABEL_DESC_CODE_RING3    - LABEL_GDT + 3

8.3. 初始化 GDT 描述符段基址

; 初始化Ring3描述符
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

9. 长返回 — 从 Ring0 跳转到 Ring3

做了一切准备,只剩下代码最开始进入的地方 — 如何从 Ring0 跳转到 Ring3 了。
根据上面说过的原理,只需要一个长返回即可:

push    SelectorStack3
push    TopOfStack3
push    SelectorCodeRing3
push    0
retf        ; 长返回,Ring0 -> Ring3

10. 执行结果

运行代码,可以看到:

11. 微信公众号

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤。

12. 附录 — 完整代码

; 段描述符
; usage: Descriptor Base, Limit, Attr
;        Base:  dd
;        Limit: dd (low 20 bits available)
;        Attr:  dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3
    dw    %2 & 0FFFFh                            ; 段界限 1 (2 字节)
    dw    %1 & 0FFFFh                            ; 段基址 1 (2 字节)
    db    (%1 >> 16) & 0FFh                    ; 段基址 2 (1 字节)
    dw    ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)    ; 属性 1 + 段界限 2 + 属性 2 (2 字节)
    db    (%1 >> 24) & 0FFh                    ; 段基址 3 (1 字节)
%endmacro ; 共 8 字节

; 门描述符
; usage: Gate Selector, Offset, DCount, Attr
;        Selector:  dw
;        Offset:    dd
;        DCount:    db
;        Attr:      db
%macro Gate 4
    dw    (%2 & 0FFFFh)                        ; 偏移 1 (2 字节)
    dw    %1                                    ; 选择子 (2 字节)
    dw    (%3 & 1Fh) | ((%4 << 8) & 0FF00h)    ; 属性 (2 字节)
    dw    ((%2 >> 16) & 0FFFFh)                ; 偏移 2 (2 字节)
%endmacro ; 共 8 字节

; ------------ DOS 加载初始内存地址 -----------
org    0100h
    jmp    LABEL_BEGIN

; ------------------- GDT ---------------------
[SECTION .gdt]
; GDT
;                              段基址,           段界限,        属性
LABEL_GDT:               Descriptor        0,                 0, 0            ; 空描述符
LABEL_DESC_NORMAL:     Descriptor        0,            0ffffh, 92h          ; Normal描述符
LABEL_DESC_CODE32:     Descriptor        0,    SegCode32Len-1, 4098h        ; 32 位非一致代码段
LABEL_DESC_DISPLAY:    Descriptor         0,    DisplayLen - 1, 409ch        ; 32 位一致代码段
LABEL_DESC_CODE16:     Descriptor        0,            0ffffh, 98h          ; 16 位非一致代码段
LABEL_DESC_DATA:       Descriptor        0,            DataLen-1, 0e2h         ; Ring3 数据段,DPL = 3
LABEL_DESC_STACK:      Descriptor        0,        TopOfStack, 4093h        ; 32 位全局堆栈段,可读写数据段,指针默认使用 esp
LABEL_DESC_STACK3:     Descriptor        0,       TopOfStack3, 40e3h        ; Ring3 堆栈段,DPL = 3 
LABEL_DESC_CODE_RING3: Descriptor        0, SegCodeRing3Len-1, 40e8h        ; Ring3 代码段
LABEL_DESC_CODE_DEST:  Descriptor        0,  SegCodeDestLen-1, 4098h        ; 非一致代码段
LABEL_DESC_TSS:        Descriptor        0,          TSSLen-1, 89h          ; TSS
LABEL_DESC_VIDEO:      Descriptor  0B8000h,            0ffffh, 0e2h         ; 显存首地址
LABEL_CALL_GATE: Gate SelectorCodeDest, 0, 0, 0dch ; 调用门描述符
; ------------------ END OF 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
SelectorData        equ    LABEL_DESC_DATA            - LABEL_GDT
SelectorStack3        equ    LABEL_DESC_STACK3       - LABEL_GDT + 3 ; RPL = 3
SelectorStack        equ    LABEL_DESC_STACK        - LABEL_GDT
SelectorTSS            equ    LABEL_DESC_TSS            - LABEL_GDT
SelectorCodeDest    equ    LABEL_DESC_CODE_DEST    - LABEL_GDT
SelectorVideo        equ    LABEL_DESC_VIDEO        - LABEL_GDT
SelectorDisplay        equ    LABEL_DESC_DISPLAY        - LABEL_GDT
SelectorCodeRing3    equ    LABEL_DESC_CODE_RING3    - LABEL_GDT + 3
SelectorCallGate    equ    LABEL_CALL_GATE            - LABEL_GDT + 3
; --------------- END OF 段选择子 ----------------

[SECTION .data1]     ; 数据段
ALIGN    32
[BITS    32]
LABEL_DATA:
SPValueInRealMode        dw    0
BootMessage:            db  "Hello World my OS!", 0
OffsetBootMessage        equ    BootMessage - $$
Ring3Message:           db  "Now I'm in Ring3", 0
OffsetRing3Message        equ    Ring3Message - $$
GateDestMessage:        db "Now I'm in Ring0 By CallGate", 0
OffsetGateDestMessage   equ GateDestMessage - $$
DataLen                    equ    $ - LABEL_DATA

; 全局堆栈段
[SECTION .gs]
ALIGN    32
[BITS    32]
LABEL_STACK:
    times 512 db 0
TopOfStack    equ    $ - LABEL_STACK - 1

; Ring3 堆栈段
[SECTION .s3]
ALIGN    32
[BITS    32]
LABEL_STACK3:
    times 512 db 0
TopOfStack3    equ    $ - LABEL_STACK3 - 1

; ----------------------------- TSS --------------------------
[SECTION .tss]
ALIGN    32
[BITS    32]
LABEL_TSS:
        DD    0                    ; Back
        DD    TopOfStack            ; 0 级堆栈栈顶
        DD    SelectorStack        ; 0 级堆栈基址
        DD    0                    ; 1 级堆栈
        DD    0                    ; 
        DD    0                    ; 2 级堆栈
        DD    0                    ; 
        DD    0                    ; CR3
        DD    0                    ; EIP
        DD    0                    ; EFLAGS
        DD    0                    ; EAX
        DD    0                    ; ECX
        DD    0                    ; EDX
        DD    0                    ; EBX
        DD    0                    ; ESP
        DD    0                    ; EBP
        DD    0                    ; ESI
        DD    0                    ; EDI
        DD    0                    ; ES
        DD    0                    ; CS
        DD    0                    ; SS
        DD    0                    ; DS
        DD    0                    ; FS
        DD    0                    ; GS
        DD    0                    ; LDT
        DW    0                    ; 调试陷阱标志
        DW    $ - LABEL_TSS + 2    ; I/O位图基址
        DB    0ffh                ; I/O位图结束标志
TSSLen        equ    $ - LABEL_TSS

[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

    ; 初始化非一致代码段描述符
    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, DISPLAY_STRING_LABEL
    mov    word [LABEL_DESC_DISPLAY + 2], ax
    shr    eax, 16
    mov    byte [LABEL_DESC_DISPLAY + 4], al
    mov    byte [LABEL_DESC_DISPLAY + 7], ah

    ; 初始化Ring3描述符
    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

    ; 初始化测试调用门的代码段描述符
    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)
    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

    ; 初始化 TSS 描述符
    xor    eax, eax
    mov    ax, ds
    shl    eax, 4
    add    eax, LABEL_TSS
    mov    word [LABEL_DESC_TSS + 2], ax
    shr    eax, 16
    mov    byte [LABEL_DESC_TSS + 4], al
    mov    byte [LABEL_DESC_TSS + 7], ah

    ; 准备加载 GDTR
    xor    eax, eax                ; 清空 eax 寄存器
    mov    ax, ds
    shl    eax, 4
    add    eax, LABEL_GDT            ; 计算出 GDT 基地址的物理地址
    mov    dword [GdtPtr + 2], eax    ; [GdtPtr + 2] <- gdt 基地址

    ; 加载 GDTR
    lgdt    [GdtPtr]

    ; 关闭硬件中断
    cli

    ; 打开 A20 地址总线
    in    al, 92h
    or    al, 00000010b
    out    92h, al

    ; 置位 PE 标志位,打开保护模式
    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]

    ; 关闭 A20 地址线
    in    al, 92h
    and    al, 0fdh
    out    92h, al

    ; 打开硬件中断
    sti

    ; 触发 BIOS int 21h 中断,回到实地址模式
    mov    ax, 4c00h
    int    21h

[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

    xor edi, edi
    mov    edi, 80 * 2 * 2         ; 屏幕第 2 行, 第 0 列
    xor esi, esi
    mov esi, OffsetBootMessage
    call SelectorDisplay:0

    ; Load TSS
    mov    ax, SelectorTSS
    ltr    ax    ; 设置任务状态段寄存器 TR

    push    SelectorStack3
    push    TopOfStack3
    push    SelectorCodeRing3
    push    0
    retf        ; 长返回,Ring0 -> Ring3
SegCode32Len        equ    $ - LABEL_SEG_CODE32

[SECTION .display]
[BITS    32]
DISPLAY_STRING_LABEL:
    ; mov    ax, SelectorVideo
    ; mov    gs, ax            ; 视频段选择子(目的)

    push eax
    mov    ah, 8Ch                    ; 0000: 黑底    1100: 红字
    cld
.loop_label:
    lodsb
    test al, al
    jz .over_print
    mov    [gs:edi], ax
    add    edi, 2
    jmp .loop_label

.over_print:
    pop eax
    retf
DisplayLen    equ    $ - DISPLAY_STRING_LABEL

; 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, 0feh
    mov    cr0, eax

LABEL_GO_BACK_TO_REAL:
    jmp word 0:LABEL_REAL_ENTRY    ; 段地址会在程序开始处被设置成正确的值

Code16Len    equ    $ - LABEL_SEG_CODE16
; END of [SECTION .s16code]

[SECTION .ring3]
ALIGN    32
[BITS    32]
LABEL_CODE_RING3:
    xor edi, edi
    mov    edi, 80 * 3 * 2         ; 屏幕第 3 行, 第 0 列
    xor esi, esi
    mov esi, OffsetRing3Message
    call SelectorDisplay:0
    call SelectorCallGate:0
SegCodeRing3Len    equ    $ - LABEL_CODE_RING3

[SECTION .sdest]; 调用门目标段
[BITS    32]
LABEL_SEG_CODE_DEST:
    xor edi, edi
    mov    edi, 80 * 4 * 2         ; 屏幕第 4 行, 第 0 列
    xor esi, esi
    mov esi, OffsetGateDestMessage
    call SelectorDisplay:0

    jmp SelectorCode16:0 ; 跳回实地址模式
SegCodeDestLen    equ    $ - LABEL_SEG_CODE_DEST

阅读原文

利用调用门实现特权级间跳转 — 实战篇》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.bookhoes.com/2120.html