目标:进入ring3
代码:pmtest5a.asm
原理:通过ret指令由高特权级转移到ring3级。注意我们的程序刚开始是运行在ring0级。
ring3是低特权级,需要通过ret命令进入。
1.因为我们要进入ring3,所以要添加一个ring3的代码段和ring3堆栈段
LABEL_DESC_CODE_RING3: Descriptor 0,SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3
LABEL_DESC_STACK3: Descriptor 0, TopOfStack3, DA_DRWA+DA_32+DA_DPL3
DPL3表明该段是ring3
2.定义段的选择子
SelectorCodeRing3 equ LABEL_DESC_CODE_RING3 - LABEL_GDT + SA_RPL3 ;=0x28+3=0x2b
SelectorStack3 equ LABEL_DESC_STACK3 - LABEL_GDT + SA_RPL3 ;=0x40+3=0x43
3.段初始化
; 初始化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
; 初始化堆栈段描述符(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
4.定义堆栈段 ring3
[SECTION .s3]
ALIGN 32
[BITS 32]
LABEL_STACK3:
times 512 db 0
TopOfStack3 equ $ - LABEL_STACK3 - 1
5.定义代码段 ring3
[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
6.修改VIDEO段属性
由于ring3要写显存而访问VIDEO段,所以需要把他的DPL改为3
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW+DA_DPL3
7.进入ring3
push SelectorStack3
push TopOfStack3
push SelectorCodeRing3
push 0
retf ;完成进入ring3的工作
8.bochs上运行pmtest5a
(0) [0x000000000003298a] 0010:0000003e (unk. ctxt): push 0x00000043 ; 6843000000
(0) [0x000000000003298f] 0010:00000043 (unk. ctxt): push 0x000001ff ; 68ff010000
(0) [0x0000000000032994] 0010:00000048 (unk. ctxt): push 0x0000002b ; 682b000000
(0) [0x0000000000032999] 0010:0000004d (unk. ctxt): push 0x00000000 ; 6800000000
push执行前
ss:0x0038, dh=0x00409303, dl=0x23e801ff, valid=7
Data segment, base=0x000323e8, limit=0x000001ff, Read/Write, Accessed
esp: 0x000001ff
| STACK 0x000325e7 [0x00000000]
| STACK 0x000325eb [0x00000000]
| STACK 0x000325ef [0x00000000]
| STACK 0x000325f3 [0x00000000]
| STACK 0x000325f7 [0x00000000]
| STACK 0x000325fb [0x00000000]
push执行后
ss:0x0038, dh=0x00409303, dl=0x23e801ff, valid=7
Data segment, base=0x000323e8, limit=0x000001ff, Read/Write, Accessed
esp: 0x000001ef
| STACK 0x000325d7 [0x00000000]
| STACK 0x000325db [0x0000002b]
| STACK 0x000325df [0x000001ff]
| STACK 0x000325e3 [0x00000043]
| STACK 0x000325e7 [0x00000000]
| STACK 0x000325eb [0x00000000]
此时的
cs:0x0010, dh=0x00409903, dl=0x294c007e, valid=1
Code segment, base=0x0003294c, limit=0x0000007e, Execute-Only, Accessed, 32-bit
下面看看ret之后的变化
(0) [0x000000000003299e] 0010:00000052 (unk. ctxt): retf ; cb
cs:0x002b, dh=0x0040f903, dl=0x2a200014, valid=1
Code segment, base=0x00032a20, limit=0x00000014, Execute-Only, Accessed, 32-bit
ss:0x0043, dh=0x0040f303, dl=0x25e801ff, valid=1
Data segment, base=0x000325e8, limit=0x000001ff, Read/Write, Accessed
esp: 0x000001ff 511 ;栈的大小事512,所以esp=0x1ff
| STACK 0x000327e7 [0x8ec88c00]
| STACK 0x000327eb [0x8ec08ed8]
| STACK 0x000327ef [0x0100bcd0]
| STACK 0x000327f3 [0x8907b8a3]
| STACK 0x000327f7 [0x8c017026]
| STACK 0x000327fb [0xb70f66c8]
我们看到retf执行后,cs和ss发生了变化,他们的值变成了ring3选择子的值。