调用门实战(4)----特权级转移实践

本次实践从ring0进入ring3然后又回到ring0,运行结果如下图:

 

 

具体步骤如下:

1、进入ring3

在前面的理论篇中,我们知道可以用ret指令跳转到目标代码段。这个例子中,在ret前的堆栈如下图:

 

调用门实战(4)----特权级转移实践_第1张图片

 

我们要添加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

 

选择子:

SelectorCodeRing3 equ LABEL_DESC_CODE_RING3- LABEL_GDT+SA_RPL3 SelectorStack3 equ LABEL_DESC_STACK3 - LABEL_GDT+SA_RPL3

 

ring3堆栈段:

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

 

ring3代码段:

;代码段ring3 [SECTION .ring3] ALIGN 32 [BITS 32] LABEL_CODE_RING3: mov ax,SelectorVideo mov gs,ax mov edi,(80*16+0)*2 mov ah, 0Ch ;0000:黑底 1100:红字 mov al, 'R' mov [gs:edi],ax add edi,2 mov al, 'I' mov [gs:edi],ax add edi,2 mov al, 'N' mov [gs:edi],ax add edi,2 mov al, 'G' mov [gs:edi],ax add edi,2 mov al, '3' mov [gs:edi],ax call SelectorCallGateTest:0 ;jmp $ SegCodeRing3Len equ $-LABEL_CODE_RING3 ret指令跳入ring3: push SelectorStack3 push TopOfStack3 push SelectorCodeRing3 push 0 retf

 

ring3代码要写显存访问到video段,把video段的DPL改写为3:

LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW+DA_DPL3 ;显存地址

 

2、进入ring3代码后,使用调用门跳回ring0

修改调用门描述符和选择子的DPL和RPL,修改描述符和选择子满足CPL和RPL小于等于调用门DPL的条件

LABEL_CALL_GATE_TEST: Gate SelectorCodeCallGate ,0 ,0 ,DA_386CGate+DA_DPL3 SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT+SA_RPL3

 

从低特权级到高特权级需要添加TSS段:

LABEL_DESC_TSS: Descriptor 0, TSSLen-1, DA_386TSS ;TSS段 SelectorTSS equ LABEL_DESC_TSS - LABEL_GDT

 

在特权级变换之前加载TSS:

mov ax,SelectorTSS ltr ax ;在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。

 

定义TSS结构如下,本例只用到0级堆栈。

[SECTION .tss] ALIGN 32 [BITS 32] LABEL_TSS: DD 0 ; Back DD TopOfStack ; 0级堆栈 DD SelectorStack ; 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

 

 

===============================================================================

完整代码如下:

pm.inc代码:

; usage: Descriptor Base, Limit, Attr ; Base: dd (32 bits 段基址) ; Limit: dd (low 20 bits available,20 bits 段界限) ; Attr: dw (lower 4 bits of higher byte are always 0) %macro Descriptor 3 dw %2 & 0FFFFh ; 段界限1 dw %1 & 0FFFFh ; 段基址1 db (%1 >> 16) & 0FFh ; 段基址2 dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性1 + 段界限2 + 属性2 db (%1 >> 24) & 0FFh ; 段基址3 %endmacro ; 共 8 字节 ; 描述符类型 DA_32 EQU 4000h ; 32 位段 DA_DPL0 EQU 00h ; DPL = 0 DA_DPL1 EQU 20h ; DPL = 1 DA_DPL2 EQU 40h ; DPL = 2 DA_DPL3 EQU 60h ; DPL = 3 ; 存储段描述符类型 DA_DR EQU 90h ; 存在的只读数据段类型值 DA_DRW EQU 92h ; 存在的可读写数据段属性值 DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值 DA_C EQU 98h ; 存在的只执行代码段属性值 DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值 DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值 DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值 ; 系统段描述符类型 DA_LDT EQU 82h ; 局部描述符表段类型值 DA_TaskGate EQU 85h ; 任务门类型值 DA_386TSS EQU 89h ; 可用 386 任务状态段类型值 DA_386CGate EQU 8Ch ; 386 调用门类型值 DA_386IGate EQU 8Eh ; 386 中断门类型值 DA_386TGate EQU 8Fh ; 386 陷阱门类型值 SA_RPL0 EQU 0 ; ┓ SA_RPL1 EQU 1 ; ┣ RPL SA_RPL2 EQU 2 ; ┃ SA_RPL3 EQU 3 ; ┛ SA_TIG EQU 0 ; ┓TI SA_TIL EQU 4 ; ┛ ; 门 ; 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 字节

 

pmtest代码:

