IE漏洞攻防编年简史

jopen 8年前

IE漏洞攻防编年简史

本文对历史上的微软 IE 浏览器的影响较大 0day 做了梳理,讨论了 IE 漏洞在攻击防御技术上的进化,以及记录了此类漏洞前人们在历史上遗留下来的对抗经验和足迹。

在 IE 浏览器攻防已经白热化的进入到第三个阶段的时候笔者才进入到 IE 浏览器攻防方面的研究学习。此时代号’Project Spartan’的微软的 Edge 浏览器从 IE11 手中接过 windows 默认浏览器的重担,使得服役将近 20 年的 IE 浏览器定格 11 这个历史的大版本号上面,自觉对 IE 浏览器漏洞的历史研究应有一篇简记,可供后来的初入行的安全研究者有所参考,故成此文,疏漏之处再所难免,敬请指正。

0×01 浏览器漏洞研究的前置背景

最近几年,网络安全研究的部分重心开始有由 PC 端向移动端倾斜的趋势。但是在 PC 端的安全研究依然以浏览器 IE/Chrome/Firefox/Spartan,Adobe 的 Reader/Acrobat/Flash 系列作为技术研究深度的展现。当然还有部分用于特定地区定向攻击的文件格式漏洞也属于一些黑客着重关注的领域,比如日本比较流行的字处理软件 ichiaro 和在韩国地区比较流行的 Hancom Office 等字处理软件系统以及 WPS 等字处理软件方面的文件格式漏洞。

浏览器从诞生之初主要提供简单的文档阅读功能.很少构成网络安全威胁,但随着互联网的高速发展,越来越多的功能集被加入到浏览器中。浏览器不仅需要像操作系统那样,为阅读文档、观看电影、欣赏音乐等传统计算机应用提供基础,也需要为社交网络、网络购物等新兴互联网应用提供支持。浏览器在增加功能集的同时,也就带来了更多的安全问题。而集成捆绑于系统中的 IE 浏览器可以占据市场较大份额,自然也成了众矢之的。针对 IE 浏览器的攻防军备竞赛也就是在这种情况下拉开了帷幕。

0×02 IE 浏览器漏洞攻防的几个时代

1. 1 缓冲区溢出和 ActiveX 控件时代(03 年-08 年)

03 年-08 年这是一个阶段,这个阶段时候的 IE 漏洞基本是以 ActiveX 控件造成的漏洞居多以及栈溢出漏洞还有一些简单的堆溢出漏洞。比如 IFRAME 标签的单个超长 SRC 属性导致的缓冲区溢出以及类似的栈溢出漏洞。

早一些的阶段,常规的 Fuzz 方法,无论是基于变形的还是基于生成的,比较适合应用于二进制格式的流数据,特别是那些包含大量 C 语言结构类型的文件或网络协议格式。由于格式解析代码经常不加检查的使用数据流数据作为内存操作的参数,单点的畸形往往就足以触发解析代码中可能存在的处理漏洞:超长数据导致的缓冲区溢出、畸形数值导致的整数上溢和下溢、畸形索引值导致数组的越界访问、畸形记数导致过量的内存读写操作。其中对于超长数据导致的缓冲区溢出,样本构造起来相对简单,传入超长的值。所以这种类型的漏洞由于发掘起来相对简单。

对早期的 IE 0day 漏洞的历史简单做一下梳理,只包含了影响比较大的例子(图 1.1.1,图 1.1.2),有些漏洞可能并不是 IE 本身的问题,但是以 IE 为最主要的利用渠道。

IE漏洞攻防编年简史

图 1.1.1

IE漏洞攻防编年简史

图 1.1.2

1. 2 时代关键字

防护方: DEP /ASLR / Stack Cookie

攻击方: 栈溢出/简单堆溢出/ROP/HeapSpray

A 缓冲区溢出

关于缓冲区溢出也简单给出一个例子方便理解:

IE漏洞攻防编年简史

