一种堆栈溢出的保护方法和装置的制作方法

文档序号:6431805阅读:148来源:国知局
专利名称:一种堆栈溢出的保护方法和装置的制作方法
技术领域
本发明涉及计算机领域,尤其涉及一种堆栈溢出的保护方法和装置。
背景技术
计算机技术和互联网的建设和发展,对整个社会的经济、文化、科技等各方面带来了巨大的推动和冲击,大量电信、电子商务、金融网络等信息化系统已经成为国家和政府的关键基础设施,因此如何确保计算机系统的安全已成为摆在我们面前迫切需要解决的难题。堆栈溢出漏洞是一个极其严重的系统安全漏洞,它是通过向一个有限的内存空间写入过长的数据,破坏系统的内存空间,导致系统运行异常、死机或重启。通过堆栈溢出攻击,使用攻击代码的地址覆盖函数指针,可以让攻击者获取部分或全部的系统控制权,这是一种极具威胁的安全隐患。如图1所示,系统内存一般分为5种,代码段code用于存放程序的执行代码,数据段data用于存放初始化的全局变量和静态变量,bss数据段用于存储非初始化的全局变量和静态变量,剩余的内存空间用于系统堆栈使用,堆用于存放系统运行时内存大小未知的对象(通常用malloc分配),使用完后释放(通常用free释放),栈则用于系统运行时“保存现场”,存放临时创建的局部变量,在函数调用时保存参数、返回地址等(通常用PUSH保存),等函数返回时弹出返回所需要的数据(通常用POP弹出)。在内存中堆和栈没有确定的界限,根据程序运行动态变化。堆从低地址往高地址生长,栈则相反。无论是堆溢出还是栈溢出,都会覆盖掉其他堆栈区域的数据,如果被覆盖的数据对于系统运行是至关重要的,那么将严重影响系统的正常工作。如果堆中保存了程序运行的函数指针,该堆中的数据如果被覆盖,可以导致系统运行到错误的地址上。图2所示的是父函数调用子函数后的栈分布图,父函数和子函数都有自己的栈空间,EBP(基址指针,base pointer)和ESP(堆栈指针,stack pointer)分别表示当前栈的底部和顶部指针。函数调用过程中,首先将参数压入堆栈中,然后EBP入栈,然后是子函数的局部变量等。局部数据溢出时,若使用精心设计好的数据(如某段攻击函数的地址)覆盖堆栈中保存的返回指针,那么就可以控制代码的跳转和程序的运行。堆栈溢出对系统危害极大,目前解决堆栈溢出保护问题的方法有多种,最简单的就是保证代码的质量,如积极进行手动的边界检查和函数指针检查;不允许执行堆栈中的命令;采用良好的编码习惯,限制使用系统中存在溢出漏洞的接口函数(如字符拷贝、格式化等),但这种方法只能尽可能的减少堆栈溢出的几率,不能从根本上消除。另一种是通过编译器自动对代码进行优化,调整变量的位置,使容易发生溢出的数据尽可能的远离重要数据(如函数指针、返回地址等),这也只能减轻堆栈溢出对系统的危害,无法消除堆栈溢出,更无法减少堆栈溢出的几率。目前的堆栈溢出保护实现大多使用基于Canaries的探测技术来完成对这种破坏的检测。Canaries探测方法在检测堆栈对函数栈的破坏时,分别在堆和栈插入Canaries缓冲区。这样如果堆栈在遭到无意或故意的溢出时,首先修改的是Canaries缓冲区,通过对该缓冲区的检查可以判断出是否发生了溢出,防止继续溢出破坏函数栈的控制信息,如图3 所示。生成Canaries的方法目前有以下种一种是采用固定的特殊字符串填充,通过检查该字符串是否被修改确定是否发生溢出,固定字符串一般选择空格、换行等特殊意义的字符串。该方法虽然可以检查到溢出, 但使用固定字符填充容易被攻击者查出Canaries的位置,并跳过该缓冲区直接修改其后的数据,这种情况下溢出保护就无效了。第二种方法是生成随机数,并保存在一块未被隐射到虚拟地址空间的内存页中, 试图通过指针访问保存随机数的内存时就会发生段错误(segment fault),但这个随机数最终会作为Canaries保存在函数栈中,所以攻击者仍然有机会获取该随机数的值。第三种方法是通过随机数和函数栈中的所有控制信息、返回地址通过运算得到缓冲区填充值,这样函数栈中Canaries、控制信息、返回地址等的修改均可以检查到。但这种方法运算涉及的量多,计算Canaries消耗太大。

