GDTR 寄存器
存放的是GDT(全局描述符表)表的位置和大小,大小为48位
在windbg中 r gdtr 查看GDT表的位置
r gdtl 查看表的大小
GDT表里面存放的元素称为段描述符 大小为8字节
dd +地址 查看地址里面的内容 查看4字节
dq +地址 查看8字节
eq +地址 +8字节数据 往指定地址写入数据
3环读取gdtr寄存器值
char buff[6]={0};
_asm{
sgdt buff
}
buff里面存的就是gdtr寄存器的值, 低两字节是gdt表的大小,高四字节是gdt表的地址,一共6字节。
段描述符
P位 当P位位1时 段描述符有效 为0时无效
Limit 长度为20位,高四字节的16至19位 低四字节的0至15位。 当G位为0时,Limit的单位是字节。为1时,Limit的单位是4KB(FFF)。加起来就是32位。
S位 当s位为1时,当前段描述符为代码段或者数据段描述符。为0时,是系统段描述符。
段寄存器
段寄存器结构
WORD Selectot //段选择子
WORD Attribute //属性 段描述符高四字节的第8位开始 到第23位结束
DWORD Base //基地址
DWORD Limit //界限
段选择子
段选择子是一个16位的段描述符
串起来: 给一个段寄存器赋值的时候 类似 mov ds,ax 实际上ds会被赋值96位 过程是这样的
1:把ax看成段选择子 经过段权限检查(段选择子的RPL<=DPL)
2:看TI 位,如果为0,查GDT表。如果为1,查LDT表(windows只用GDT表所以这里的值一定为0);
3:把第3至15位看成一个索引,在GDT表中查出段描述符(8字节),查出来的值给段寄存器赋值。
TYPE域
s位为1时
type域位于段描述符高4四字节的第8至11位。
当第11位为0时:当前段为数据段
E 扩展方向 为0 向上扩展 为1 向下扩展 windows只用了向上扩展,向下扩展会出错。已测试
W 可写 为1表示可写,0表示不可写
A 是否访问 为1表示被访问过,为0表示没有被访问过
当第11位位1时,当前段为代码段。
A 是否访问 为1表示被访问过,为0表示没有被访问过
R 可读 为1表示可读,0表示不可读
C 一致性 为1时 是一致代码段,为0 非一致代码段
一致代码段与非一致代码段区别
非一致代码段: 用户权限只能访问用户数据
一致代码段: 用户权限可以访问内核数据
s位为0时
解析段描述符代码:
#include "stdafx.h"
#include <string.h>
#include "stdio.h"
typedef struct {
unsigned short limit_low; //limit的低16位
unsigned short base_low; //base的低16位
unsigned char base_middle; //base的中间8位
unsigned char type:4; //数据段或者代码段的详细描述
unsigned char s:1; //0 代表当前段位代码段,1代表数据段
unsigned char dpl:2; //当前等级描述符
unsigned char p:1; // 当P位位1时 段描述符有效 为0时无效
unsigned char limit_high: 4; //limit的16-19位
unsigned char :1; //系统没有使用这一位
unsigned char :1; //没有使用
unsigned char d_b:1; // D/B位,CPU在读取指令时解析硬编码不同,不用关心。
unsigned char g:1; //0 代表limit的单位是1字节,1 代表limit的单位是4kb
unsigned char base_high; //base的高8位
}GDT,*PGDT;
void segmentDesctiprotInfoParse(PGDT pGdt)
{
if (!pGdt->p)
{
printf("当前段描述符无效\n");
return;
}
printf("当前段描述符的 DPL =%x\n",pGdt->dpl);
if (pGdt->s==0)
{
switch (pGdt->type)
{
case 1:
printf("该段描述符为系统段描述符,类型为 16位TSS(Avallable)");
break;
case 2:
printf("该段描述符为系统段描述符,类型为 LDT");
break;
case 3:
printf("该段描述符为系统段描述符,类型为 16位TSS(Busy)");
break;
case 4:
printf("该段描述符为系统段描述符,类型为 16位调用门");
break;
case 5:
printf("该段描述符为系统段描述符,类型为 (Task)任务门");
break;
case 6:
printf("该段描述符为系统段描述符,类型为 16位(Intertupt)中断门");
break;
case 7:
printf("该段描述符为系统段描述符,类型为 16位(Trap)陷阱门");
break;
case 9:
printf("该段描述符为系统段描述符,类型为 32位TSS(Avallable)");
break;
case 11:
printf("该段描述符为系统段描述符,类型为 32位TSS(Busy)");
break;
case 12:
printf("该段描述符为系统段描述符,类型为 32位调用门");
break;
case 14:
printf("该段描述符为系统段描述符,类型为 32位(Intertupt)中断门");
break;
case 15:
printf("该段描述符为系统段描述符,类型为 32位(Trap)陷阱门");
break;
default:
printf("该段描述符为系统段描述符,被系统保留,未使用");
}
return;
}
else
{
switch (pGdt->type)
{
case 0:
printf("当前段描述符为数据段 权限为:只读 向上扩展 未被访问\n");
break;
case 1:
printf("当前段描述符为 数据段 权限为:只读 向上扩展 已被访问\n");
break;
case 2:
printf("当前段描述符为 数据段 权限为:可读 可写 向上扩展 未被访问\n");
break;
case 3:
printf("当前段描述符为 数据段 权限为:可读 可写 向上扩展 已被访问\n");
break;
case 4:
printf("当前段描述符为 数据段 权限为:只读 向下扩展 未被访问\n");
break;
case 5:
printf("当前段描述符为 数据段 权限为:只读 向下扩展 以被访问\n");
break;
case 6:
printf("当前段描述符为 数据段 权限为:可读 可写 向下扩展 未被访问\n");
break;
case 7:
printf("当前段描述符为 数据段 权限为:可读 可写 向下扩展 已被访问\n");
break;
case 8:
printf("当前段描述符为 非一致代码段 权限为:可执行 未被访问\n");
break;
case 9:
printf("当前段描述符为 非一致代码段 权限为:可执行 已被访问\n");
break;
case 10:
printf("当前段描述符为 非一致代码段 权限为:只读 可执行 未被访问\n");
break;
case 11:
printf("当前段描述符为 非一致为代码段 权限为:只读 可执行 已被访问\n");
break;
case 12:
printf("当前段描述符为 一致代码段 权限为:可执行 未被访问\n");
break;
case 13:
printf("当前段描述符为 一致代码段 权限为:可执行 已被访问\n");
break;
case 14:
printf("当前段描述符为 一致代码段 权限为:只读 可执行 未被访问\n");
break;
case 15:
printf("当前段描述符为 一致代码段 权限为:只读 可执行 已被访问\n");
break;
}
//计算base值
int base=pGdt->base_low+(pGdt->base_middle<<16)+(pGdt->base_high<<24);
printf("当前段描述符的base=%X\n",base);
//计算limit值
int limit_high=pGdt->limit_high;
int limit=(limit_high<<16)+pGdt->limit_low;
if (pGdt->g==1)
{
limit=(limit<<12)+0xfff;
}
printf("当前段描述符的limit=%X\n",limit);
}
}
int main(int argc, char* argv[])
{
printf("非一致代码段: 用户权限只能访问用户数据\n");
printf("一致代码段: 用户权限可以访问内核数据\n\n");
//测试数据,数组第一个元素是低32位,第二个元素是高32位
unsigned int a[]={0x0000f200,0x0400ffff };
GDT gdt;
memcpy(&gdt,&a,sizeof(GDT));
segmentDesctiprotInfoParse(&gdt);
return 0;
}