图 1.2.1

我们在 VC6.0 的编译器编译上述程序,执行后结果如下:

IE漏洞攻防编年简史

图 1.2.2

可以看到 main 函数中只调用了 foo 这个函数。但是实际运行中,bar 函数也被调用了。

实际上因为 foo 函数处理不当,并且外部输入超长,造成了缓冲区溢出后修改了 foo ()函数的返回地址从而导致程序执行本不应该执行的 bar ()函数。而如果被覆盖的返回地址是一串经过精心编码具有后门功能的 shellcode,此时计算机即可被恶意攻击者控制。

这只是一个简单的C程序的范例,表现在浏览器当中形式上多少有所不同,比方说 IE 浏览器支持的 IFRAME 标签,IFRAME 标签的单个超长 SRC 属性构造超长数据可能就会导致的缓冲区溢出从而浏览器崩溃。

DEP 和 Security Cookie

从上面的缓冲区溢出我们可以看到,在特定的环境下只要控制输入的数据超长然后覆盖掉返回地址,只要此时程序崩溃就很容易感知目标程序存在缓冲区溢出漏洞。然后在修改这串超长数据糅合上恰当的 shellcode 精确覆盖返回地址就可以执行我们的恶意代码。只是留给攻击者的这样的大好时光极为短暂。微软从 Windows XP SP2 开始提供 DEP 的支持。DEP 全称是 Data Execution Prevention,可以分为硬件的 DEP 和软件的 DEP。但是目的都是一致的。阻止数据页上代码执行。(图 1.2.3)

IE漏洞攻防编年简史

图 1.2.3

由于数据所在的内存页被标识为不可执行,即使程序溢出成功转入 shellcode 的执行,这个时候 CPU 就会抛出异常从而阻止恶意 shellcode 的执行。

从这里也可以看到这一阶段的攻击者只是去覆盖栈上的返回地址,试图从栈上将恶意 shellcode 执行起来。

考虑到攻击是因为覆盖返回地址产生的,微软在 VS2008 和之后的编译器加入了一个编译选项 GS。也就是 Security Cookie 也可以称为 Stack Cookie。

IE漏洞攻防编年简史

图 1.2.4

可以看到在开始的时候会将一个 security_cookie 提前写入到栈中。而在函数返回之前会检查这个 security_cookie 是否被篡改。

IE漏洞攻防编年简史

图 1.2.5

一旦被篡改便会跳转到异常执行的流程:

IE漏洞攻防编年简史

(图 1.2.6)

当然这里说的是栈中的情况。在堆溢出中也有相似的防护措施如 Header Cookie。

盯上 SEH

当攻击者发现覆盖 4 字节返回地址(32 位系统)去执行 shellcode 这种攻击方法的门槛被抬高之后便又想出了新的方案。覆盖 SEH 的 Exception handler

其实在二进制的攻防当中所有的努力都是为了获得哪怕一次控制 EIP (RIP)的机会。而 SEH 恰好符合这个要求可以给攻击者提供这个机会。SEH 存放在栈内,故超长的数据就可能覆盖掉 SEH  ,其中将异常处理函数的入口地址更改为 shellcode 的起始地址。由于溢出后产生的错误数据往往会触发异常,而此时 shellcode 恰好可以得到一次被 EIP 指向的机会。

只是留给攻击者的好时光依然极为短暂。在 VS2003(.net)当中支持了/SafeSEH 的选项,用于应对针对 S E H 的攻击。后来又进一步推出了 SEHOP。当然这些措施需要 XP SP2 操作系统以及更新的操作系统还有 DEP 的配合。这两种防护措施详细展开又要占很多篇幅。感兴趣的读者可以自行学习。

需要说明的是 64 位的 windows 系统 SEH 已经不是放在栈中了。想要通过栈溢出覆盖异常处理例程来实现漏洞利用已经是不可能的了。

ROP ASLR 和 HeapSpray 技术

