第19課 - 深入特權級轉移(中)
阿新 • • 發佈:2018-12-02
資料段的訪問規則(資料段無可執行屬性)
訪問者許可權(CPL) 高於或等於資料許可權(DPL) 請求特權級(RPL) 高於或等於資料段許可權(DPL) 即:(CPL <= DPL) && (RPL <= DPL) CPU 不檢查CPL和RPL 棧段只能在同級使用(CPL==RPL==DPL) 資料段沒有一致性和非一致性的概念程式碼段的分類
非系統段( s=1) 一致性程式碼段 非一致性程式碼段 系統段( s=0) LDT,TSS,門非系統段的分類
一致性程式碼段:X= 1,C= 1 非一致性程式碼段程式碼段之間的跳轉規則(不借助門描述符)
非一致性程式碼段 程式碼段之間只能 平級轉移( CPL == DPL, RPL <= DPL) 一致性程式碼段 支援低特權級程式碼向高特權級程式碼的轉移( CPL >= DPL) 雖然可以成功 轉移高特權級程式碼段實驗結論
特權級降低轉移時,retf指令會觸發棧段的特權級檢查 一致性程式碼段可直接跳轉到其它同級非一一致性程式碼段執行 一致性程式碼段與非一致性程式碼段僅僅是使用時合法性判斷規則不同,可以同級跳轉 大多數情況下,RPL和DPL可以設定一樣的值小結
CPL,RPL和DPL是處理器進行特權級保護的依據 對於 資料段:CPL <= DPL,RPL <= DPL 對於 非一致性 程式碼段:CPL == DPL,RPL <= DPL 對於 一致性 程式碼段:CPL >= DPL,轉移後CPL不變程式碼
// loader.asm %include "inc.asm" ; 載入標頭檔案,一些常量、設定函式 org 0x9000 ; 記憶體載入地址 jmp ENTRY_SEGMENT ; 跳轉到ENTRY_SEGMENT入口處 [section .gdt] ; 全域性描述符表,部分段基址未知基址需使用時再調節(InitDescItem) ; GDT definition ; "函式名" 段基址 段界限 段屬性 GDT_ENTRY : Descriptor 0, 0, 0 ; 全域性段描述符表第0項不使用 CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32 + DA_DPL1 VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32 + DA_DPL2; 視訊段描述符表設在正確無須初始化 DATA32_DESC : Descriptor 0, Data32SegLen - 1, DA_DR + DA_32 + DA_DPL2 STACK32_DESC : Descriptor 0, TopOfStack32, DA_DRW + DA_32 + DA_DPL1 FUNCTION_DESC : Descriptor 0, FunctionSegLen -1, DA_C + DA_32 + DA_DPL1 NEW_DESC : Descriptor 0, NewSegLen - 1, DA_CCO + DA_32 + DA_DPL0 ; GDT end GdtLen equ $ - GDT_ENTRY GdtPtr: ; 全域性描述符表指標 dw GdtLen - 1 ; 偏移,記錄描述符數量 dd 0 ; 全域性描述符起始地址,先設定為0 ; GDT Selector ; TI:全域性、區域性 RPL:請求許可權級別 Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL1 ; 0x0001==第二個選擇子 VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL2 ; 視訊記憶體特權級低只會影響顯示,對系統安全無影響 Data32Selector equ (0x0003 << 3) + SA_TIG + SA_RPL2 Stack32Selector equ (0x0004 << 3) + SA_TIG + SA_RPL1 FunctionSelector equ (0x0005 << 3) + SA_TIG + SA_RPL1 NewSelector equ (0x0006 << 3) + SA_TIG + SA_RPL0 ; end of [section .gdt] TopOfStack16 equ 0x7c00 [section .s16] ; 真實模式程式碼段(16bit) [bits 16] ; 使用16位編譯 ENTRY_SEGMENT: ; 16位保護模式入口段 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 ; 初始化32位程式碼段、資料段、棧段描述符 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 ; 視訊段描述符表設在正確無須初始化 mov esi, FUNCTION_SEGMENT ; 初始化函式段描述符 mov edi, FUNCTION_DESC call InitDescItem mov esi, NEW_SEGMENT ; 初始化一致性程式碼段描述符 mov edi, NEW_DESC call InitDescItem ; initialize GDT pointer struct mov eax, 0 ; 程式碼段地址左移4位 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 ; 通過0x92埠開啟A20地址線開關 or al, 00000010b out 0x92, al ; 4. enter protect mode mov eax, cr0 ; 設定cr0暫存器,進入保護模式 or eax, 0x01 mov cr0, eax ; 5. jump to 32 bits code push Stack32Selector ;jmp dword Code32Selector : 0 ; 使用jmp跳轉到32位程式碼段選擇子的0偏移處 push TopOfStack32 push Code32Selector push 0 retf ; esi --> code segment label ; edi --> descriptor label InitDescItem: ; 初始化描述符專案 push eax mov eax, 0 ; 程式碼段地址左移4位 mov ax, cs shl eax, 4 ; 實地址=段暫存器地址左移4位+偏移地址 add eax, esi mov word [edi + 2], ax ; 將段基址寫入描述符2個位元組(16位暫存器),低32位的16-31bit(偏移2位元組) shr eax, 16 ; 移除eax實地址中已經寫入段基址的2位元組資料 mov byte [edi + 4], al ; 將段基址寫入描述符1個位元組(8位暫存器),高32位的0-7bit(偏移4+0=4位元組) mov byte [edi + 7], ah ; 將段基址寫入描述符1個位元組(8位暫存器),高32位的24-31bit(偏移4+3=7位元組) 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] ; 32位程式碼段 [bits 32] ; 使用32位編譯 CODE32_SEGMENT: ; 32位程式碼段資料 mov ax, VideoSelector ; 把視訊段選擇子放到gs全域性段暫存器 mov gs, ax mov ax, Data32Selector ; 設定資料段地址 mov ds, ax mov ax, Stack32Selector ; 設定棧段地址 mov ss, ax mov eax, TopOfStack32 ; 設定32位棧頂地址 mov esp, eax ;mov ebp, DTOS_OFFSET ; 全域性函式列印字串,使用選擇子:偏移量呼叫 ;mov bx, 0x0c ;mov dh, 12 ;mov dl, 33 ;call FunctionSelector : PrintString jmp NewSelector : 0 Code32SegLen equ $ - CODE32_SEGMENT [section .new] ; conforming code seg [bits 32] NEW_SEGMENT: mov ebp, DTOS_OFFSET ; 一致性程式碼段列印字串,使用選擇子:偏移量呼叫 mov bx, 0x0c mov dh, 12 mov dl, 33 call FunctionSelector : PrintString jmp $ NewSegLen equ $ - NEW_SEGMENT [section .func] [bits 32] FUNCTION_SEGMENT: ; ds:ebp --> string address ; bx --> attribute ; dx --> dh : row, dl : col PrintStringFunc: 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 retf PrintString equ PrintStringFunc - $$ FunctionSegLen equ $ - FUNCTION_SEGMENT [section .gs] [bits 32] STACK32_SEGMENT: times 1024 * 4 db 0 Stack32SegLen equ $ - STACK32_SEGMENT TopOfStack32 equ Stack32SegLen - 1