发明内容
本发明提供了一种堆栈溢出的保护方法,在提高堆栈溢出防护能力的同时,避免计算过于复杂度的问题。本发明采取的技术手段是一种堆栈溢出的保护方法,方法包括在堆栈的缓冲区内填充格式为“固定字符串+随机字符串”或“随机字符串+固定字符串”的填充字符串的步骤;每隔预定的周期检查缓冲区内的填充值是否发生变化。其中,在堆栈缓冲区内填充所述填充字符串之前还包括有生成长度和内容均随机的随机字符串的步骤;以及,申请堆栈,并在栈内数据和控制信息间插入缓冲区,在堆数据的两端插入缓冲区的步骤。进一步,所述随机字符串每个字符的取值从0-255随机生成;固定字符串为长度固定的,且包含0x00(' \0')和0x0a(' \a')字符的字符串,例如0x000a、0x0a00、 0x00000a 等等。进一步,所述缓冲区的长度为“固定字符串+随机字符串”长度的整数倍,或“随机字符串+固定字符串”长度的整数倍。进一步,所述堆的申请及插入缓冲区的步骤包括申请一片一定长度的堆内存;申请两片内存分别作为缓冲区,将其中一片内存指向所述堆内存首部地址,将另一片内存指向所述堆内存的底部地址。进一步,所述方法还包括释放堆时的检查步骤对堆的前后两块缓冲区的填充值进行检查,若填充值被修改则提示堆溢出,不进行堆释放;若填充值未被修改则释放堆及堆缓冲区;以及释放栈时的检查步骤
对栈的缓冲区的填充值进行检查,若填充值被修改则不执行栈底指定的返回地址,若填充值未被修改则释放栈及栈缓冲区。进一步,除每隔预定的周期检查缓冲区内的填充值外,还对栈底地址、栈底内容、 返回地址和基址指针的值、栈的大小进行检查。

本发明还提供了一种堆栈溢出的保护装置,包括用于在堆栈的缓冲区内填充格式为“固定字符串+随机字符串”或“随机字符串+ 固定字符串”的填充字符串的缓冲区填充模块;以及,用于每隔预定的周期检查缓冲区内的填充值是否发生变化的检查模块。所述保护装置进一步包括用于生成长度和内容均随机的随机字符串的随机字符串生成模块、申请堆栈的堆栈申请模块以及在栈内数据和控制信息间插入缓冲区的栈缓冲区插入模块和在堆数据的两端插入缓冲区的堆缓冲区插入模块。所述随机字符串每个字符的取值从0-255随机生成;固定字符串为长度固定的, 且包含0x00和OxOa字符的字符串。所述缓冲区的长度为“固定字符串+随机字符串”长度的整数倍,或“随机字符串 +固定字符串”长度的整数倍。所述堆栈申请模块用于在堆的申请时申请一片长度为“Len+2*bUfLen”的堆内存;所述堆缓冲区插入模块用于在对堆插入缓冲区时定义堆头部缓冲区指针、实际堆内存指针和堆尾部缓冲区指针;并且,将堆头部缓冲区的指针指向堆内存的首部地址, 将实际堆内存指针指向首部地址+bufLen的位置,将堆尾部缓冲区的指针指向首部地址 +bufLen+Len 的位置。进一步,所述保护装置还包括释放堆栈的堆栈释放模块;所述检查模块进一步用于在释放堆栈时对堆的前后两块缓冲区的填充值进行检查,若填充值被修改则提示堆溢出,堆栈释放模块不进行堆释放;若填充值未被修改则堆栈释放模块释放堆及堆缓冲区; 所述检查模块还用于在释放栈时的对栈的缓冲区的填充值进行检查,若填充值被修改则不执行栈底指定的返回地址,若填充值未被修改则释放栈及栈缓冲区。进一步,所述检查模块进一步用于对栈底地址、栈底内容、返回地址和基址指针的值、栈的大小进行检查。本发明的有益效果是采用固定字符串与随机字符串的结合作为填充缓冲区的特殊填充字符串,除了能达到分别采用固定字符串或随机字符串作为填充缓冲区的填充字符串的效果外,由于随机字符串的内容和长度的随机性,使得填充字符串的整体长度和内容不易被攻击者所得到;再者,固定字符串一般选择空格、换行等特殊意义的字符串,使得攻击者在获取填充字符串内容时更为困难。优选的,固定字符串包含OxOOC \0')和 OxOaC W )字符,由于0x00字符’ \0’是字符串结束符,字符串相关的操作对该缓冲区是无效的,即无法通过系统对缓冲区做字符串操作;其次,OxOa是换行符,无法通过标准输入流读取函数获得缓冲区的内容。如果攻击者知道存在Canaries并想跳过该缓冲区对后面的控制信息进行修改,那么就必须计算该缓冲区的起始位置,而缓冲区采用这些特殊字符后,将会给攻击者分析缓冲区制造很大的麻烦;进一步的,在释放堆时,对堆的缓冲区的填充值进行检查,也进一步增强了堆栈溢出的保护。