前面说到 DEP 技术即使返回地址被 shellcode 覆盖,DEP 也会去阻止 shellcode 的执行。但是如果执行的代码是操作系统的库本身提供的函数如直接使用 libc 库中提供的 system ()函数来覆盖程序函数调用的返回地址。然后传递重新设定好的参数使其能够按照预期执行。这种绕过 DEP 的攻击方式称为 return to libc。

Return-to-libc 攻击用库函数的地址来覆盖程序函数调用的返回地址,这样在程序返回时就可以调用库函数从而使攻击得以成功实施。但是由于攻击者可用的指令序列只能为应用程序中已存在的函数,所以这种攻击方式的攻击能力有限。并且攻击只能在 x86 的 CPU 平台中实施而对 x86_64 的 CPU 平台中无效。这是因为 x86_64CPU 平台中程序执行时参数不是通过栈传递的而是通过寄存器,而 return-into-libc 需要将参数通过栈来传递。

由于这种 return-to-libc 攻击方式的局限性,返回导向编程(Return-Oriented Programming, ROP)被提出,并成为一种有效的 return-to-libc 攻击手段。返回导向编程攻击的方式不再局限于将漏洞程序的控制流跳转到库函数中,而是可以利用程序和库函数中识别并选取的一组指令序列。攻击者将这些指令序列串连起来,形成攻击所需要的 shellcode 来从事后续的攻击行为。因此这种方式仍然不需要注入新的指令到漏洞程序就可以完成任意的操作。同时,它不利用完整的库函数,因此也不依赖于函数调用时通过堆栈传递参数。

一般我们通过 immunitydbg 配合 mona 的脚本插件提取 rop 的指令序列构造 rop chain。

Rop chain 展示:

IE漏洞攻防编年简史

图 1.2.7

Rop 的出现一度使得在 XP 时代的攻击者占据上风。由于 dll 加载地址的固定。针对不同的 IE 版本然后提取 rop chain 的工作虽然让人感觉无趣但是达成的攻击效果的确不错。但是作为防御一方的微软的脚步并没有停止。Vista 系统的臃肿繁杂为人所诟病并且市场份额也并不高。但是从 Vista 系统引入的由 Win7 沿袭的 ASLR 机制却结结实实的又一次提高了攻击的门槛。

在 Rop 攻击中,攻击者可以事先预知特定的函数如 system 或者 VirtualProtect 的入口地址。这是因为在 XP 以及 2000 的操作系统上面,由于 kernel32.dll 这些动态链接库加载地址是固定的,所以导致相关的函数入口地址也是固定的即攻击者可以事先确定这些函数的入口地址。

当然 Rop 这一技术有一个弊端就是针对不同的操作系统要编写提取不同的 rop chain。这使得兼容性并不是很好。

ASLR 全称 Address space layout randomization,是系统级别的特性,率先在 Vista 操作系统中得到支持。它的原理就是在当一个应用程序或动态链接库 ,如 kernel32.dll,被加载时,如果其选择了被 ASLR 保护 ,那么系统就会将其加载的基址随机设定 。这样 ,攻击者就无法事先预知动态库,如 kernel32.dll 的基址,也就无法事先确定特定函数,如 VirtualProtect 的入口地址了。

如果感兴趣,可以自己写一段简单的C代码打印出 VC 运行库的加载地址。会发现每次重启之后 win7 下面 VC 运行库加载地址是变化的,但是 XP 系统 VC 的运行库加载地址就是固定的。    

Heap Spray

ASLR 在新系统上面的应用又使得相当长的一段时间在缓冲区溢出利用时代攻击方陷入了弱势。但是攻击者发现之前很早就被提出的(2001 年左右)heap spray 正好可以解决这个问题。基本在 2005 年之后 IE 漏洞的利用很多都用到了 Heap Spray 的技术。

