Operating system - under privilege level transfer

Deep privilege level transfer
A. Deep understanding of call gate
1. Call gate is used for code segment transfer to high privilege level
2. The privilege level of calling the door descriptor is lower than the current privilege level
Notes on calling door
1. Call gate supports privilege level peer transfer
2. Call gate level transfer is processed as normal function call or direct jump
3.CALL can promote privilege level through call gate, jmp can only transfer at the same level through call gate
4. When calling the gate privilege level return (retf), check the privilege level of the target code segment and stack segment, and force the relevant segment register to zero (the segment register pointing to the high privilege level data)
Code








%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 Section base,       Segment boundaries,       Segment properties
GDT_ENTRY       :     Descriptor    0,            0,           0
CODE32_DESC     :     Descriptor    0,    Code32SegLen - 1,   DA_C + DA_32 + DA_DPL2
VIDEO_DESC      :     Descriptor 0xB8000,     0x07FFF,         DA_DRWA + DA_32 + DA_DPL2
DATA32_DESC_0   :     Descriptor    0,    Data32SegLen0 - 1,   DA_DR + DA_32 + DA_DPL0
DATA32_DESC_2   :     Descriptor    0,    Data32SegLen2 - 1,   DA_DR + DA_32 + DA_DPL2
STACK32_DESC_0  :     Descriptor    0,     TopOfStack320,      DA_DRW + DA_32 + DA_DPL0
STACK32_DESC_2  :     Descriptor    0,     TopOfStack322,      DA_DRW + DA_32 + DA_DPL2
TSS_DESC        :     Descriptor    0,       TSSLen - 1,       DA_386TSS + DA_DPL0
FUNCTION_DESC   :     Descriptor    0,   FunctionSegLen - 1,   DA_C + DA_32 + DA_DPL0
; Call Gate
;                                           Selectors,            deviation,          Number of parameters,         attribute
FUNC_PRINTSTRING_DESC    :    Gate      FunctionSelector,   PrintString,       0,         DA_386CGate + DA_DPL3
; GDT end

GdtLen    equ   $ - GDT_ENTRY

GdtPtr:
          dw   GdtLen - 1
          dd   0

; GDT Selector
Code32Selector     equ (0x0001 << 3) + SA_TIG + SA_RPL2
VideoSelector      equ (0x0002 << 3) + SA_TIG + SA_RPL2
Data32Selector0    equ (0x0003 << 3) + SA_TIG + SA_RPL0
Data32Selector2    equ (0x0004 << 3) + SA_TIG + SA_RPL2
Stack32Selector0   equ (0x0005 << 3) + SA_TIG + SA_RPL0
Stack32Selector2   equ (0x0006 << 3) + SA_TIG + SA_RPL2
TSSSelector        equ (0x0007 << 3) + SA_TIG + SA_RPL0
FunctionSelector   equ (0x0008 << 3) + SA_TIG + SA_RPL0
; Gate Selector
FuncPrintStringSelector    equ   (0x0009 << 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_0
    mov edi, DATA32_DESC_0

    call InitDescItem

    mov esi, DATA32_SEGMENT_2
    mov edi, DATA32_DESC_2

    call InitDescItem

    mov esi, STACK32_SEGMENT_0
    mov edi, STACK32_DESC_0

    call InitDescItem

    mov esi, STACK32_SEGMENT_2
    mov edi, STACK32_DESC_2

    call InitDescItem

    mov esi, FUNCTION_SEGMENT
    mov edi, FUNCTION_DESC

    call InitDescItem

    mov esi, TSS_SEGMENT
    mov edi, TSS_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. load TSS
    mov ax, TSSSelector
    ltr ax

    ; 6. jump to 32 bits code
    push Stack32Selector2
    push TopOfStack322
    push Code32Selector;Jump to code snippet with privilege level 2
    push 0                 
    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 .dat0]
[bits 32]
DATA32_SEGMENT_0:
    DPL0               db  "DPL = 0", 0
    DPL0_OFFSET        equ DPL0 - $$