; ========================================== ; pmtest.asm ; 编译输出nasm pmtest.asm -o pmtest.com ; ========================================== %include "pm.inc" ; GDT结构头文件 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_DATA: Descriptor 0, DataLen-1, DA_DRW+DA_DPL1 ;可读写数据段 LABEL_DESC_LDT: Descriptor 0, LDTLen-1 , DA_LDT ;LDT LABEL_DESC_CODE_RING3: Descriptor 0,SegCodeRing3Len-1 , DA_C+DA_32+DA_DPL3 LABEL_DESC_STACK: Descriptor 0, TopOfStack , DA_DRWA+DA_32 LABEL_DESC_STACK3: Descriptor 0, TopOfStack3 , DA_DRWA+DA_32+DA_DPL3 LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW+DA_DPL3 ;显存地址 LABEL_DESC_CALL_GATE: Descriptor 0, CodeCallGateLen-1, DA_C+DA_32 ;调用门地址 LABEL_DESC_TSS: Descriptor 0, TSSLen-1, DA_386TSS ;TSS段 LABEL_CALL_GATE_TEST: Gate SelectorCodeCallGate ,0 ,0 ,DA_386CGate+DA_DPL3 ; 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 SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT SelectorCodeCallGate equ LABEL_DESC_CALL_GATE - LABEL_GDT SelectorStack equ LABEL_DESC_STACK - LABEL_GDT SelectorTSS equ LABEL_DESC_TSS - LABEL_GDT SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT+SA_RPL3 SelectorCodeRing3 equ LABEL_DESC_CODE_RING3- LABEL_GDT+SA_RPL3 SelectorStack3 equ LABEL_DESC_STACK3 - LABEL_GDT+SA_RPL3 ; END of [SECTION .gdt] [SECTION .data1] ;数据段 ALIGN 32 [BITS 32] LABEL_DATA: ;字符串 PMMessage: db "Welcome to Protect Mode",0 ;在保护模式中显示 OffsetPMMessage equ PMMessage-$$ DataLen equ $-LABEL_DATA ; END of [SECTION .data1] [SECTION .s16] [BITS 16] LABEL_BEGIN: mov ax, cs mov ds, ax mov es, ax mov [LABEL_GO_BACK_TO_REAL+3], ax ; 初始化 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, 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 ; 初始化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 ;初始化测试调用门的代码描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_CODE_CALL_GATE mov word [LABEL_DESC_CALL_GATE+ 2], ax shr eax, 16 mov byte [LABEL_DESC_CALL_GATE+ 4], al mov byte [LABEL_DESC_CALL_GATE+ 7], ah ;初始化ring0堆栈段 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_STACK_3 mov word [LABEL_DESC_STACK3 + 2], ax shr eax, 16 mov byte [LABEL_DESC_STACK3 + 4], al mov byte [LABEL_DESC_STACK3 + 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 ; 初始化 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 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 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 ah,0ch ; 0000: 黑底 1100: 红字 xor esi,esi xor edi,edi mov esi,OffsetPMMessage ;源数据偏移 mov edi,(80*10+0)*2 ;屏幕第10行,第0列 cld ;设置DF值 .1: lodsb ;从esi 指向的源地址中逐一读取一个字符,送入AL 中; test al,al jz .2 mov [gs:edi],ax add edi,2 jmp .1 .2: ;显示完毕 ;call SelectorCallGateTest:0 ;LOAD TSS mov ax,SelectorTSS ltr ax ;在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。 ;进入ring3 push SelectorStack3 push TopOfStack3 push SelectorCodeRing3 push 0 retf ;跳转到LDT ;mov ax, SelectorLDT ;lldt ax ;jmp SelectorLDTCodeA:0 ;跳回实模式 ;jmp SelectorCode16:0 SegCode32Len equ $-LABEL_SEG_CODE32 ; END of [SECTION .s32] [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] [SECTION .ldt] ALIGN 32 ; ldt描述符,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*12+0)*2 mov ah, 0Ch ;0000:黑底 1100:红字 mov al, 'L' mov [gs:edi],ax add edi,2 mov al, 'D' mov [gs:edi],ax add edi,2 mov al, 'T' mov [gs:edi],ax ;跳回实模式的代码段 jmp SelectorCode16:0 CodeALen equ $-LABEL_CODE_A ; END of [SECTIONH .la] ;Call Gate 代码段 [SECTION .cgate] ALIGN 32 [BITS 32] LABEL_CODE_CALL_GATE: mov ax,SelectorVideo mov gs,ax mov edi,(80*14+0)*2 mov ah, 0Ch ;0000:黑底 1100:红字 mov al, 'G' mov [gs:edi],ax add edi,2 mov al, 'A' mov [gs:edi],ax add edi,2 mov al, 'T' mov [gs:edi],ax add edi,2 mov al, 'E' mov [gs:edi],ax ;跳转到LDT mov ax, SelectorLDT lldt ax jmp SelectorLDTCodeA:0 ;retf CodeCallGateLen equ $-LABEL_CODE_CALL_GATE ;堆栈段ring0 [SECTION .s0] ALIGN 32 [BITS 32] LABEL_STACK: times 512 db 0 TopOfStack equ $-LABEL_STACK-1 ; END of [SECTION .s0] ;堆栈段ring3 [SECTION .s3] ALIGN 32 [BITS 32] LABEL_STACK_3: times 512 db 0 TopOfStack3 equ $-LABEL_STACK_3-1 ;代码段ring3 [SECTION .ring3] ALIGN 32 [BITS 32] LABEL_CODE_RING3: mov ax,SelectorVideo mov gs,ax mov edi,(80*16+0)*2 mov ah, 0Ch ;0000:黑底 1100:红字 mov al, 'R' mov [gs:edi],ax add edi,2 mov al, 'I' mov [gs:edi],ax add edi,2 mov al, 'N' mov [gs:edi],ax add edi,2 mov al, 'G' mov [gs:edi],ax add edi,2 mov al, '3' mov [gs:edi],ax call SelectorCallGateTest:0 ;jmp $ SegCodeRing3Len equ $-LABEL_CODE_RING3 ;END of [SECTION .ring3] [SECTION .tss] ALIGN 32 [BITS 32] LABEL_TSS: DD 0 ; Back DD TopOfStack ; 0级堆栈 DD SelectorStack ; 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

 

你可能感兴趣的:(c,video,dos,include,任务,Descriptor)