在缓冲区溢出的时候,我们能够劫持覆盖一个地址,从而使得程序崩溃,但是只使得程序崩溃这样是没有价值的接下来如何将程序的执行流程交接到 shellcode 的手中,这就变成了一个问题。如果覆盖到一个固定的地址比 0x0C0C0C0C,0x0A0A0A0A,0x0D0D0D0D 而恰好从这个地址开始布满了我们的 shellcode。这样触发漏洞的时候就转入了我们的 shellcode 进行了恶意代码的执行。

实际应用当中 shellcode 前面都是要加上一些 slidecode 的(滑板指令)。为什么要加入滑板指令而不是全用 shellcode 去填充呢。因为如果要想 shellcode 执行成功,必须要准确命中 shellcode 的第一条指令,如果整个进程空间都是 shellcode,反而精确命中 shellcode 的概率大大降低了,因为必须要命中第一条指令,加上 slidecode 之后,现在只要命中 slidecode 就可以保证 shellcode 执行成功了,一般 shellcode 的指令的总长度在 50-100 个字节左右,而 slidecode 的长度则大约是 100 万字节(按每块分配 1M 计算),那么现在命中的概率就接近 99.99% 了。因为现在命中的是 slidecode,那么执行 slidecode 的结果也不能影响和干扰 shellcode。但是如果单纯使用0×90(NOP)指令进行填充,因为现在使用较多的攻击场景是覆盖虚函数指针(这是一个多级指针),这种情况下如果你使用0×90 来做 slidecode,而用 0x0C0C0C0C 去覆盖虚函数指针,那么现在的虚表(假虚表)里面全是0×90909090,程序跑到0×90909090(内核空间)去执行,直接就 crash 了。根据这个流程,你可以看到,我们的 slidecode 也选取 0x0C0C0C0C 就可以了。

IE漏洞攻防编年简史

(图 1.2.8)

大概大量分配内存之后分别覆盖到的地址是这样的:

  0x0A0A0A0A(160M),    0x0C0C0C0C(192M),    0x0D0D0D0D(208M)

网马里面进行堆喷时,申请的内存大小一般都是 200M 的原因,主要是为了保证能覆盖到 0x0C0C0C0C 地址。(图 1.2.9)

IE漏洞攻防编年简史

2. 1 UAF 时代

由于缓冲区类漏洞由于发掘起来相对简单,在攻防对抗的时间长河中这类漏洞资源很快耗尽。08 年之后释放重利用这样漏洞利用方式变成了 IE 漏洞的主流。逐渐在这几年达到了高峰。对象畸形操作类的漏洞一般来说触发漏洞需要一系列的操作。单个的操作,比方说对象的创建使用删除都是正常的。导致问题的是对于对象操作的畸形的组合。由于没有标准的章法可供参考,基于传统的溢出类漏洞的发掘手段已经不甚适用。

2. 2 对象操作类漏洞原理

跟面向过程的编程语言不同,c++支持多态和继承。支持这些机制的核心就是虚表。C++的(虚)函数指针位于一个全局数组中,形成虚表。而指向这个虚表的指针(VSTR)一般位于对象实例在内存中开始的 4 个字节(32 位系统).

之后才是类中声明的数据成员,一般按照声明的先后顺序排列。对于存在多态行为的类,子类的所有实例共享相同的虚表,但区别于父类的虚表。对于某个对象,其调用存在多态行为的某个函数时,会先通过虚表指针得到虚表.再根据函数在虚表中的偏移来得到相应的函数指针,最后才会调用函数。

另外,对象所在的地址一般通过 ecx 等寄存器传递。因此.C++中调用存在多态行为的函数的反汇编代码类似于如下序列:

IE漏洞攻防编年简史

(图 2.2.1)

我们以 stackexchange 上面 Polynomial 给出的示范代码对 UAF 做一下简介。

如下例的这样的一段 C++ 代码:

IE漏洞攻防编年简史

图 2.2.2

可以衍生为:

IE漏洞攻防编年简史

