3段寄存器段选择子,GDT表,段描述符x86

在这里插入图片描述

在x86架构的计算机中,段寄存器是一种用于存储段选择子(Segment Selector)的寄存器。段寄存器包括:

CS(Code Segment): 存储当前执行的代码所在的段的选择子。
DS(Data Segment): 存储数据段的选择子,用于指示程序访问数据的位置。
ES(Extra Segment): 附加数据段寄存器,提供额外的数据段选择子,有时用于字符串和数据传输操作。
SS(Stack Segment): 存储堆栈段的选择子,用于指示程序的堆栈段。
FS 和 GS: 一些较新的x86处理器增加了额外的段寄存器,以提供更多的扩展性。

在x86架构中,各个段寄存器的常用名称如下:

CS(Code Segment):代码段寄存器。
DS(Data Segment):数据段寄存器。
ES(Extra Segment):附加段寄存器。
SS(Stack Segment):堆栈段寄存器。
FS(Additional Segment):额外段寄存器。
GS(Additional Segment):额外段寄存器。
32位下GS没有用

这些寄存器从功能上可以划分成两种,CS为代码段其他的我们都可以认为是数据段。

在这里插入图片描述
在这里插入图片描述
通过观察汇编代码发现 段寄存器在读取或写入内存的时候起到前缀的作用。

读实验

在这里插入图片描述

用每个段寄存器作为前缀去地址0x0041b320读取dword大小的数据,0x0041b320的数据为0x22,执行第一条指令之前EAX为0x11,

在这里插入图片描述

执行前4条指令之后EAX的值都是0x22,

当执行前缀为FS的指令后 程序崩溃 0xC0000005

FS段寄存器

观察FS跟其他段寄存器的区别
在这里插入图片描述
其他段寄存器地址都是0 但是FS寄存器是0x7FFDF000

在这里插入图片描述

在内存窗口查看 这里存放的时候SEH异常处理链表指针,
在这里插入图片描述
也就是程序入口这里mov eax,dword ptr fs:[0],会取出SEH链表指针,

在这里插入图片描述
F8单步执行,通过这个现象可以得出一个结论,在读写内存地址的时候,比如mov ecx,dword ptr ds:[0x41B320] 不仅仅是 向0x41B320地址读写,而是0x41B320地址加上段寄存器后面的地址,由于ES CS SS DS 后面地址都是0所以前面四条汇编指令执行正确读取0x0041b320地址的数据,但是到FS的时候由于FS后面的地址是0x7FFDE000所以就到0x7FFDE000+0x0041b320的地址去读写数据,所以引发程序错误,(因为0x7FFDE000+0x0041b320=0x803F9320,应用程序的虚拟地址空间通常被限制在 0x00000000 到 0x7FFFFFFF 之间,已经超过了应用层最大地址长度)。

现在知道了段寄存器的其中一个作用是用来寻址的,他的作用是在地址后面加上段寄存指向的地址。

写实验

前面测试了用段寄存器做前缀读0x0041b320地址,知道了FS读为什么会出错,现在测试用段寄存器作为前缀去写0x0041b320地址,
在这里插入图片描述
执行前三条指令后 0x0041b320都为0x123,

执行第四条指令mov dword ptr cs:[0x41B320],eax之后进程崩溃OD提示错误0xC0000005,之前这四个段寄存器做读实验的时候没出错,现在往里面写入的时候CS为前缀的命令出错了,首先可以确定读写都是同一个地址0x41B320,而且这个地址的属性也是可读可写的,由此可以知道 段寄存器还会控制写的权限

深入了解段寄存器

在这里插入图片描述
调试器显示的段寄存器后面的这些值有什么作用是哪里来的?

在这里插入图片描述
在这里插入图片描述
这张图就是段寄存后面存的两个字节(16位)的值,它有很多叫法,段选择器,段选择子,段选择符,。

第 0-1 位(RPL,Requested Privilege Level):这两位用于确定选择子所在的请求特权级别,表示当前程序或任务希望访问的特权级别,0表示0环权限11(3)表示3环权限.

第 2 位:描述符表指示位(Table Indicator Bit,TI),用于指示描述符表是全局描述符表(GDT)还是局部描述符表(LDT)中的描述符。

0:表示选择的是全局描述符表(GDT)中的描述符。
1:表示选择的是局部描述符表(LDT)中的描述符。

第 3-15 位:段描述符索引(Descriptor Index),用于指示描述符表中的描述符的位置,从 0 开始计数。

综上所述,段选择子的各位用于确定请求的特权级别、描述符表的类型以及在描述符表中的位置。这些信息帮助处理器和操作系统确定和访问内存中的段描述符,从而获得有关段的基址、限长、访问权限等重要信息。

全局描述符表GDT

LDT使用较少这里先不研究
GDT表存放的是段描述符,段描述符就是用来描述段的信息和属性的,段描述符的大小是64位

GDT表就是一个数组 每一项元素都是64位,段选择子的3-15位用来索引这张表中的段描述符。

拆分段选择子找到段描述符
在这里插入图片描述
这里将DS段寄存器的 0x0023拆分成2进制00100011

首先是RPL0-1位=11,十进制是3;表示请求特权级别是3环
TI 第2位 =0;表示使用GDT表
index 3-15位= 00100,十进制是4; 描述符在GDT表中的索引值

