Win10安全特性之执行流保护

腾讯电脑管家 · 2015/02/04 15:07

0x00 背景


微软在2015年1月22日公布了windows10技术预览版,Build号:9926。电脑管家反病毒实验室第一时间对其引入的新安全特性进行了深入分析。

众所周知,漏洞利用过程中攻击者若要执行恶意代码,需要破坏程序原有指令的的正常执行。执行流保护的作用就是在程序执行的过程中检测指令流的正常性,当发生不符合预期的情况时,及时进行异常处理。业界针对执行流保护已经有一些相对成熟的技术方案,在微软发布的windows10最新版本中,我们看到了这一防护思想的广泛使用。

0x01 CFI


CFI即控制流完整性Control-Flow Integrity,主要是通过对二进制可执行文件的动态改写,以此为其增加额外的安全性保障。

这是Mihai Budiu介绍CFI技术时使用的例子。这里通过对二进制可执行文件的改写,对jmp的目的地址前插入一个在改写时约定好的校验ID,在jmp的时候看目的地址前的数据是不是我们约定好的校验ID,如果不是则进入错误处理流程。

同理在call 和 ret的时候也可以进行改写:

左半部分就是一个对call的改写,右半部分是对ret的一个改写,在call的目的地址和ret的返回地址之前插入校验ID,然后改写的call 和ret中增加了对校验ID的检查,如果不符合预期,进入错误处理流程,这个思路和上边对jmp的处理是完全一样的。

0x02 CFG


实现CFI需要在jmp、call 一个寄存器(或者使用寄存器间接寻址)的时候,目的地址有时必须通过动态获得,且改写的开销又很大,这些都给CFI的实际应用造成了一定的困难。

微软在最新的操作系统win10当中,对基于执行流防护的实际应用中采用了CFG技术。CFG是Control Flow Guard的缩写,就是控制流保护,它是一种编译器和操作系统相结合的防护手段,目的在于防止不可信的间接调用。

漏洞攻击过程中,常见的利用手法是通过溢出覆盖或者直接篡改某个寄存器的值,篡改间接调用的地址,进而控制了程序的执行流程。CFG通过在编译和链接期间,记录下所有的间接调用信息,并把他们记录在最终的可执行文件中,并且在所有的间接调用之前插入额外的校验,当间接调用的地址被篡改时,会触发一个异常,操作系统介入处理。

以win10 preview 9926中IE11的Spartan html解析模块为例,看一下CFG的具体情况:

这里就是被编译器插入的CFG校验函数

但是静态情况下默认的检测函数是一个直接return的空函数,是微软在和我们开玩笑吗?

通过动态调试看一下

从上图我们可以看出,实际运行时的地址和我们通过IDA静态看到的地址是不一样的,这里就涉及到CFG和操作系统相关的那部分。支持CFG版本的操作系统加载器在加载支持CFG的模块时,会把这个地址替换成ntdll中的一个函数地址。不支持CFG版本的操作系统不用理会这个检测,程序执行时直接retn。

这是ntdll中的检测函数

原理是在进入检测函数之前,把即将call的寄存器值(或者是带偏移的寄存器间接寻址)赋值给ecx,在检测函数中通过编译期间记录的数据,来校验这个值是否有效。

检测过程如下:

首先从LdrSystemDllInitBlock+0x60处读取一个位图(bitmap),这个位图表明了哪些函数地址是有效的,通过间接调用的函数地址的高3个字节作为一个索引,获取该函数地址所在的位图的一个DWORD值,一共32位,证明1位代表了8个字节,但一般来说间接调用的函数地址都是0x10对齐的,因此一般奇数位是不使用的。

通过函数地址的高3个字节作为索引拿到了一个所在的位图的DWORD值,然后检查低1字节的0-3位是否为0,如果为0,证明函数是0x10对齐的,则用3-7bit共5个bit就作为这个DWORD值的索引,这样通过一个函数地址就能找到位图中所对应的位了。如果置位了,表明函数地址有效,反之则会触发异常。

这里有个有趣的东西,虽然使用test cl,0Fh检测是否0x10对齐,如果对齐的话实际上用3-7位作为索引,也就是说第3位一定是0。但如果函数地址不是0x10对齐的话,则会对3-7位 or 1,然后再作为索引。这样就有一个弊端,如果一个有效的间接调用的函数地址是8字节对齐的,那么其实是允许一个8字节的一个错位调用的,这样可能导致的结果就是可能造成虽然通过了校验,但是实际调用的地址并不是原始记录的函数地址。

还有一点,如果这时候漏洞触发成功,间接调用的寄存器值已经被攻击者修改了,这时候从bitmap中取值的时候可能造成内存访问无效。请看LdrpValidateUserCallTargetBitMapCheck符

号处的这条指令:mov edx,dword ptr [edx+eax*4] edx是bitmap地址,eax是索引,但如果eax不可信了,这个很有可能,则会导致内存访问异常,并且这个函数并没有异常处理。这是因为微软为了效率考虑(毕竟这个校验函数的调用十分频繁,一个开启CFG的模块可能会有上万个调用处),微软在ntdll! RtlDispatchException中对该地址发生的异常做了一个处理:

如果异常发生的地址命中LdrpValidateUserCallTargetBitMapCheck,则进行一个单独处理,RtlpHandleInvalidUserCallTarget会校验当前进程的DEP状态和要间接调用的地址(ecx)的内存属性,如果当前进程关闭了DEP并且要间接调用的地址有可执行属性,则触发CFG异常,否则通过修改pContext把EIP修正到ret返回处,并且表明异常已被处理。

最后再说下这个原始的bitmap,在系统初始化的时候,内存管理器初始化中会创建一个Section(MiCfgBitMapSection32),这个Section在Win8.1上的大小是通过MmSystemRangeStart(32位下是0x80000000)计算的,前面提到过bitmap里面1位代表8字节,计算完后正好是32MB

而在Win10上MiCfgBitMapSection32的大小有了变化,直接写死成了0x3000000(48MB)

Section创建完成后在每个进程启动的时候会映射进去

(NtCreateUserProcess-> PspAllocateProcess-> MmInitializeProcessAddressSpace-> MiMapProcessExecutable-> MiCfgInitializeProcess)
复制代码

映射的时候作为shared view,除非某一个进程修改了这片内存。

在一个CFG模块映射进来的时候,重定位过程中会重新解析PE文件LOADCONFIG中的Guard Function Table以重新计算该模块对应的bitmap(MiParseImageCfgBits),最后更新到MiCfgBitMapSection32中去(MiUpdateCfgSystemWideBitmap)。

0x03 电脑管家XP防护的执行流保护


早些年的漏洞攻击代码可以直接在栈空间或堆空间执行指令,但近几年,微软操作系统在安全性方面逐渐加强,DEP、ASLR等防护手段的应用,使得攻击者必须借助ROP等绕过手段来实现漏洞利用。在ROP利用中,栈交换指令Stack pivot必不可少。

针对ROP攻击的防御长久以来是漏洞防御的一个难题,因为ROP指令在静态层面分析与程序的正常指令流毫无差别,且运行时也是在合法模块内执行,因此极难防御。

管家漏洞防御团队针对ROP利用的特点,从整个程序的执行流层面进行分析,研究出在动态运行时区分是合法指令流还是异常指令流的方法,其思想与CFI不谋而合。

下边就是一个由于错位汇编形成的比较常用的栈交换指令

而实际正常的执行流程是这样的

以上是没有开启XP防护的情况

开启电脑管家XP防护之后:

此时如果攻击者依靠静态分析时得到栈交换指令位置来执行ROP攻击的话,会被执行流保护逻辑发现异常,后续攻击则无法实现。

0x04 尾声


CFG防护方法需要在编译链接阶段来完成准备工作,同时需要操作系统的支持。CFI无需编译时的帮助,且不仅能够防御call调用,能够对全部执行流进行保护。但CFI需要插入大量的检测点,并且在执行过程中检测的频率极高,难免对程序执行效率带来影响。

电脑管家XP版的防御方法相比于前两者,对性能的影响更小,但这种方法是针对旧版操作系统的缓解方案,通用性会打折扣。所以建议广大windows用户尽量升级到最新操作系统,享受全面的安全保护。而由于某些原因无法升级的用户也不必担心,管家XP版会继续提供最高的安全防护能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452459.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java】 大话数据结构(1) 线性表之顺序存储结构

本文根据《大话数据结构》一书,实现了Java版的顺序存储结构。 顺序存储结构指的是用一段地址连续的存储单元一次存储线性表的数据元素,一般用一维数组来实现。 书中的线性表抽象数据类型定义如下(第45页): 实现程序&am…

程序复杂程度的定量度量

对程序复杂程度进行度量的目的 1.把程序的复杂程度乘以适当常数即可估算出软件中错误的数量以及软件开发需要用的工作量, 2.定量度量的结果可以用来比较两个不同的设计或两个不同算法的优劣; 3.程序的定量的复杂程度可以作为模块规模的精确限度。 …

Readhat中升级openssh

1.挂载yum源(镜像) 如何挂载yum源(镜像),在本人的另外一篇博客中,请戳这里 2.安装升级所需依赖 由于升级ssh需要安装依赖,这里提前将所需依赖安装 指令: yum install -y zlib-dev…

android暂停活动,如何将Android暂停活动带到前面

我有一个活动启动异步任务,侦听来自服务器的消息.当用户点击主页按钮时,活动暂停,异步任务继续在后台运行.当某个消息到达时,我希望活动恢复并在不重新创建的情况下到达前面.我尝试了以下内容.机器人:launchMode "singleTop"intent new Intent(getBaseContext(), M…

软件开发人员怎样走好从技术到管理之路?

软件开发人员怎样走好从技术到管理之路?这是一部分技术人员思考和谈论的老话题。虽然我自己并没有丰富的管理经验,但还是想记载下这一段时间里对这一问题的想法。从我个人走过的路来看,要走顺这条路,应该做好三个方面:…

如何选择程序设计语言

程序设计语言是人和计算机通信的最基本的工具,会影响人的思维和解题方式,影响人和计算机通信的方式和质量,影响其他人阅读和理解程序的难易程度。 选择适宜的程序设计语言的原因: 1.根据设计去完成编码时,困难最少&am…

zabbix4

1.宏(Macros) 宏可以理解为一个用于文本替换模式的预设文本内容; 宏根据一系列预定义的规则替换一定格式的文本模式,一般情况下,解释器或编译器在遇到宏时会自动进行文本模式替换; 类似的,Zabbix可以基于宏保存预设文件…

结对项目——Subway

博客链接:结对项目-Subway 转载于:https://www.cnblogs.com/Dominic-Abraham/p/9117266.html

Readhat中作安全基线

文章目录1.新建文件夹并上传脚本2.修改脚本中设置root2用户的密码字段3.添加脚本的可执行权限4.执行脚本5.尝试使用root2登录验证1.新建文件夹并上传脚本 在根目录下的/openssh8(没有则新建)中上传脚本: 2.修改脚本中设置root2用户的密码字…

软件测试的准则

1.所有测试都应该能追溯到用户需求;2.应该远在测试开始之前就制定出测试计划;3.把Pareto原理应用到软件测试中;4.应该从“小规模”测试开始,并逐步进行“大规模”测试;5.穷举测试是不可能的;6.为了达到最佳…

在线计算机计器,计算机存储单位换算-电脑容量在线换算器

APP说明存储单位是一种计量单位。指在某一领域以一个特定量,或标准做为一个记录(计数)点。再以此点的某个倍数再去定义另一个点,而这个点的代名词就是计数单位或存储单位。二进制序列用以表示计算机、电子信息数据容量的量纲,基本单位为字节B…

WordPress插件开发-创建、停用、删除插件

插件存放目录 wp-content/plugins 创建一个插件 在plugins创建一个文件插件文件夹,命名最好加前缀,这个前缀可以使用你的名字或者你自己的域名,防止插件和别人重名,再创建一个PHP文件名字和你的插件名一样。我这里创建一个名为 yg…

在eclipse中使用hadoop插件

我的配置环境看我的上篇博文。 配置过程: (1)把插件放到eclipse/plugins目录下。(我的版本上一篇也有) (3)重启eclipse,配置Hadoop installation directory 如果插件安装成功&#…

从程序员到技术领导者

入行 你为什么要当程序员?每当我问起很多人入行的人,回答各不相同。 有很多人是因为喜欢。谁说过:热爱是最好的老师。当然,关键是热爱是否能支撑自己把爱好做成一份职业。但不论做多久,因为热爱或曾经热爱&#xff0…

黑盒测试和白盒测试

黑盒测试(又称功能测试)把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。黑盒测试是在程序接口进行的测试,只检查程序功能是否能按照规格说明书的规定正常使用,程序是否能适当地接收输入数据并产生正确的输…

Diango博客--11.Nginx + Gunicorn + Supervisor 方式部署

文章目录0.部署前准备1.创建一个超级用户2.更新 SQLite33.安装 Python3 、pip3.6以及 Pipenv4.部署代码5.使用 Gunicorn6.启动 Nginx 服务器7.配置 Nginx8.关闭 DEBUG 模式,收集静态文件9.使用 Supervisor管理 Gunicorn 进程10.使用 CDN 加快 Bootstrap 和 jQuery 的…

计算机更改了用户名数据恢复,怎么把电脑更换用户后恢復到原来的用户呢?

如何让administrator帐户出现在登陆画面?安装Windows XP时,如果设置了一个管理员账户,那么系统内置没有密码保护的Administrator管理员账户是不会出现在用户登录列表中的。虽然它身在幕后,可却拥有系统最高权限,为了方…

StringBuilder类

1.1 StringBuilder类概述StringBuilder:是一个可变的字符串。字符串缓冲区类。 String和StringBuilder的区别:String的内容是固定的StringBuilder的内容是可变的1.1.1 拼接字符串耗费内存原因:每次拼接都会产生新的字符串对象,而利用StringBuilder来拼接字符串自始至…

如何使用搜索技巧来成为一名高效的程序员

没有人是完全独立的孤岛,每个人都是整体的一部分。—— 约翰多恩对于缺乏编程知识的人来说,完全有可能编写一个网页或小程序。如果在用Google搜索相关示例时幸运的话,可以搜到现成的代码。即使是经验丰富的程序员,通常也会为了节省…

电开大计算机应用基础作业,2016年电大-电大计算机应用基础作业 答案.doc

2016年电大-电大计算机应用基础作业 答案计算机作业2单项选择题:第1题:在Word中编辑文本时,编辑区显示的“水印”在打印时( )出现在纸上。(2分)A、不会B、全部C、一部分D、大部分第2题:Word文档以文件形式存放于磁盘中,其默认的文件扩展名为(…