Data32SegLen0 equ $ - DATA32_SEGMENT_0

[section .dat2]
[bits 32]
DATA32_SEGMENT_2:
    DPL2               db  "DPL = 2", 0
    DPL2_OFFSET        equ DPL2 - $$

Data32SegLen2 equ $ - DATA32_SEGMENT_2

[section .tss]
[bits 32]
TSS_SEGMENT:
        dd    0
        dd    TopOfStack320           ; 0
        dd    Stack32Selector0        ;
        dd    0                       ; 1
        dd    0                       ;
        dd    0                       ; 2
        dd    0                       ;
        times 4 * 18 dd 0
        dw    0
        dw    $ - TSS_SEGMENT + 2
        db    0xFF

TSSLen    equ    $ - TSS_SEGMENT

[section .s32]
[bits 32]
CODE32_SEGMENT:
    mov ax, VideoSelector
    mov gs, ax

    mov ax, Data32Selector2
    mov ds, ax

    mov ebp, DPL2_OFFSET
    mov bx, 0x0C
    mov dh, 12
    mov dl, 33

    call FuncPrintStringSelector : 0

    jmp $

Code32SegLen    equ    $ - CODE32_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 .gs0]
[bits 32]
STACK32_SEGMENT_0:
    times 1024 db 0

Stack32SegLen0 equ $ - STACK32_SEGMENT_0
TopOfStack320  equ Stack32SegLen0 - 1

[section .gs2]
[bits 32]
STACK32_SEGMENT_2:
    times 1024 db 0

Stack32SegLen2 equ $ - STACK32_SEGMENT_2
TopOfStack322  equ Stack32SegLen2 - 1

1. As shown in the figure below, the code change mainly realizes the transfer from calling gate to high code segment

Operation results

When the privilege level of the calling door is changed to 1, func ﹣ printstring ﹣ desc: gate functionselector, printstring, 0, Da ﹣ 386cgate + Da ﹣ dpl1
There will be an error during operation. The error prompt is as follows

2. As shown in the figure below, verify the transfer experiment between peers

The results are as follows

3. Verify the privilege level check of the target code segment and the forced clearing of the related registers
Code











%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 Section base,       Segment boundaries,       Segment properties
GDT_ENTRY       :     Descriptor    0,            0,           0
CODE32_DESC     :     Descriptor    0,    Code32SegLen - 1,   DA_C + DA_32 + DA_DPL2
VIDEO_DESC      :     Descriptor 0xB8000,     0x07FFF,         DA_DRWA + DA_32 + DA_DPL2
DATA32_DESC_0   :     Descriptor    0,    Data32SegLen0 - 1,   DA_DR + DA_32 + DA_DPL0
DATA32_DESC_2   :     Descriptor    0,    Data32SegLen2 - 1,   DA_DR + DA_32 + DA_DPL2
STACK32_DESC_0  :     Descriptor    0,     TopOfStack320,      DA_DRW + DA_32 + DA_DPL0
STACK32_DESC_2  :     Descriptor    0,     TopOfStack322,      DA_DRW + DA_32 + DA_DPL2
TSS_DESC        :     Descriptor    0,       TSSLen - 1,       DA_386TSS + DA_DPL0
FUNCTION_DESC   :     Descriptor    0,   FunctionSegLen - 1,   DA_C + DA_32 + DA_DPL0
; Call Gate
;                                           Selectors,            deviation,          Number of parameters,         attribute
FUNC_PRINTSTRING_DESC    :    Gate      FunctionSelector,   PrintString,       0,         DA_386CGate + DA_DPL3
; GDT end

GdtLen    equ   $ - GDT_ENTRY

GdtPtr:
          dw   GdtLen - 1
          dd   0

; GDT Selector
Code32Selector     equ (0x0001 << 3) + SA_TIG + SA_RPL2
VideoSelector      equ (0x0002 << 3) + SA_TIG + SA_RPL2
Data32Selector0    equ (0x0003 << 3) + SA_TIG + SA_RPL0
Data32Selector2    equ (0x0004 << 3) + SA_TIG + SA_RPL2
Stack32Selector0   equ (0x0005 << 3) + SA_TIG + SA_RPL0
Stack32Selector2   equ (0x0006 << 3) + SA_TIG + SA_RPL2
TSSSelector        equ (0x0007 << 3) + SA_TIG + SA_RPL0
FunctionSelector   equ (0x0008 << 3) + SA_TIG + SA_RPL0
; Gate Selector
FuncPrintStringSelector    equ   (0x0009 << 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_0
    mov edi, DATA32_DESC_0

    call InitDescItem

    mov esi, DATA32_SEGMENT_2
    mov edi, DATA32_DESC_2

    call InitDescItem

    mov esi, STACK32_SEGMENT_0
    mov edi, STACK32_DESC_0

    call InitDescItem

    mov esi, STACK32_SEGMENT_2
    mov edi, STACK32_DESC_2

    call InitDescItem

    mov esi, FUNCTION_SEGMENT
    mov edi, FUNCTION_DESC

    call InitDescItem

    mov esi, TSS_SEGMENT
    mov edi, TSS_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. load TSS
    mov ax, TSSSelector
    ltr ax

    ; 6. jump to 32 bits code
    push Stack32Selector2
    push TopOfStack322
    push Code32Selector;Jump to code snippet with privilege level 2
    push 0                 
    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 .dat0]
[bits 32]
DATA32_SEGMENT_0:
    DPL0               db  "DPL = 0", 0
    DPL0_OFFSET        equ DPL0 - $$

Data32SegLen0 equ $ - DATA32_SEGMENT_0

[section .dat2]
[bits 32]
DATA32_SEGMENT_2:
    DPL2               db  "DPL = 2", 0
    DPL2_OFFSET        equ DPL2 - $$

Data32SegLen2 equ $ - DATA32_SEGMENT_2

[section .tss]
[bits 32]
TSS_SEGMENT:
        dd    0
        dd    TopOfStack320           ; 0
        dd    Stack32Selector0        ;
        dd    0                       ; 1
        dd    0                       ;
        dd    0                       ; 2
        dd    0                       ;
        times 4 * 18 dd 0
        dw    0
        dw    $ - TSS_SEGMENT + 2
        db    0xFF

TSSLen    equ    $ - TSS_SEGMENT

[section .s32]
[bits 32]
CODE32_SEGMENT:
    mov ax, VideoSelector
    mov gs, ax

    mov ax, Data32Selector2
    mov ds, ax

    mov ebp, DPL2_OFFSET
    mov bx, 0x0C
    mov dh, 12
    mov dl, 33

    call FuncPrintStringSelector : 0

    jmp $

Code32SegLen    equ    $ - CODE32_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

    mov ax, Data32Selector0
    mov ds, ax
    mov gs, ax

    retf

PrintString    equ   PrintStringFunc - $$

FunctionSegLen    equ   $ - FUNCTION_SEGMENT

[section .gs0]
[bits 32]
STACK32_SEGMENT_0:
    times 1024 db 0

Stack32SegLen0 equ $ - STACK32_SEGMENT_0
TopOfStack320  equ Stack32SegLen0 - 1

[section .gs2]
[bits 32]
STACK32_SEGMENT_2:
    times 1024 db 0

Stack32SegLen2 equ $ - STACK32_SEGMENT_2
TopOfStack322  equ Stack32SegLen2 - 1

Commissioning process
1. First, find the addresses of three jump commands through decompilation, and set breakpoints respectively
2. Step by step debugging, check the register value at the set breakpoint
3. In the final jmp $instruction, it is found that the value of registers ds and gs is 0, which indicates that the relevant registers are forcibly cleared when the privilege level is returned by calling the gate. The main purpose of this operation is for kernel security

Summary
1. Use of call gate
2. Call gate supports peer transfer (jmp instruction can only be peer transfer)
3.retf checking the stack
4. When the privilege level is lowered and transferred, the value of the relevant register will be cleared








Tags: Attribute

Posted on Mon, 04 May 2020 00:58:45 -0400 by Jack McSlay