现在有了 GDT表的索引,通过GDTR寄存器找到GDT表的地址
(在x86架构的处理器中,GDTR寄存器(Global Descriptor Table Register)用于存储全局描述符表(GDT)的信息。)

在这里插入图片描述
在这里插入图片描述
GDT表第4项元素 0x00cff300`0000ffff,这就是DS段选择子的段描述符
在这里插入图片描述
这张图里面有个两个32位的方块 上面的是高32位下面的是低32位。

00cff300
0000ffff

解析段描述符

0x00cff300`0000ffff
段基址(Base Address):指定了段在内存中的起始地址。在32位系统中,段基址由32位的线性地址组成。
段描述符低32位的16-31位和高32位的0-7位以及24-31位就是段基址;

0x00CFF300`0000FFFF
段基址(Base Address): 00000000
在这里插入图片描述

段限长(Segment Limit):指定了段的大小。在32位系统中,段限长由20位组成,以字节为单位。这意味着在32位系统中,每个段的大小最多可以达到2^20个字节,即1MB。
段描述符低32位的0-15位和高32位的16-19位是段限长;
0x00CFF300`0000FFFF
段限长(Segment Limit)= FFFFF;

G(Granularity)是段描述符高32位的第23位,段描述符高32位的20-23位这4位=0xC
拆分成二进制就是1100,0x00CFF300`0000FFFF

G(Granularity)= 1;

G(Granularity):该位决定了段限长的粒度。如果为0,则段的限长以字节为单位;如果为1,则以4KB为单位。这意味着,如果G位为1,段的实际大小将是Segment Limit * 4096。
G位=1也就是说段的实际大小将是Segment Limit * 4096,我们需要注意一点:Segment Limit的值应该加1,因为Segment Limit实际上表示的是段的页数减1,刚才解析出段限长FFFFF,实际上应该是((fffff+1)*4096)-1=0xFFFFFFFF
在这里插入图片描述
D/B(Default/Big):是段描述符高32位的第22位,用于指示代码段的默认操作数大小或者数据段的最大增长方向。

在代码段中,如果为0,则表示默认使用16位操作数;如果为1,则表示默认使用32位操作数。
在数据段中,如果为0,则表示段的大小由段限长字段决定;如果为1,则表示段的大小是一个“增长向上”的数据段,即基址向高地址增长。
段描述符高32位的20-23位这4位=0xC
拆分成二进制就是1100,0x00CFF300`0000FFFF
D/B=1;

AVL(Available):这是一个可用位,供软件使用,CPU不会对其进行任何操作。

P(Present):该位指示段是否存在于内存中。如果为1,则表示段存在;如果为0,则表示段不存在,访问该段将会引发异常。

DPL(Descriptor Privilege Level):描述符特权级别,用于控制对段的访问权限。它决定了谁可以访问这个段,0表示最高特权级,3表示最低特权级。

S(Descriptor Type):该位用于指示描述符的类型。如果为1,则表示这是一个数据段或堆栈段描述符;如果为0,则表示这是一个系统段描述符或门描述符。

P ,DPL ,S 在段描述符高32位的12-15位 0x00CFF300`0000FFFF,二进制 1111
P=1表示该段可以访问,DPL(占两位)=11(十进制=3 表示三环权限),S=1 表示数据段或者代码段 ;

Type(Segment Type):用于指示段的类型,如代码段、数据段等
0x00CFF300`0000FFFF
Type =0011(十进制=3) ;

在x86架构中,段描述符中的 Type 字段用于指示段的类型,它决定了段的用途和访问权限。Type 字段是一个4位的字段,根据不同的取值,可以分为以下几种主要类型:

数据段(Data Segment):数据段用于存储程序的数据,比如全局变量、堆、栈等。数据段可以被读取和写入,但不能被执行。Type 字段的取值通常为 0010 或 0011。

代码段(Code Segment):代码段用于存储程序的指令。代码段可以被执行,但不能被写入或读取。Type 字段的取值通常为 1010 或 1011。

系统段(System Segment):系统段用于存储系统管理信息,比如全局描述符表(GDT)和中断描述符表(IDT)等。系统段对于用户程序来说通常是不可见的。Type 字段的取值通常为其他值。

非一致代码段(Non-Conforming Code Segment):非一致代码段与代码段类似,但它允许更低特权级的程序访问更高特权级的代码。Type 字段的取值通常为 1110。

TSS段(Task State Segment):TSS 段用于存储任务的状态信息,比如寄存器的值和任务的特权级等。它主要用于任务切换。Type 字段的取值通常为 1001。

LDT段(Local Descriptor Table Segment):LDT 段用于存储局部描述符表(LDT),它是一种特殊的全局描述符表,用于存储局部段描述符。Type 字段的取值通常为 0010。

这些 Type 字段的取值决定了段的属性和访问权限。例如,如果一个段描述符的 Type 字段取值为 1010,那么它就是一个代码段,只能被执行,不能被读取或写入。而如果 Type 字段的取值为 0010,那么它就是一个数据段,可以被读取和写入,但不能被执行。

在这里插入图片描述
当TYPE的值=0-7的时候他是一个数据段
当type=8-15的时候他是一个代码段

在这里插入图片描述
直接windbg dg 0x23命令也可以自动解析段选择子 段描述符

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值