您的位置:首页 > 其它

数据执行保护的奥秘

2006-04-12 15:02 351 查看
http://lu0s1.3322.org/sys/20041022.html

数据执行保护的奥秘


作者: 陆麟
转载请征得作者同意.
2004.10.22

“数据执行保护“的奥秘
lu0
Webmaster of Inside Programming
http://lu0.126.com
2004-10-5
转载请注出处

Microsoft在WINDOWS XP SP2中增加的”数据执行保护”是令人感兴趣的安全措施之一. 本文研究的是如何进行”数据执行保护”。

首先,在讨论数据执行保护前,我们看看是什么导致所谓”数据执行保护”的概念得以实现。 最先出现能够使得”数据执行保护”概念得到实现的是AMD64架构的CPU。

AMD64是一个架构。在这个架构下,支持64位操作数,虚拟地址空间也被扩展到了64位。AMD64为64位的操作增加一个名为Long Mode的CPU运作模式。在Long Mode下,划分了2种执行模式出来:一种被称为64-Bit Mode。一种被称为Compatibility Mode。32BIT的CPU支持的32位、16位保护模式和实模式则被称为Legacy Mode. 从AMD64 Architecture Programming Manual中有下表描述AMD64支持的各种模式。
<!--[if !vml]-->

<!--[endif]-->

既然操作模式有了加强,地址转换机制也需要顺路进行加强。分页机制在Long Mode下有2种可能性。 1种是1个PAGE为4K,另外1种为1PAGE为2M。4K PAGE的地址转换由4级页表转换得来。而2M PAGE的地址转换由3级页表转换得来。

看看4K的页是怎么回事情。
<!--[if !vml]-->

<!--[endif]-->
把地址划分为6组。Bit48-63是Bit 47的符号扩展,不在转换中起作用。为什么要这么设计要问AMD。Bit39-47是Page Map Level 4(PML4) Index,Bit30-38是Page Directory Pointer(PDP) Index,Bit21-29是Page Directory(PD) Index,Bit12-20是Page Table (PT) Index。转换过程与”数据执行保护”无关,本文中不予介绍。有兴趣的朋友可以自行参考AMD64 Architecture Programmer Manual,但是各表的Entry却和”数据执行保护”大大相关。因此是一定要介绍的。下面是各表的Entry格式。

<!--[if !vml]-->

<!--[endif]-->

Long Mode 4K PML4E (Level 4)

<!--[if !vml]-->

<!--[endif]-->

Long Mode 4K PDPE (Level 3)

<!--[if !vml]-->

<!--[endif]-->

Long Mode 4K PDE (Level 2)

<!--[if !vml]-->

<!--[endif]-->

Long Mode 4K PTE (Level 1)


2MPAGE则是3级转换得出物理地址位置。
<!--[if !vml]-->

<!--[endif]-->

把地址划分为5组。Bit48-63是Bit 47的符号扩展,不在转换中起作用。Bit39-47是Page Map Level 4(PML4),Bit30-38是Page Directory Pointer(PDP),Bit21-29是Page Directory(PD)。省略了Page Table。
<!--[if !vml]-->

<!--[endif]-->

Long Mode 2M PML4E (Level 3)

<!--[if !vml]-->

<!--[endif]-->

Long Mode 2M PDPE (Level 1)

<!--[if !vml]-->

<!--[endif]-->

Long Mode 2M PDE (Level 1)

Page Map Level 4(PML4),Page Directory Pointer(PDP) Index,Page Directory(PD) Index, Page Table (PT) Index都是以表的形式存在。每个表容纳一定数量的Entry。我们可以看到在各个表的Entry都会有1个NX Bit,位于Bit 63。其他的Bit我们暂不关心,这个NX bit则是这次”数据执行保护”的关键所在。

No Execute (NX) Bit.在各Entry的中的Bit63决定当对应的项映射到虚拟内存中,对应的地址是否可以是代码并且被执行。当NX位被设定为1,代码不可以从对应的虚拟地址执行。如果NT位被设定为0,代码可以从对应的地址执行。

