一种针对虚函数表劫持攻击的防御方法
【技术领域】
[0001]本发明属于应用程序技术领域,尤其涉及一种针对虚函数表劫持攻击的防御方法。
【背景技术】
[0002]内存破坏漏洞(memory corrupt1n bugs)广泛存在于使用C/C++等低级语言编写的程序中,栈溢出、堆溢出、释放后重用等漏洞均属于内存破坏漏洞。攻击者利用此类漏洞,可以控制应用程序内存中的数据、代码,改变程序行为甚至劫持程序的控制流。
[0003]现有技术中有以下两种处理方式:
[0004]VTGuard:VTGuard是部署在IE浏览器中的一项虚函数表保护技术。其基本思想是:在每个虚函数表中插入一个私密的cookie,并在虚函数被调用时进行检查,当前表中的cookie和对应的cookie是否一致,如果不一致则会禁止此次调用。该方案能够有效减少虚函数表重用攻击,但对虚函数表破坏和虚函数表注入攻击无效。
[0005]SafeDispatch:SafeDispatch是基于编译器的虚函数表劫持攻击防御方案,它首先对整个程序的类关系进行分析,推断出程序中有效的虚函数表集合及虚函数集合;接着在虚函数被调用时进行安全校验,检查当前虚函数及虚函数表是否在有效集合中,若不在则禁止此次调用。对于虚函数的检查,将带来7%的额外开销;对于虚函数表的检查,将带来30%的额外开销,且对虚函数表破坏攻击无效。
[0006]DieHard:DieHard提供了自定义的内存分配器,在进行内存分配时实现随机化及隔离。该技术方案在某种程度上对虚函数表劫持攻击有效,但存在不确定性。
[0007]但是上述方案中,均存在以下缺陷:有效性:VTGuard、SafeDispatch、DIeHard均无法保证对所有类型的虚函数表劫持攻击进行有效防护;二进制兼容:VTGuard、SafeDispatch以及DieHard均不二进制兼容,即需要源代码。而在实际中获取目标保护程序的源码是极其困难的;系统开销-SafeDispatch所带来的系统开销7与% 30)使其很难应用于实际中。
【发明内容】
[0008]为解决上述问题,本发明提供一种针对虚函数表劫持攻击的防御方法。本发明基于二进制重写技术,不需要源码即可完成部署;且能够有效防护程序中的重要对象,不受虚函数表劫持攻击的影响;而本发明所带来的系统开销也在可接受范围之内。
[0009]本发明的针对虚函数表劫持攻击的防御方法,其包括:
[0010]步骤一、构建有效虚函数表集合和有效虚函数集合;有效虚函数表集合用于存储虚函数表指针,虚函数表指针指向虚函数表;有效虚函数集合用于存储虚函数表,虚函数表用于存储虚函数指针,虚函数指针指向虚函数;
[0011 ] 步骤二、确定可执行程序中可能被虚函数表劫持攻击、需要被保护的对象和对象中的虚函数,分析得到虚函数数据的读取地址和虚函数的调用地址;其中,虚函数数据包括:虚函数表指针和虚函数表;同一个对象的不同虚函数数据采用相同读取地址,且虚函数数据中的虚函数表指针和虚函数表采用相同读取地址;
[0012]步骤三、在可执行程序的运行过程中,采用动态二进制插装方式,在虚函数数据的读取地址处插装备份回调函数,在虚函数的调用地址处插装校验回调函数;
[0013]步骤四、当可执行程序执行到某个对象X的虚函数数据对应的备份回调函数时,在该备份回调函数中,将对象X的虚函数表指针及其指向的虚函数表进行备份,其中虚函数表指针备份到有效虚函数表集合中,虚函数表备份到有效虚函数集合中;
[0014]步骤五、当可执行程序执行到某个虚函数对应的校验回调函数时,在校验回调函数中,检查被调用的虚函数所在的虚函数表的虚函数表指针Y是否在有效虚函数表集合中;
[0015]若虚函数表指针Y不在有效虚函数表集合中,则校验失败、拒绝调用虚函数,并立即终止该可执行程序;
[0016]若虚函数表指针Y在有效虚函数表集合中,则根据备份的有效虚函数表集合和有效虚函数集合,找到虚函数表指针Y指向的虚函数表Z;判断被调用的虚函数指针是否在虚函数表Z中,若在则校验成功,运行可执行程序调用虚函数,否则校验失败、拒绝调用虚函数,并终止该可执行程序。
[0017]进一步的,步骤四中备份后将备份数据所在的内存页的访问属性修改为只读。
[0018]有益效果:
[0019]本发明通过二进制插装技术,在对象实例化时插装代码对虚函数表指针及虚函数表进行备份;在对象的虚函数被调用时,依据当前虚函数表指针和虚函数指针与原有值进行比对以判断是否能够进行调用。通过这种方式,本发明在二进制层面对虚函数表进行了防护,有效保护对象不受虚函数表劫持攻击的影响。
【附图说明】
[0020]图1(a)为本发明的针对虚函数表劫持攻击的防御方法示意图;
[0021]图1(b)为本发明的备份数据示意图;
[0022]图1 (c)为本发明的校验过程流程图;
[0023]图2为可执行程序调用虚函数的代码示意图;
[0024]图3 (a)为本发明的实施例中对象d的类结构;
[0025]图3(b)为本发明的实施例中对象d的虚函数表内存布局。
【具体实施方式】
[0026]PE文件中有多个对象,其中部分对象的虚函数表易受到攻击者的攻击,夺取程序的控制流,执行危险代码,影响系统安全。
[0027]本发明技术方案如图1 (a)所示。首先,对待保护的PE文件进行预分析,得到需要保护对象的虚函数表的生成处及虚函数的调用处;接下来,在生成处及虚函数调用处进行插装,添加对目标程序的防护。为了对目标程序进行插装,需要通过预分析得到:1.虚函数表生成位置,以便进行插装进行数据备份;2.虚函数调用位置,以便进行插装在调用时做安全验证。目前有多种针对二进制文件的分析方法可以实现这个目标,包括自动分析平台、静态分析、动态分析等。
[0028]本发明的针对虚函数表劫持攻击的防御方法,其包括:
[0029]步骤一、构建有效虚函数表集合和有效虚函数集合;有效虚函数表集合用于存储虚函数表指针,虚函数表指针指向虚函数表;有效虚函数集合用于存储虚函数表,虚函数表用于存储虚函数指针,虚函数指针指向虚函数。
[0030]步骤二、确定可执行程序中可能被虚函数表劫持攻击、需要被保护的对象和对象中的虚函数,分析得到虚函数数据的读取地址和虚函数的调用地址;其中,虚函数数据包括:虚函数表指针和虚函数表;同一个对象的不同虚函数数据采用相同读取地址,且虚函数数据中的虚函数表指针和虚函数表采用相同读取地址;
[0031]其中获得虚函数调用地址的方式为:
[0032]通过网络获得攻击代码,修改攻击代码对虚函数指针或虚函数表指针的赋值语句,在可执行程序调用虚函数且该虚函数在被修改后的攻击代码攻击时,可执行程序报错,则可执行程序报错时可执行程序所执行的指令地址即为虚函数的调用位置。
[0033]获得虚函数数据的读取地址的方式为:
[0034]在可执行程序中分析虚函数调用时的代码,追踪该虚函数所属对象的数据流以确定对象的虚函数数据的读取位置。
[0035]步骤三、在可执行程序的运行过程中,采用动态二进制插装方式,在虚函数数据的读取地址处插装备份回调函数,在虚函数的调用地址处插装校验回调函数。
[0036]步骤四、当可执行程序执行到某个对象X的虚函数数据对应的备份回调函数时,在该备份回调函数中,将对象X的虚函数表指针及其指向的虚函数表进行备份,其中虚函数表指针备份到有效虚函数表集合中,虚函数表备份到有效虚函数集合中。
[0037]步骤五、当可执行程序执行到某个虚函数对应的校验回调函数时,在校验回调函数中,检查被调用的虚函数所在的虚函数表的虚函数表指针Y是否在有效虚函数表集合中;
[0038]若虚函数表指针Y不在有效虚函数表集合中,则校验失败、拒绝调用虚函数,并立即终止该可执行程序;
[0039]若虚函数表指针Y在有效虚函数表集合中,则根据备份的有效虚函数表集合和有效虚函数集合,找到虚函数表指针Y指向的虚函数表Z;判断被调用的虚函数指针是否在虚函数表Z中,若在则校验成功,运行可执行程序调用虚函数,否则校验失败、拒绝调用虚函数,并终止该可执行程序。
[0040]进一步的,步骤四中备份后将备份数据所在的内存页的访问属性修改
为只读。
[0041]图2中给出了对某程序反编译后(Intel语法)得到的调用虚函数的过程。在程序中调用虚函数包括三步:第一步为获得调用该虚函数的对象地址,然后获取该对象首地址处所存储的虚函数表地址(该虚函数表在内存中的起始地址),最终根据调用指令获得被调用的虚函数在虚函数表中的偏移量,根据该偏移量去调用该虚函数。其中,若该对象存在虚函数表,则其虚函数表位于该独享的前端。其中eax寄存器中存放的为对象首地址,ecx寄存器为虚函数表指针,其值为虚函数表的地址。从调用过程可以看出,无论虚函数表指针被篡改(虚函数表注入/重用攻击)或是虚函数表(虚函数表破坏攻击)被篡改,都将使得程序控制流完整性遭到破坏。
[0042]现假设通过预分析阶段得知,某对象在完成虚函数表的分配后将虚函数表地址(虚函数指针)存入eax寄存器中,此时的代码位置为set_address ;在call_addressL....call_addreslO处存在该对象的虚函数调用,调用指令为cal [ecx+14c]、call [ecx+20c]等。
[0043]在set_address地址处进行插装。备份寄存器eax中存储的虚函数表指针,并依次备份被调用的虚函数指针。被调用的虚函数指针可以通过调用指令获得其位于虚函数表中的位置,例如call[ecx+14c],则意味着在虚函数表中偏移量为14c处的虚函数被调用,需要进行备份。将所有备份的被调用的虚函数指针,称为有效虚函数表集合。虚函数表指针及虚函数指针备份在新申请的内存页中,当备份操作完成后,将当前页的属性设为只读。
[0044]有效性分析:本发明在虚函数调用时会对虚函数表指针进行校验,因此能够有效防御虚函数表重用攻击及虚函数表注入攻击;而对调用的虚函数指针的备份则保证了程序不受虚函数表破坏攻击的影响。同时,本发明将数据备份在内存的只读页中。在本发明所定义的威胁模型下,尽管攻击者扫描到了备份数据,也无法进行篡改。
[0045]上述虚函数表(virtual table,简称虚表或vtable):C++的动态多态是由虚函数(Vitrual Funct1n)实现的。每个含有虚函数的类都有一张虚函数表,表中的每一项是一个虚函数的地址,虚函数表解决了继承、覆盖的问题。
[0046]虚函数表劫持攻击(vtable hijacking attack)指通过篡改虚函数表或虚函数表指针(指向虚函数表的指针,其值为虚函数表起始地址),而达到劫持程序控制流目的的一类攻击。
[0047]对于被防护程序,本发明假设:被防护程序为PE格式文件;二进制文件没有进行代码混淆;程序由gcc、visual C++等主流编译器生成。
[0048]对象虚函数表内存布局:当使用父类的指针操作一个子类的时候,虚函数表就像一张地图,指明了实际应该调用的函数。通过遍历表中的函数指针,便可以调用相应的虚函数。图3(a)展示了对象d的类结构,图3(b)描述了对象d的虚函数表内存布局,从图中可以看出,每个父类有自己的虚表,子类的虚函数被放到了第一个父类(以声明顺序决定)的虚表中;被子类覆盖的虚函数放在虚表中原父类虚函数的位置,没有被覆盖的函数不变;如图3(b),对象的虚函数表指针位于对象内存布局中靠前的位置;图3(&)中Basel中依次声明了 f()、g()、h()三个虚函数,由图3(b)中Basel的虚函数表可以看出,虚函数按照其声明顺序放于表中;图3 (a) Derive类类图,该类为多重继承且子类覆盖了父类的一个虚函数f O ; (b) Derive类对象d的内存布局,虚函数表指针位于对象实例中靠前的位置,它指向该对象的各个虚函数表,父类虚函数表中的f()的位置被替换成了子类的函数指针。
[0049]虚函数表劫持攻击的主要方式包括:
[0050]1.虚函数表破坏(vtable corrupt1n):攻击者覆盖虚函数表中存储的虚函数指针来达到攻击目的。
[0051]2.虚函数表注入(vtable inject1n):攻击者覆盖虚函数表指针,令该指针指向由攻击者构造的虚函数表。这种方式可靠且高效,是攻击者最常采用的攻击方法。
[0052]3.虚函数表重用(vtable reuse):攻击者覆盖虚函数表指针,令该指针指向内存中已存在的虚函数表。此种方式利用难度高且并不稳定,目前并未在实际攻击中出现
[0053]二进制插装是指在二进制层面对程序进行修改,通过增加、删除、修改代码,达到增加功能、监视程序运行等目的。
[0054]本发明假设攻击者满足以下条件:
[0055]1.攻击者能够读取全内存,从而攻击者能够进行信息泄露攻击(informat1nleakage attacks),并绕过 ASLR(Adress space layout randomizat1n,通过对内存堆、栈等线性区布局的随机化,增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置的防御手段)等防御机制;
[0056]2.攻击者能够在所有可写内存页进行写操作,从而攻击者能够修改函数返回地址、虚函数表指针等重要数据,达到改变程序执行流的目的;
[0057]3.攻击者无法直接读取、写入寄存器;
[0058]上述假设已足够严格,满足真实世界中利用内存破坏漏洞所进行攻击时的条件;同时,利用内存破坏漏洞,攻击者也能够实现上述条件。
[0059]当然,本发明还可有其他多种实施例,在不背离本发明精神及其实质的情况下,熟悉本领域的技术人员当可根据本发明作出各种相应的改变和变形,但这些相应的改变和变形都应属于本发明所附的权利要求的保护范围。
【主权项】
1.一种针对虚函数表劫持攻击的防御方法,其特征在于,包括: 步骤一、构建有效虚函数表集合和有效虚函数集合;有效虚函数表集合用于存储虚函数表指针,虚函数表指针指向虚函数表;有效虚函数集合用于存储虚函数表,虚函数表用于存储虚函数指针,虚函数指针指向虚函数; 步骤二、确定可执行程序中可能被虚函数表劫持攻击、需要被保护的对象和对象中的虚函数,分析得到虚函数数据的读取地址和虚函数的调用地址;其中,虚函数数据包括:虚函数表指针和虚函数表; 步骤三、在可执行程序的运行过程中,采用动态二进制插装方式,在虚函数数据的读取地址处插装备份回调函数,在虚函数的调用地址处插装校验回调函数; 步骤四、当可执行程序执行到某个对象X的虚函数数据对应的备份回调函数时,在该备份回调函数中,将对象X的虚函数表指针及其指向的虚函数表进行备份,其中虚函数表指针备份到有效虚函数表集合中,虚函数表备份到有效虚函数集合中; 步骤五、当可执行程序执行到某个虚函数对应的校验回调函数时,在校验回调函数中,检查被调用的虚函数所在的虚函数表的虚函数表指针Y是否在有效虚函数表集合中; 若虚函数表指针Y不在有效虚函数表集合中,则校验失败、拒绝调用虚函数,并立即终止该可执行程序; 若虚函数表指针Y在有效虚函数表集合中,则根据备份的有效虚函数表集合和有效虚函数集合,找到虚函数表指针Y指向的虚函数表Z;判断被调用的虚函数指针是否在虚函数表Z中,若在则校验成功,运行可执行程序调用虚函数,否则校验失败、拒绝调用虚函数,并终止该可执行程序。2.如权利要求1所述的针对虚函数表劫持攻击的防御方法,其特征在于,步骤四中备份后将备份数据所在的内存页的访问属性修改为只读。
【专利摘要】本发明提供一种针对虚函数表劫持攻击的防御方法,其包括:构建有效虚函数表集合和有效虚函数集合;确定可执行程序中需要被保护的对象和对象中的虚函数,分析得到虚函数数据的读取地址和虚函数的调用地址;可执行程序的运行过程中在虚函数数据的读取地址处插装备份回调函数,在虚函数的调用地址处插装校验回调函数;对虚函数表指针及其指向的虚函数表进行备份;根据备份的虚函数表指针及其指向的虚函数表进行校验,并根据校验结果进行虚函数的执行与否。本发明基于二进制重写技术,不需要源码即可完成部署;且能够有效防护程序中的重要对象,不受虚函数表劫持攻击的影响;而本发明所带来的系统开销也在可接受范围之内。
【IPC分类】G06F21/57
【公开号】CN104881610
【申请号】CN201510333581
【发明人】胡昌振, 王勇, 闫海林, 冉宇辰, 杨亚峰
【申请人】北京理工大学
【公开日】2015年9月2日
【申请日】2015年6月16日
转载请注明原文地址:https://www.famiwei.com/read-8138466.html