图1为系统内存分布示意图;图2为函数调用的堆栈分布图;图3为插入缓冲区的栈结构示意图;图4为本发明一种堆栈溢出保护方法的流程示意图;图5为申请堆及堆缓冲区流程示意图;图6为具有缓冲区的堆结构示意图;图7为释放堆流程示意图;图8为本发明一种堆栈溢出保护装置的结构示意图。
具体实施例方式以下结合附图对本发明的原理和特征进行描述,所举实例只用于解释本发明,并非用于限定本发明的范围。作为本发明一种堆栈溢出的保护方法的实施例,包括生成随机字符串的步骤;申请堆栈的步骤;在缓冲区填充字符串的步骤;检查堆栈的步骤以及释放堆栈的步骤,具体如图4所示。生成随机字符串生成一串长度和内容均随机的字符串,作为填充缓冲区的一部分。字符串长度的上限可以根据设备性能与实际应用结合确定,每个字符的取值从0-255 随机生成;申请堆栈堆的申请使用malloc进行操作,通过对malIoc函数的封装,可实现申请堆时插入缓冲区。插入缓冲区的方法可以灵活,本实施例采用的方法如图5所示,申请长度为Len+2*bufLen的堆内存,其中Len为实际堆内存长度,bufLen为缓冲区内存长度,分别定义堆头部缓冲区指针sigl、实际堆内存指针ptr和堆尾部缓冲区指针sig2,将堆头部缓冲区的指针指向堆内存的首部地址,将实际堆内存指针指向首部地址+bufLen的位置, 将堆尾部缓冲区的指针指向首部地址+bufLen+Len的位置。这样就形成由ptr指向的长度为Len实际堆内存,以及在头和尾部的两块长度为bufLen的缓冲区。具体的定义指针实现命令如下Meminfo_tChar*sigl ;Char^ptr ;Chartsig2 ;其中,Len是length的缩写,是长度的意思;buf是buffer的缩写,是缓冲的意思。 长度为Len+2*bufLen的堆内存,Len为实际堆内存的长度,2*bufLen为2个缓冲区的长度。这样就在堆内存的头和尾处形成了缓冲区,如图6所示。缓冲区的长度buflen可选择需要填入的字符串的整数倍,具体的长度可根据设备性能和实际应用综合考虑。栈的申请可由编译器完成对栈缓冲区的添加。在缓冲区填充字符串在缓冲区内填充格式为“固定字符串+随机字符串”或“随机字符串+固定字符串”的填充字符串。其中,固定字符串优选的为0X000a,0X00字符’\0’是字符串结束符,字符串相关的操作对该缓冲区是无效的,即无法通过系统对缓冲区做字符串操作,从而防止如返回地址等重要指针和数据被覆盖;OxOa是换行符,无法通过标准输入流读取函数获得缓冲区的内容;固定字符串的选择也可以为包含OxOOOa的其他固定字符串,例如 0x000a、0x0a00、0x00000a,0x00050a 等等。检查堆栈每隔预定的周期检查缓冲区内的填充值,优选的,除检查缓冲区的填充值外,对栈底地址、栈底内容、返回地址和EBP的值、栈的大小等进行检查,这些内容可以从操作系统中获得,进一步实现堆栈溢出的保护。释放堆栈堆的释放使用free进行操作,通过对free函数的封装,可实现在释放堆时对堆内存前后两个缓冲区内填充值的检查,具体流程如图7所示。在释放ptr指向的实际堆内存时,检查堆内存头和尾部的缓冲区sigl和sig2两块缓冲区内的填充值是否与初始填充字符串相同,若不同则进行堆溢出告警,若相同则释放sigl和sig2以及ptr指向的堆内存。栈的释放同样可由编译器决定如何处理,编译器添加对栈缓冲区的添加、填充和释放操作后,若发现栈的缓冲区被修改,那么将不执行栈底指定的返回地址。如图8所示,本发明还提供了一种堆栈溢出保护装置,包括随机字符生成模块、堆栈申请模块、栈缓冲区插入模块和堆缓冲区插入模块,以及缓冲区填充模块、检查模块和堆栈释放模块。其中,随机字符生成模块用于生成长度和内容均随机的随机字符串,随机字符串的每个字符的取值从0-255随机生成;堆栈申请模块用于申请堆栈,在本实施例中,在堆的申请时,申请一片长度为 "Len+2*bufLen"的堆内存,其中Len为实际堆内存长度,bufLen为缓冲区内存长度;栈缓冲区插入模块用于在栈内数据和控制信息间插入缓冲区;堆缓冲区插入模块用于在堆数据的两端插入缓冲区,在本实施例中,堆缓冲区插入模块在对堆插入缓冲区时定义堆头部缓冲区指针、实际堆内存指针和堆尾部缓冲区指针;并且,将堆头部缓冲区的指针指向堆内存的首部地址,将实际堆内存指针指向首部地址 +bufLen的位置,将堆尾部缓冲区的指针指向首部地址+bufLen+Len的位置;缓冲区填充模块用于在堆栈的缓冲区内填充格式为“固定字符串+随机字符串” 或“随机字符串+固定字符串”的填充字符串,优选的,固定字符串为长度固定的,且包含 0x00 和 OxOa 字符的字符串,例如,0x000a、OxOaOO、0x00000a,0x00050a 等等。检查模块用于每隔预定的周期检查缓冲区内的填充值、在释放堆栈时对堆的前后两块缓冲区的填充值进行检查,在填充值被修改时提示堆溢出,并还用于对栈底地址、栈底内容、返回地址和基址指针的值、栈的大小进行检查;检查模块进一步用于在释放栈时的对栈的缓冲区的填充值进行检查。堆栈释放模块用于释放堆栈,并在检查模块对堆缓冲区填充值判断为堆溢出时不进行堆释放;并在检查模块对栈缓冲区填充值判断为被修改时不执行栈底指定的返回地址,若填充值未被修改则释放栈及栈缓冲区。本发明所述的堆栈溢出保护装置,可以理解为由计算机程序实现的虚拟装置,相应地,其包括的各个功能性模块即可理解为该虚拟装置中的组成部分;进一步地,各模块能够分别执行多种操作,那么针对由同一个调度子系统所执行的多种操作来说,还可以在该模块中存在相应的子模块,本文为了简化说明,不再一一列举这些子模块。对于多种操作如何实现包括判断、生成等,以及各模块之间如何交互的具体方式, 本领域技术人员可以利用计算机程序实现,本文不再赘述。以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明保护的范围之内。
权利要求
1.一种堆栈溢出的保护方法,其特征在于,方法包括在堆栈的缓冲区内填充格式为“固定字符串+随机字符串”或“随机字符串+固定字符串”的填充字符串的步骤;每隔预定的周期检查缓冲区内的填充值是否发生变化。
2.根据权利要求1所述的方法,其特征在于,在堆栈缓冲区内填充所述填充字符串之前还包括有生成长度和内容均随机的随机字符串的步骤;以及,申请堆栈,并在栈内数据和控制信息间插入缓冲区,在堆数据的两端插入缓冲区的步马聚ο
3.根据权利要求1所述的方法,其特征在于,所述随机字符串每个字符的取值从0-255 随机生成;固定字符串为长度固定的,且包含0x00和OxOa字符的字符串。
4.根据权利要求1所述的方法,其特征在于,所述缓冲区的长度为“固定字符串+随机字符串”长度的整数倍,或“随机字符串+固定字符串”长度的整数倍。
5.根据权利要求2所述的方法,其特征在于,所述堆的申请及插入缓冲区的步骤包括 申请一片长度为“Len+2*bufLen”的堆内存,其中Len为实际堆内存长度,bufLen为缓冲区内存长度;定义堆头部缓冲区指针、实际堆内存指针和堆尾部缓冲区指针; 将堆头部缓冲区的指针指向堆内存的首部地址,将实际堆内存指针指向首部地址 +bufLen的位置,将堆尾部缓冲区的指针指向首部地址+bufLen+Len的位置。
6.根据权利要求1所述的方法,其特征在于,所述方法还包括释放堆时的检查步骤 对堆的前后两块缓冲区的填充值进行检查,若填充值被修改则提示堆溢出,不进行堆释放;若填充值未被修改则释放堆及堆缓冲区; 以及释放栈时的检查步骤对栈的缓冲区的填充值进行检查,若填充值被修改则不执行栈底指定的返回地址,若填充值未被修改则释放栈及栈缓冲区。
7.根据权利要求1所述的方法,其特征在于,除每隔预定的周期检查缓冲区内的填充值外,还包括对栈底地址、栈底内容、返回地址和基址指针的值、栈的大小进行检查的步骤。
8.一种堆栈溢出的保护装置,其特征在于,包括用于在堆栈的缓冲区内填充格式为“固定字符串+随机字符串”或“随机字符串+固定字符串”的填充字符串的缓冲区填充模块;以及,用于每隔预定的周期检查缓冲区内的填充值是否发生变化的检查模块。
9.根据权利要求8所述的保护装置,其特征在于,所述保护装置进一步包括用于生成长度和内容均随机的随机字符串的随机字符串生成模块、申请堆栈的堆栈申请模块以及在栈内数据和控制信息间插入缓冲区的栈缓冲区插入模块和在堆数据的两端插入缓冲区的堆缓冲区插入模块。
10.根据权利要求8所述的保护装置,其特征在于,所述随机字符串每个字符的取值从 0-255随机生成;固定字符串为长度固定的,且包含0x00和OxOa字符的字符串。
11.根据权利要求8所述的保护装置,其特征在于,所述缓冲区的长度为“固定字符串 +随机字符串”长度的整数倍,或“随机字符串+固定字符串”长度的整数倍。
12.根据权利要求9所述的保护装置,其特征在于,所述堆栈申请模块用于在堆的申请时申请一片长度为“Len+2*bufLen”的堆内存,其中Len为实际堆内存长度,bufLen为缓冲区内存长度;所述堆缓冲区插入模块用于在对堆插入缓冲区时定义堆头部缓冲区指针、实际堆内存指针和堆尾部缓冲区指针;并且,将堆头部缓冲区的指针指向堆内存的首部地址, 将实际堆内存指针指向首部地址+bufLen的位置,将堆尾部缓冲区的指针指向首部地址 +bufLen+Len 的位置。
13.根据权利要求8所述的保护装置,其特征在于,所述保护装置进一步包括释放堆栈的堆栈释放模块;所述检查模块进一步用于在释放堆栈时对堆的前后两块缓冲区的填充值进行检查,若填充值被修改则提示堆溢出,堆栈释放模块不进行堆释放;若填充值未被修改则堆栈释放模块释放堆及堆缓冲区;所述检查模块还用于在释放栈时的对栈的缓冲区的填充值进行检查,若填充值被修改则不执行栈底指定的返回地址,若填充值未被修改则释放栈及栈缓冲区。
14.根据权利要求8所述的保护装置,其特征在于,所述检查模块进一步用于对栈底地址、栈底内容、返回地址和基址指针的值、栈的大小进行检查。
全文摘要
本发明提供了一种堆栈溢出的保护方法,通过在堆栈中插入缓冲区,并在缓冲区内填充“固定字符串+随机字符串”或“随机字符串+固定字符串”的格式的填充字符串,并在堆栈释放时对缓冲区内填充值进行检查,解决了堆栈溢出漏洞防攻击能力差的问题,进而减小了攻击者利用堆栈溢出漏洞对系统进行破坏的风险。本发明还包括一种堆栈溢出的保护装置。
文档编号G06F21/02GK102298677SQ20111025117
公开日2011年12月28日 申请日期2011年8月29日 优先权日2011年8月29日
发明者宋卿 申请人:瑞斯康达科技发展股份有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1