NX是扩展功能,通常在某个特殊寄存器的某个Bit会有一个标志,来起用NX功能。这个Bit就是No-Execute Enable (NXE) Bit。在Extended Feature Enable Register(EFER)寄存器的Bit11。EFER寄存器是Model Specific Register(MSR)的其中一个。EFER位于MSR的C0000080H处。可以通过特权指令RDMSR/WMSR来进行读写。当NXE为1时,NX功能就启动了。所谓”数据执行保护”也就被启动出来。在启动NX功能前,必须通过CPUID指令来确定NX功能确实存在。CPUID指令的Function 80000001H用于检查CPU的Signature和AMD扩展功能。可用来检查NX功能是否存在。AMD扩展的CPUID指令可以在AMD64 Architecture Programmer Manual Vol3中得到详尽参考。

当NXE,也就是EFER的Bit11被置为1前,NX Bit被认为是保留位。如果将NX Bit置1则会导致一个Page Fault Exception。只有将NXE置为1后,NX位才开始发挥作用。当NX发生作用时,如果每次执行指令时都去检查NX Bit,恐怕CPU的效率不会很好。因此,NX Bit只在指令TLB(TLB是虚拟地址和物理地址转换用的CACHE)加载的时候才会被检查。CPU在指令预取时,如果没有命中指令TLB,就需要尝试将虚拟地址和物理地址转换加载到TLB。此时,如果NX Bit被检查到为1,就引发一个Page Fault exception。而且无论是否是RING0,这项检查都无法逃过。

有一个小小的地方需要注意,由于每个表Entry都有NX位。因此不同表Entry的能控制的NX范围也不同,比如PTE中的NX只能控制对应的PAGE是否NX。而PDE的NX位则作用于PDE所指向的整个PT。当PDE的NX位为1,无论对应的PTE是否NX被置位,对应的页面就是NX,不可执行。

上面讲到的都是Long Mode的NX。AMD在设计CPU时,同样将NX设计到了Legacy Mode中。但是Legacy Mode的情况有些特殊,32BIT的PTE,PDE需要兼容INTEL的IA32的PTE,PDE。而且IA32的PTE,PDE并没有什么空闲的地方可以插入NX位。有什么地方能动脑筋一下的呢?嘿嘿,从PENTIUM PRO开始,INTEL定义了一个名为Physical Address Extension(PAE)的扩展模式。在这个模式下,能够使用到36Bit的物理地址。能动脑筋的恐怕就是Physical Address Extension(PAE)起用后的PDPE,PDE,PTE了。在PAE起用后,PDPE,PDE,PTE被扩展为64Bit. 由于PAE只用36BIT的地址空间,Bit63到可以占用一下。INTEL在PAE中规定了4K和2M这2种页面格式,那AMD看来也必须兼容4K和2M这2种格式的页面。AMD在设计Legacy Mode的NX功能时,不象Long Mode那么全面。并没有在所有的级别都设定了NX Bit。

首先看看Legacy Mode情况下的4K页面。
<!--[if !vml]-->

<!--[endif]-->
虚拟地址分成4部分。Bit30-31是Page Directory Pointer(PDP),Bit21-29是Page Directory Index,Bit 12-20是Page Table(PT) Index。

<!--[if !vml]-->

<!--[endif]-->
Legacy mode PAE 4K PDPE

<!--[if !vml]-->

<!--[endif]-->
Legacy mode PAE 4K PDE

<!--[if !vml]-->

<!--[endif]-->

Legacy mode PAE 4K PTE

我们可以看到在Legacy PAE Mode下,4K的页面模式,只有PTE和PDE能控制NX。而PDPE则无法控制NX。

再看看Legacy Mode情况下的2M页面。

<!--[if !vml]-->

<!--[endif]-->


虚拟地址分成3部分。Bit30-31是Page Directory Pointer(PDP),Bit21-29是Page Directory Index。

<!--[if !vml]-->

<!--[endif]-->
Legacy mode PAE 2M PDPE

<!--[if !vml]-->

<!--[endif]-->

Legacy mode PAE 2M PDE

在Legacy PAE Mode下,2M的页面模式,只有PDE能控制NX。而PDPE同样无法控制NX。

好了,硬件上的AMD64基本规格就是这样。自从AMD64推出这样的规格后。INTEL也开始走“兼容”路线。INTEL称为EM64T,NX规格的兼容是EM64T的一部分。

