前奏
X86 CPU的3个模式:实模式,保护模式和虚拟8086模式
保护模式有什么特点?
段的机制
页的机制
学习保护模式有什么用?
真正理解内核是如何运作的
段寄存器
段寄存器:
ES CS SS DS FS GS LDTR TR共8个
读一个段寄存器只读16位,写一个段寄存器写96位
Struct SegMent{
WORD Selector段选择子;//16位selector
WORD Attribute;//16位的Attribute
WORD Base;//32位的Base
DWORD Limit //32位的Limit
};
XP环境下:
段寄存器 | Selector | Attribute | Base | Limit |
---|---|---|---|---|
ES | 0023 | 可读,可写 | 0 | 0xFFFFFFFF |
CS | 001B | 可读,可执行 | 0 | 0xFFFFFFFF |
SS | 0023 | 可读,可写 | 0 | 0xFFFFFFFF |
DS | 0023 | 可读,可写 | 0 | 0xFFFFFFFF |
FS | 003B | 可读,可写 | 0x7FFDE000 | 0xFFF |
GS | - | - | - | - |
可执行:当前这个段修饰的地址可以赋值给eip
注意:
加粗数据在不同环境下,数值可能不一样。
验证环节:
探测Attribute:
__asm {
mov ax,ss //ss段寄存器可写,cs段寄存器不可写
mov ds,ax
mov dword ptr ds:[var],eax
}
printf("你死了");
__asm {
mov ax,cs //ss段寄存器可写,cs段寄存器不可写
mov ds,ax
mov dword ptr ds:[var],eax
}
printf("你死了");
验证Attribute的确存在
探测Base:
__asm {
mov ax, ds
mov gs, ax
mov eax,gs:[0]
}
__asm {
mov ax, ds
mov gs, ax
mov dword ptr ds : [var] , eax
}
验证Base的确存在
探测Limit:
__asm{
mov ax,fs
mov gs,ax
mov eax ,gs:[0x1000] //0x7FFDF000+0x1000 fs的limit的0xFFF
mov dword ptr ds:[var],eax
}
__asm{
mov ax,fs
mov gs,ax
mov eax, dword ptr cs:[0x7FFDF000 + 0x1000]
mov dword ptr ds:[var],eax
}
验证Limit的确存在
可以通过MOV指令对寄存器进行读写(LDTR和TR除外)
段描述符和段选择子
GDT(全部描述符表) LDT(局部描述符表)
Windows里面并没有使用LDT,使用的都是GDT
GDTR(48位寄存器,表中存放了GDT表 的起始地址(32位),外加存放GDT表的大小(16位))
当我们执行类似MOV DS,AX
指令时,CPU会查表,根据AX的值来决定查找GDT还是LDT,查找表的什么位置,查出多少数据。
r gdtr
利用winDbg
可以查看GDT 的地址
r gdtl
利用winDbg
可以查看GDT 表的大小
dd 地址
查看此地址开始以double word
为一组的数据
段描述符(8个字节为一组)
GDT表里面存储的元素称为段描述符,每个段描述符是8个字节
dq 地址
查看此地址开始以8个字节为一组的数据
段选择子
RPL:请求特权级别
TI:
TI=0 查GDT表
TI=1 查LDT表
Index:(索引值)
MOV DS,AX
指令时,假如AX=1B,即001B
拆分为0000 0000 0001 1011
去掉TI和RPL值,后剩下Index值为11,即3,则查GDT表索引值为3 (GDT表中索引值从0开始,索引值为0处的段描述符为0)的段描述符
加载段描述符至寄存器(dword 4个字节;fword 6个字节;qword 8个字节;):
除了MOV指令,我们还可以使用LES,LSS,LDS,LFS,LGS指令修改寄存器
CS不能通过上述的指令进行修改,CS为代码段,CS的改变会导致EIP的改变,要改CS,
必须要保证CS与EIP一起改
char buffer[6];
__asm{
les ecx,fword ptr ds:[buffer]//高2字节给es,低4个字节给ecx
}
注意:RPL<=DPL(在数值上)段权限检查
P位(高四字节第15位)
p=1短描述符有效
p=0短描述符无效
段描述符与段寄存器的对应关系
Attribute //16位 对应段描述符(高四字节) 第8位~第23位
Base //32位 (高四字节)第24位 ~ 第31位 + (高四字节)第0位 ~ 第7位+(低四字节)第16位 ~ 第31位
Limit //32位 (高四字节)第16位 ~ 第19位 +(低四字节)第0位 ~ 第15位 总共20位 最大值也就是FFFFF,此时分情况
1.如果G位为0,那么Limit单位是字节,此时高位填0,即最大值也就是0x000fffff
2.如果G位为1,那么Limit单位是4KB,4x1024=4096,4096代表有多少个,但是地址计算都是从0开始的,那么需要减1,即上限为4096-1=4095,刚好转为0xfff,如果此时Limit此时界限为1的话,那么此时为0x1FFF,则最大可以为0xffffffff
总结:
如果G为0的话,那么Limit为0x000FFFFF
如果G为1的话,那么Limit为0xFFFFFFFF
注意:
FS对应的短描述符比较特殊,FS是与线程相关,查分后的值与段寄存器中的值不符合。