操作系统真象-保护模式

操作系统真象-保护模式

Column: September 12, 2021
Tags: learning experience, 操作系统

一点写汇编的新知识:

可以在代码中用[bits xx]来指定生成xx位的shellcode, 如果在接触到下一个[bits xx]之前出现了不符合当前位数的内存/寄存器操作, 则会在机器码之前添加0x66(反转操作数大小前缀)和0x67(反转寻址方式签字), 然后汇编如何在机器码方面体现操作数的位数不同就交给硬件吧!

如何进入保护模式:

  1. 打开A20地址线
  2. 加载gdt
  3. 将cr0的pe位置1

PS. 这三个步骤可以不顺序, 不连续, 且具体实现方式可以用好多不同的小步骤

GDT:

GDT全局描述表, 为loader加载到内存中, 其作用为记录内存段的属性, 使得保护模式下的地址分段赋予权限等, 每个表项为64位: 记录了有段基址, 段界限(这俩在表内居然不是连续的位…为了兼容的说), G(颗粒度, 段界限的单位: byte/4kb ), S(系统段/非系统段), TYPE(细分的段类型), AVL(用户的操作系统可以自由使用这个段), D/B(也是为了兼容的玩意), L(是否64位代码段), 前面这种东西, 谁记得住啊(悲

GDT表索引范围为0-8192, 其中0号不可用, GDT的地址被一个特殊寄存器GDTR(48位)记录, 而且在保护模式中还可以重新加载GDT, 因为可能要挪个位置2333

LDT局部描述表, 基本用不上的玩意就懒得看了

选择子

之前16位的段寄存器虽然现在不用用*4的偏移了, 所以也不直接记录段地址了, 现在用来记录选择子, 0-1位记录请求的特权级, 第2位判断GDT/LDT, 剩下的是在描述中的索引值

个人感觉上面的玩意知道概念就行, 真得自己打工实操的时候再查字典吧2333

代码:

mbr: 这玩意, sector count改成4就行了

boot.inc: 书上那么多0属实顶不住, 疯狂数错

LOADER_BASE_ADDR equ 0x900
LOADER_START_SECTOR equ 0x2

DESC_G_4K equ 1_000_000_000_000_000_000_000_00b
DESC_D_32 equ 1_000_000_000_000_000_000_000_0b
DESC_L    equ 0_000_000_000_000_000_000_000b

DESC_AVL  equ 0_000_000_000_000_000_000_00b
DESC_LIMIT_CODE2 equ 1111_0000_0000_0000_0000b
DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2 equ 0000_000_000_000_000_000b
DESC_P equ 1_000_000_000_000_000b
DESC_DPL_0 equ 00_000_000_000_000_0b
DESC_DPL_1 equ 01_000_000_000_000_0b
DESC_DPL_2 equ 10_000_000_000_000_0b
DESC_DPL_3 equ 11_000_000_000_000_0b
DESC_S_CODE equ 1_000_000_000_000b
DESC_S_DATA equ DESC_S_CODE
DESC_S_sys  equ 0_000_000_000_000b
DESC_TYPE_CODE equ 1000_0000_0000b
DESC_TYPE_DATA equ 0010_0000_0000b

DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \
DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \
DESC_P + DESC_DPL_0 + DESC_S_CODE + \
DESC_TYPE_CODE + 0x00

DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \
DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \
DESC_P + DESC_DPL_0 + DESC_S_DATA + \
DESC_TYPE_DATA + 0x00

DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \
DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \
DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b

RPL0 equ 00b
RPL1 equ 01b
RPL2 equ 10b
RPL3 equ 11b
TI_GDT equ 000b
TI_LDT equ 100b

loader.S:

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP equ LOADER_BASE_ADDR

jmp loader_start
GDT_BASE:  dd 0x00000000
           dd 0x00000000
CODE_DESC: dd 0x0000ffff
           dd DESC_CODE_HIGH4
DATA_STACK_DESC: dd 0x0000ffff
                 dd DESC_DATA_HIGH4
VIDEO_DESC: dd 0x80000007
            dd DESC_VIDEO_HIGH4

GDT_SIZE equ $ - GDT_BASE
GDT_LIMIT equ GDT_SIZE - 1
times 60 dq 0
SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0
SELECTOR_DATA equ (0X0002<<3) + TI_GDT + RPL0
SELECTOR_VIDEO equ (0X0003<<3) + TI_GDT + RPL0

gdt_ptr dw GDT_LIMIT
        dd GDT_BASE
loadermsg db '2 loader in real', 0x0a

loader_start:
    mov sp, LOADER_BASE_ADDR
    mov bp, loadermsg
    mov cx, 18
    mov ax, 0x1301
    mov bx, 0x001f
    mov dx, 0x1600
    int 0x10

;ready to go to protect
;open A20
    in al, 0x92
    or al, 0000_0010B
    out 0x92, al
;load GDT
    lgdt [gdt_ptr]
;change cr0
    mov eax, cr0
    or eax, 0x00000001
    mov cr0, eax

    jmp dword SELECTOR_CODE:p_mode_start

[bits 32]
p_mode_start:
    mov ax, SELECTOR_DATA
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov esp, LOADER_STACK_TOP
    mov ax, SELECTOR_VIDEO
    mov gs, ax
    mov byte [gs:160], 'P'

jmp $

坑:

说来好玩, 我一开始dd loader到hd60M之后突然发现loader_start中的代码没有写入硬盘中, 以为是汇编写错了, 然后才发现dd的count也要写到4, 要不然字节数不足以支持写完所有内容
偶对,突然还想起来之前曾经为16位的实模式下写入32位寄存器而困惑,其实是这样的,俺们实际后面运行的是32位环境,而它硬件什么的向下兼容,导致可以在16位实模式下使用32位的寄存器

猜你喜欢

转载自blog.csdn.net/eeeeeight/article/details/120318934
今日推荐