NX规格可以使得某片区域的RAM无法被执行。但是又不影响读写,这样的区域很符合HEAP和STACK的特征。通常HEAP和STACK是只能被读写,不被用来生成可执行代码的。这个很不错的特性被WINDOWS XP SP2所利用。就是所谓的”数据执行保护”了。但是”数据执行保护”有其局限性,因为”数据执行保护”归根结底是个CPU提供的硬件保护措施,如果CPU不支持NX特性,那么”数据执行保护”就无从谈起。目前大家手头的机器基本是没有机会享用这个”高级”特性了。

那么在现实情况下,有了NX特性可以预防什么情况的发生呢?网络入侵中有一种常见入侵就是堆栈溢出,有些病毒和蠕虫也利用堆栈溢出来获得操作机会。NX规格对这些情况十分适用。可以阻止病毒,蠕虫以及入侵的代码被执行。通常情况下应用程序在STACK被破坏以后没有能力继续运行,但是OS却有了机会向应用发出一个ACCESS VIOLATION的异常。一个编写良好的应用通过SHE能获得出错地址,并且利用这点协助分析自己代码的问题所在。

在WINDOWS XP SP2以及其他能支持NX功能的WINDOWS OS下如何识别是因为”数据执行保护”引发的异常呢?这是个问题。当”数据执行保护”引发异常后,应用程序通过SEH捕捉到的异常是STATUS_ACCESS_VIOLATION,异常信息的第一个参数是异常类型。当检查到这个值为8时,代表这个违例是由于试图在NX的区域执行代码所导致的。如果是在KERNEL MODE(比如驱动程序中)触发”数据执行保护”异常,就会引发一个兰屏。BugCheck代码是0xfc。这就要求各个驱动厂商必须更仔细检查自己的代码稳定性。以前那些由于STACK OVERFLOW引发的漏洞十分隐蔽,兰屏时很难区分真正BUG所在,现在这样的BUG就比较容易被抓到。骂不到Microsoft了。

”数据执行保护”对一些应用提出的新的要求。比如可执行文件的壳程序。启动了”数据执行保护”后,正常情况下通过malloc/HeapAlloc获得的RAM,则是不可执行的。意味着当壳解码真正执行内容时,如果是解码到malloc/HeapAlloc中获得的空间,那代码会无法执行起来。必须在执行目标代码前通过VirtualProtectEx设定页面的属性为PAGE_EXECUTE/PAGE_EXECUTE_WRITE_COPY/PAGE_EXECUTE_READ,或者PAGE_EXECUTE_READWRITE。这对可执行文件的壳作者提出了新的挑战。如果壳代码不顾一切,先将所有的的页面全部设定为PAGE_EXECUTE_READWRITE,那么就彻底破坏了NX的原有保护功能。在壳代码所在的进程范围内无法阻止病毒蠕虫和恶意入侵。如果那个壳装的是SERVERICE。那个SERVICE如果存在缓冲区溢出漏洞则仍然会将系统暴露给攻击者。NX带来的好处将全部消失。那样的话一个糟糕的应用加上糟糕的壳会是更糟糕的产品。

在WINDOWS XP SP2以及其他能支持NX的WINDOWS OS下,有时候由于NX的存在导致的问题会严重影响系统。想象一下下面的状况:某些PROJECT受到限制,购买了其他厂商的SDK,其中有一部分代码是以C文件的形式存在,厂商在提供代码时考虑到代码的知识产权的问题,没有提供真正的源代码,而是在某一个C文件里面写一个BYTE ARRAY,把代码的2进制值写到了BYTE ARRAY里面。原先在没有NX的情况下勉强是跑起来了。但是一旦起用了NX功能,应用就崩溃了,经过几次人事更替后,新来的员工根本无法断定问题所在部件。真不是普通的糟糕。现在仍然有最后一招。Boot.ini为NX功能新增了2个开关。/NOEXECUTE和/EXECUTE。/NOEXECUTE用来起用NX功能。而/EXECUTE则关闭了NX功能。在产品一时无法定位问题所在时,可以用这个救急。但是普通用户就要注意了。如果安装了某个应用后,您发现Boot.ini中出现了/EXECUTE参数,说明您安装的那个软件是个很糟糕的软件,应该要注意一下。如果有替代产品的话就用替代产品顶上。不要让糟糕的软件破坏系统整体安全性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: