APP下载

基于动态二进制翻译的关键内存防护

2018-10-20秦焕青马刘杰

关键词:二进制指令代码

秦焕青, 刘 敏, 马刘杰

(1.上海航天计算机技术研究所,上海200050;2.中远海运科技股份有限公司,上海200135;3.中天安泰(北京)信息技术有限公司,北京100040)

0 引 言

随着计算机技术和信息技术的快速发展,信息网络遭受到的攻击越来越多,计算机安全问题越来越来突出。近30 a来,对内存进行攻击的手段(包括内存溢出、内存破坏和内存重用等)层出不穷,其中内存溢出已是软件开发方面的难题,是黑客攻击企业网络的重要手段。据统计[1],有将近50%的安全漏洞都是由内存溢出引起的。在内存破坏类攻击中,最主要的是HOOK类动态内存破坏攻击,攻击者通过在内存中执行代码段进行挂钩注入shellcode,从而使计算机在执行被修改的代码时执行恶意代码,达到攻击目标的目的,该类攻击已成为攻击操作系统的重要手段。

为应对内存攻击问题,相关人员研究出多种防御手段。例如:针对内存溢出类攻击[2],一般采用“在非运行时检测缓冲区溢出漏洞,在运行时检测是否发生溢出漏洞”的方式,但在非运行时无法检测到所有可能的溢出漏洞,在运行时采用的被动防护(插入canary值、存储Retaddr值、指针前后加guardzone、低脂指针等)和主动防护(更换动态链接库、加密指针型数据、随机化内存地址、去堆栈布局等)方式都没有从根本上解决问题;针对内存破坏类攻击,只能被动地采用运行时防护的方式,一般的防护措施包括控制数据防护和非控制数据防护[3],该方式也没有从根本上解决问题。

实质上,无论是内存溢出类攻击还是内存破坏类攻击,在本质上都是通过中央处理器(Central Processing Unit,CPU)中的内存操作指令对本来不允许操作和修改的内存进行操作和修改。例如:内存溢出类攻击是通过修改非本函数能修改的堆栈内存进行内存修改;内存破坏类攻击是通过直接或间接修改内存进行内存修改。因此,若能实时获取针对内存操作和修改的指令,并对指令操作数进行分析,即可有效解决上述内存攻击问题。

基于上述分析,本文提出一种新的解决办法,利用“操作系统运行时会将内存提交到CPU执行,从而在提交前对提交的内存指令进行分析”的理念,分析相关操作是否有对关键内存进行篡改。通过试验验证本文提出的方法和机制对内存破坏和内存溢出行为进行防护的有效性,从而大大提高计算机的安全性。

1 总体架构和关键技术

1.1 总体架构

本文提出的关键内存防护机制总体架构和基本设计思路见图1。

首先根据系统的运行情况构建程序的关键内存保护区域,其程序运行分别包括但不限于PE文件的映射加载和映射卸载、可执行代码区域的分配和释放、操作系统和应用程序关键内存区域的构建等,将关键内存扩展到可执行内存、系统和程序对外接口位置、操作

系统和程序的关键数据区域等,从而构建一个完整的关键内存保护区域,并根据系统的运行和程序的启动与关闭自动改变关键内存的保护区域。

同时,对将要执行的代码(准备提交给CPU执行的代码)进行动态的二进制翻译,从而得到所有将要执行的指令,并获取读写内存的指令和出栈入栈指令等关键指令。出栈入栈指令用来更新关键内存中的栈保护区域,随时刷新关键内存的保护范围,从而为防止栈溢出做准备。

当准备提交的指令为写内存的指令时,判断准备写的内存地址是否在关键内存区域内。若所要写的指令在栈关键内存区域内,则代表发生栈溢出攻击;若所要写的指令在其他关键内存区域内,则代表发生内存破坏(篡改)行为,此时通过修正将要执行的代码,在CPU执行内存溢出和内存破坏行为之前阻止此类行为发生。

图1 关键内存防护机制总体架构和基本设计思路

1.2 关键技术

1.2.1 动态二进制翻译与优化技术

林洋扎根农场十个春秋,攻坚克难,大胆改革,锐意进取,带领云城乳业实现了转型发展。多年来,他先后多次受到山西省农垦局、大同市国资委的表彰,并当选大同市第十四届人大代表和大同市第十五届政协委员。

动态二进制翻译技术是一种对即将提交到CPU的指令进行即时反编译和重新编译的技术[4-5],用来获取即将执行的代码块中的读写指令和出栈入栈指令。

动态二进制翻译技术需构建翻译引擎和执行引擎。首先由翻译引擎获取将要执行的代码块,通过反编译将其解码成指令,利用翻译出来的指令获取指令、指令操作数及待分析的读写内存指令,并将编译后的分析代码加入到解码后的指令块中,从而形成新的指令块。随后将新的指令块提交给CPU执行,从而执行翻译和编译后的代码,当准备提交下一个指令块时,判断新的指令块是否为尚未翻译的模块,若是尚未翻译的模块,则进行翻译、分析指令插入和编译,从而形成新的指令块并进行分析。此外,若新的已被翻译的指令被频繁执行,则对其进行优化。如此发展,即可使所有的指令均被翻译、实时分析和优化。

动态二进制翻译可参照DigitalBridge设计方法[6]来设计,但本文仅在翻译X86指令之后加入分析指令,且分析指令多为查表指令,因此效率更高。图2为动态二进制翻译设计思路。

图2 动态二进制翻译设计思路

1.2.2 关键内存区域获取技术

关键内存区域获取技术是指获取要防护的关键内存的技术,本文主要依据可执行文件加载到内存中形成的映像得到关键内存区域。首先获取操作系统所有可执行文件的加载过程和可执行文件在内存中的映像位置;随后从映像中获取导出代码位置和可执行的代码,从而获取到可执行文件的内存区域;同时,还需获取操作系统卸载映像,并在卸载映像时准确获取卸载的映像位置及对应的区域,从而在关键内存区域摘除该区域。

本文重点对Windows映像进行研究。在Windows操作系统中,可执行文件是遵循Windows操作系统可执行文件的格式存储的。在计算机运行过程中,可执行文件的映像根据需要进行加载,可通过二进制翻译或其他方式获取文件的映像加载。文件加载到内存映像之后是线性连续的,加载的映像按照操作系统的页表进行连续分配,在分配过程中确保可执行代码页和数据页是分离的。此时可对可执行代码页和数据页进行优化,即在页表中将可执行代码页标准化,确保可执行代码能实时获取;同时,获取数据页中关键内存的存放区域,构建关键内存的区域存放,供后期检查时获取。通过二进制翻译或其他方式,在内存映像卸载时实时获取,确保文件卸载之后关键区域也能实时变化,从而使后期的判断不会失误。具体方法见图3。

图3 关键内存区域获取设计基础

1.2.3 栈内存区域获取技术

栈内存区域获取技术的主要设计思路是在动态二进制翻译过程中获取到实时栈区域的关键技术和睡眠线程栈获取技术。该技术的主要实现方法是在动态二进制翻译过程中获取导致出栈入栈的指令,并通过在CPU中的栈顶和栈底位置获取实时栈的位置及对栈顶位置进行标记,使下次入栈时能实时获取到上次的入栈位置及出栈后的返回位置,同时在每次入栈过程中和代码指令执行过程中不会出现修改此次入栈深度以外的栈数据的现象和在出栈过程中不会出现出栈改变的现象,因为出现这些现象代表发生栈溢出获取栈偏移现象,因此通过该设计能使栈溢出或栈偏移时实时被捕捉和获取。

1.3 试验结果和分析

为验证上述设计思路的有效性,本文通过在Windows XP中的内核上开展试验,验证通过动态二进制翻译对关键内存进行防护的有效性;同时,通过对二进制翻译和关键内存区域进行合理分配及对算法进行优化,使整体思路对系统的影响保持在30%以内。此外,通过病毒测试证明该方案对内存溢出和内存破坏攻击具有很好的防护效果。试验结果表明,该方案的设计思路可得到实现和推广。

1.3.1 有效性评估

为验证有效性,设置自主设计的栈溢出和内存破坏类病毒、metasploit中的栈溢出和内存破坏类病毒、学校病毒库中的相关病毒及其他有好单位的病毒库中的相关病毒进行测试。测试结果表明,可检测到溢出和破坏类病毒的比例达到90%以上,可有效实时阻止的病毒也达到60%以上,且大部分病毒得以阻止是由于检测之后因阻止病毒而造成系统奔溃。

1.3.2 性能评估

该方案的设计开销主要在动态二进制翻译和大量的内存区域比较上,通常动态二进制并加入分析代码会造成效率降低5%~15%,内存区域比较会造成效率降低约15%,因此可通过对动态二进制翻译作进一步优化,或直接在CPU内进行分析,使损失效率降到5%左右,甚至在2%以内(该损失效率是在与相关CPU设计人员和设计单位讨论损失后得出的)。比较效率若能通过算法进行优化(例如利用特征值比较等),亦能得到一定的提高。此外,若能对内存的分配处理进行优化,确保关键内存区域的物理连续性,将能带来飞跃级别的性能提升,但该方法需在能对源码进行控制的操作系统上实现。

2 结 语

本文通过对内存溢出和内存破坏的本质原因进行深入分析和研究,提出一种新的关键内存防护思路和方法。通过对操作内存的指令进行分析,辨别出针对内存溢出和关键内存破坏的指令并对其进行修改,从而阻止内存溢出和内存破坏的发生。同时,在Windows操作系统上对该方案进行测试,结果表明,本文设计的方案能有效识别和阻止相关类型的病毒攻击,具有较高的实用价值。

猜你喜欢

二进制指令代码
用二进制解一道高中数学联赛数论题
有用的二进制
《单一形状固定循环指令G90车外圆仿真》教案设计
有趣的进度
新机研制中总装装配指令策划研究
关于ARM+FPGA组建PLC高速指令控制器的研究
神秘的代码
一周机构净增(减)仓股前20名
一行代码玩完19亿元卫星
近期连续上涨7天以上的股