保护模式验证段寄存器的属性

         保护模式第一篇段寄存器,学习过8086汇编的同学应该知道段寄存器在8086种的重要程度,8086CPU的寄存器都是16位,8086CPU能够以16位的地址总线访问到1MB的内存地址,采用的就是段地址*16+偏移地址=物理地址的方式,以16位地址总线访问1MB的物理内存,8086时代访问的地址都是物理地址没有虚拟地址的概念,进程访问的都是物理地址,如果不小心改了系统数据这是非常的危险的,本人在保护模式下编写驱动都没少蓝过,实在不敢想象如果应用程序能直接访问操作系统,得让操作系统崩溃多少次,实在不安全,于是随着时代的发在实模式退出了舞台(当然计算机刚上电进入的是实模式然后跳转到保护模式的),来到了保护模式的时代,首先需要理解的是保护模式保护的是什么

        刚接触编程的时候老师们就没少给我们灌输,计算机所有能操作的东西都必须加载到内存中才能够处理数据,可见内存有多么重要,理所当然保护模式就是保护的内存资源,从实模式到保护模式,由单任务->到多任务,有直接访问的物理地址->到抽象到虚拟地址(每个进程有4GB的虚拟地址,低2GB不同,高2GB是操作系统内核所有进程通用的),我们应用程序能有权限访问的只有低2GB,高2GB运行着操作系统的内核应用程序没有权限访问,保护模式保护的是内存,它是通过段机制,和页机制的双层保护机制(后面会讲到CPU是如果通过段机制和页机制实现对内存的保护)

       通过上面的科普让大家了解了一点实模式和保护模式的知识,也来到今天的课题段寄存器32位windows系统下使用的寄存器都是32位,段寄存器有CS  ES  DS  SS  FS  GS等,我们在使用dtbug等调试工具看到的这些寄存器都是16位的,而这16位只是段寄存器的可见部分(称为段选子),还有80位是不可见的但却实际存在的,总共分为四部分

struct  Segment{

   shrot       Select;                                     //16位的段选择子

   shrot       Atrribute;                                 //16位的段属性    决定了这个段是可读,可写,还是可执行

   int           Base;                                      //段的开始

   int           Limit;                                      //段的限长          从开始到结束就是段的限长可以访问的地方

}

段CS  ES  DS  SS  FS  GS

在3环可以看到WIndows  Xp系统可以看到

cs的段选择子为0x1B          Base=0x00000000             Limit=0xFFFFFFFF           cs段的属性为可读,可执行(稍后证明)

  es=ss=ds=0x23               Base=0x00000000             Limit=0xFFFFFFFF           这些数据段的属性为可读可写(稍后证明)

fs的段选择子为0x3B          Base=0x7FFDF000            Limit=0xFFF                      属性为可读可写

操作系统有两种表非常的重要GDT(全局描述符表)IDT(中断描述符表)

这些段寄存会根据段选择子,从GDT表中加载段描述符(顾名思义就描述加载段的属性 访问属性,Base,Limit)

加载的时机就是当段寄存的选择子发生(也就是可见部分)改变的时候比如:Mov ds,ax  执行这行代码后,ds段选择子发生赋值

就会从GDT表中加载段描述符(需要新的属性描述这个段了)

 

可以看到下面这张图片,   mov  ax,ss  mov  ds,ax  把ss的段选择值,给了ds 在执行为mov   ds,ax后 CPU需要从GDT表中

根据段选择子加载对应的段描述符,用于描述ds段的属性,这里ds和ss的选择值本来就是相同的都是0x23  段的属性也都相同可读可写,段的开始和结束也都一样,得到的结构也完全没有问题

cs的选择子是0x1B   Base=0,Limit=0xFFFFFFFF和ds相同的,但是cs段的属性是可读可执行,ds段的属性是可读可写,

可以看到执行了mov  ds,ax  ds=0x1B后  CPU会从GDT表中加载对应的段描述符(用于描述ds段的属性),加载完成后ds段访问权限和cs段一样了可读,可执行当执行mov  ds:[taolaoda],1000就挂了  0xC0000005访问异常 没有写的权限

fs段寄存的选择子位0x3B  Base=0x7FFDF000(以自己电脑的为准)   Limit=0xFFF把0x3B赋值给es后,CPU从GDT表中根据段选择子加载段属性,Base,Limit 此时 es段的Base=0x7FFDF000,所有  mov  edi,dword ptr es:[0]这行代码访问的是 es.Base+0这个内存地址,这才是本质,平常es=ds=ss的base=0所以  []里面的地址就是实际的虚拟地址   0+[]中的地址

es段寄存器赋值了fs的选择子,当CPU从GDT表中记载完成后,Base=0x7FFDF000,Limit=0xFFF所以es段的范围只有

Base到Base+Limit之间,这明显越界了,所以过不了段的检测

就是这么简单,有人肯定会有疑问2GB以上的内存空间访问会出问题是因为没道理?难道因为搞2GB是内核空间所有不能访问,

应用程序确实不能访问高2GB,但不是因为高2GB是内核,ds,es,ss的base=0,limit=0xFFFFFFFF,这说明内核也在他们访问范围之内,可以过段的检查,但是别忘了保护模式是有段和页机制一起实现,过来段的检查过不了页的检查啊,

 

GS寄存器Windows并没有使用到,我们可以自己使用,需要注意的是GS寄存器几乎进内核就会把清0(后面的帖子到逆向Windows的线程切换代码SwapContext中可以找到这条清0的反汇编代码),这是初学内核需要注意的地方,下断点调试的时候如果实现了GS单步的时候可能会挂,让程序直接运行就可以了。

 

我们上面写段寄存器的时候只写入了16位,剩下的80位填充什么,从哪里来的?答案是根据写入的段选择子,CPU从GDT表中对应位置的段描述符中加载而来的,本期见这里了,后面还会带来,CPU如果从GDT表中记载段描述到段寄存器,和各种保护模式的只是,页的只是,应用程序到系统调用如何从ring3进入ring0,进程线程的只是,windows线程切换的逆向,APC机制等等

 

 

 

 

 

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值