注意,当执行到 Account_GetBalance 的时候,由于 Account_Destroy 函数的执行 myAccount 指针指向的内存已经是一个不确定的状态。如果此时能够可靠的触发 Account_Destroy 函数。并且填充一块精心构造的内容到 myAccount 指针指向的内存,时机在 Account_Destroy 执行后 Account_GetBalance 执行之前。很多情况下这是可能实现的。   

Account_Create 函数执行之后分配了 8 个字节的内存。Balance 和 transactionCount 分别占据 4 个字节,并且返回一个指向他们的指针。这个指针储存在 myAccount 变量当中。Account_Destroy 释放了这块内存,但是 myAccount 变量依然指向那个 8 字节的内存。我们将 39 05 00 00 01 00 00 00 这 8 字节内容可靠的进行内存分配。由于旧的 8 字节内存块已经被标记释放,所以内存管理器有很大可能会用新分配的内存去覆盖掉旧的内存块到那 8 个字节已经被释放的内存。这个时候 Account_GetBalance 函数被调用了,他会去读取那 8 个字节的内存块,但是实际上那 8 字节的内存块已经被我们覆盖成了

Balance    39 05 00 00   (1337)     transactionCount    01 00 00 001

所以我们已经越权执行到了下一个函数。

当然具体到 IE 当中,由于对象繁杂,UAF 就更为错综复杂。

浏览器中跟对象操作类漏洞相关的对象有 DOM ,BOM ,JavaScript 对象。我们以 DOM 对象的分配过程为例。

DOM (文档对象模型)提供了操作 HTML/XML 文档的接口。IE 浏览器中跟 DOM 实现相关的代码主要在 mshtml dll 中。mshtml 中的 CMarkup 类负责构造整个 htmI 树结构,其成员函数 CreateElement 会调用全局的 CreateElement 函数束构造不同标签对应的元素。比如<object>标签.会构造对应的 CObjectElement 元素:<area>标签.会构造对应的 CAreaElement 元素。这些 Element 类都是 CElement 类的子类。接下来的逆向工作主要基于 IE8  8.00.7601.17537 版本的 mshtml dll。

对于每个不同的标签,IE 测览器内部有不同的 CTagDesc 结构。这些 CTagDesc 结构中的其中一项就是对应元素的 CreateElement 函数指针。因此,全局的 CreateElement 函数,会根据不同的标签柬获得对应的 CTagDesc 结构,然后再从里面取得对应该标签的 CreateElement 函数指针然后 call 过去进行调用。具体可参看全局 CreateElement 函数的反汇编代码,如图 2.2.6 所示。

IE漏洞攻防编年简史

IE漏洞攻防编年简史

这里有一些小细节,有的时候直接用 IDA 反汇编如 mshtml dll 这样的 dll 文件的时候没有找到对应的符号表,可以先使用 Symbol Type Viewer 这样的小工具将符号表下载下来放到跟 dll 同目录然后再使用 IDA 对相关的 dll 文件进行反汇编。

IE漏洞攻防编年简史

接下来,以 CObjectElement 为例,介绍其创建过程,其他 Elenlent 的创建过程类似。CObjectElement 的初始化是在成员函数 CrcateElement 函数中完成的。创建过程如下:先分配内存,然后调用构造函数,最后将返回的对象指针保存在传入的 CElemen**参数中。反汇编代码如图。

IE漏洞攻防编年简史

图 2.2.9

HeapAlloc 进行堆内存分配,高版本的一些 mshtml dll 中可能是由 ProcessHeapAllocClear 这个函数进行内存的分配。传给 HeapAlloc 的字节数是 0E0h 可知,当前 IE 浏览器版本中的 CObjectElement 大小为 E0h。

接下来调用 CObjectEtemem 的构造函数完成 CObjectElement 对象的初始化,构造函数会自动调用父类的构造函数。调用完构造函数后.会将新建的 CObjcctElemenl 对象指针保存在传入的参数 CElemen**中。这是通过代码完成的。

mov ecx,[ebp+arg_8]  mov[ecx],eax

IE 浏览器采用引用计数束跟踪 DOM 对象的生命周期。引用计数(Reference Counting)算法对每个对象计算指向它的指针的数量。当有一个指针指向该对象时计数值加 1 ,当删除一个指向酸对象的指针时,计数值减l。如果计数值减为0,说明不存在指向该对象的指针.此时就可以安全的销毁泼对象。垃圾回收过程就是回收引用计数为 0 的对象。引用计数算法的优点是算法实现简单,并且进行垃圾回收时无需挂起应用程序,回收速度快。

缺点是出于每一次对对象的指针操作都要对对象的引用计数进行更新,因此会减缓系统的整体运行速度。另外,使用引用计数算法的每个对象都需要额外的空问存储计数值。除此之外,引用计数算法的最大缺点是无法处理循环引用。循环引用指的是两个对象互相指向对方。此时两个对象的引用计数都依赖于对方.因此始终无法减至0。

IE 浏览器实现引用计数的核心就是 IUnknown 接口。该接口提供了两个非常重要的特性:生存期控制与接口查询。对象内部通过引用计数来实现对象的生存期控制。调用程序不甩在意对象的内部实现细节.通过接口查询即可获得指向对象的指针。IE 浏览器中的很多类都继承于 IUnknown。IUnknown 有三个方法。

IE漏洞攻防编年简史

图 2.2.10

以上节介绍的<obiect>标签的内部实现 CObjectElement 类为例.该类最终继承于 CElement。而 CElement 继承于 CBase,CBase 则实现了 IUnknown 接口。用户要查询<object>标签对应的 CObjectElement 对象,需要调用 CObjectElement::QueryInterface 函数。而 CObjectElement 的 QueryIntefface 函数最终会调用到 CElement 的 QueryInterface 接口.CElement 的 QueryInterface 接口最终会调用 PrivateQueryInterface 来获得对象指针。

PrivateQueryInterface 会先调用 CElement::CreateTearOffThunk 函数退回对象包装后的指针.然后在接下来调用 CCaret::AddRef 函数(call eCX)增加引用计数。

而 CElement::CreateTearOffThunk 函数仅仅是简单的调用全局的 CreateTearOflThunk 函数。全局的 CreateTearOflThunk 函数反汇编部分代码如图

IE漏洞攻防编年简史

图 2.2.11

再来看看释放引用时所做的工作。对于 CElement,用户不再需要其引用时,调用 CElement::Release 即可。CElement::Release 是对 CElement::PrivateRelease 的封装,而 CElemem::PrivateRelease 主要的工作是调用父类 CBase 的 PrivateRelease 函数。CBase::PrivateRelease 负责减少引用计数。

实际上 IE 当中这种对对象的创建和销毁的场景比比皆是,这也是在缓冲区漏洞在 IE 上面几近绝迹后 UAF 中兴的基础。     

2. 3 时代关键字

Deferred/Delayed Free Control Flow Guard Isolated Heap

上文已经简单的给出一个例子帮助理解 UAF 的成因和触发了。但是由于 IE 中对象众多调用关系复杂,微软作为防守的一方并不能像挖掘缓冲区溢出漏洞一样容易的穷举并修复所有潜在的漏洞。但是微软分别以发布补丁的方式在 14 年的 6 月和 7 月分别引入了隔离堆和延迟释放的漏洞利用缓解措施。并且在 Win8.1Update3 和 Win10 中引入了新的机制 Control Flow Guard。我们简单记录说明一下这些机制。

UAF 的触发和利用依赖于被释放的对象的重用。利用的过程必须依赖非法 IE 对象被确定的分配和释放。而隔离堆和延迟释放分别在对象的分配和释放的时候加入了保护。

在 IE 中 CVE-2014-0282 修补前 CTextArea::CreateElement 分配内存的时候有这样的代码

IE漏洞攻防编年简史

图 2.3.1

漏洞修补之后代码是这样的。

IE漏洞攻防编年简史

图 2.3.2

可以比较明显的看到存在 UAF 隐患的对象的内存分配已经单独使用了隔离堆进行内存分配。

而延迟释放是这样的。正常的对象释放使用 HeapFree 就立即释放了,而加入延迟释放之后需要被释放的对象会被统一记录然后根据规则再进行延迟释放。

再说一下 CFG (Control Flow Guard)这个机制。CFG 的机制是基于控制流完整性 Control-Flow Integrity 的设想。这里通过对二进制可执行文件的改写,对 jmp 的目的地址前插入一个在改写时约定好的校验 ID,在 jmp 的时候看目的地址前的数据是不是我们约定好的校验 ID,如果不是则进入错误处理流程。

IE漏洞攻防编年简史

图 2.3.3

在 Call 的过程中会引入一个 CFG 的校验函数。CFG 需要编译器和操作系统的双重配合。当这个校验函数在不支持的操作系统上运行的时候直接就 return 了。当在被支持的操作系统(win10 和 win8.1 update3) 的时候就会跳转到一个 ntdll 里面的一个检测函数。检测的机制我们不在详细展开。

由于在溢出漏洞和 UAF 的大部分利用当中都依赖于覆盖某个地址然后劫持程序的 EIP 跳转到我们的恶意代码的地址进行执行。CFG 在控制非法地址跳转方面直接斩断了大部分漏洞利用的可能。

3. 1 后 UAF 时代

就目前来看,14 年之后由于新的缓解措施的加入使得攻防双方的优势几乎一边的倒向了微软为首的防守者的阵营。

浏览器的漏洞利用已经没有固定的套路。如浏览器内部的脚本引擎的设计错误导致从脚本层面突破 IE 而进行漏洞的相关利用(CVE-2014-6332),对浏览器中 flash 插件的漏洞发掘利用得到 ring3 权限,然后配合对较老字体解析引擎代码发掘出来的提权漏洞再进行提权拿到系统权限(Hacking Team 相关利用)。漏洞利用方式不一而足,有机会在修订简史的时候一并补充。                 

0×03 IE 漏洞防护措施关键时点

2015 年 7 月 CFG 编译器支持 VS2015 RTM 版本引入/guard 开关对 Control Flow Guard 特性提供编译器支持。

2014 年 11 月 CFG 系统级别支持 Windows 8.1 update3 对 Control Flow Guard 提供系统层面的支持,之后的 windows 系统均在操作系统层面支持该特性。

2014 年 7 月 MS14-037 补丁发布引入 Delayed  Free 特性。

2014 年 6 月 MS14-035 补丁发布引入 Isolated  Heap 特性。

2008 年 1 月 SEHOP 系统级别支持发布 vista Service Pack 1 补丁包,引入对 SEHOP 特性的操作系统支持。自 vista sp1 后的 windows 系统均在操作系统层面支持该特性。

2007 年 1 月 ASLR 系统级别支持 windows vista 系统引入对 ASLR 特性操作系统级别的支持。自 vista 后的 windows 系统均在操作系统层面支持该特性。

2006 年年初 safeseh/stack cookie/aslr/dep 编译器支持 VS2005 引入/safeseh 编译开关缓和溢出漏洞对 seh 的攻击,引入/GS 编译开关插入 Stack Cookie 缓和对返回地址的攻击,加入/dynmicbase 编译开关引入对 ASLR 特性的编译器支持,加入/NXCOMPAT 编译开关引入对 DE 特性的编译器支持。自 VS2005 之后的编译器均支持上述编译开关。

2004 年 8 月 DEP 系统级别支持。微软推出 XP Service Pack 2 补丁包引入对 DEP 特性的操作系统支持,自 XP SP2 后的 windows 系统均在操作系统层面支持该特性。

作者:阿尔法实验室,转载请注明来自 FreeBuf 黑客与极客

来自: www.freebuf.com