二进制程序循环写内存安全漏洞的检测方法

文档序号:6369143阅读:239来源:国知局
专利名称:二进制程序循环写内存安全漏洞的检测方法
技术领域
本发明涉及计算机软件安全分析领域,尤其涉及一种二进制程序循环写内存安全漏洞的检测方法。
背景技术
二进制程序中的缓冲区溢出漏洞通常发生在复杂的循环结构中。当二进制程序的代码含有嵌套循环时,通常会有复杂的代码之间的交互,而这类代码可能更易于含有潜在的安全漏洞。例如二进制程序循环写内存安全漏洞,该安全漏洞是指在循环写内存时,没有考虑内存区间的边界导致的内存访问越界。目前,通常采用静态分析技术对二进制程序循环写内存安全漏洞进行检测。其工作原理是,利用静态的符号执行技术生成测试数据,遍历二进制程序循环结构的所有路径,将循环结构进行明确数目的展开或近似的展开来逼近循环。对于真实的应用程序来说,展开循环在计算上的代价是很昂贵的。二进制程序循环结构的路径数目可能非常巨大,比如,如果一个单循环的迭代次数依赖于一些无界的输入,可能导致该二进制程序循环结构的可行路径也是无限增长的,因此二进制程序中的循环结构是进行静态分析的瓶颈。另外,有些包含在循环结构内部的安全漏洞在循环执行到一定次数时才被触发。采用符号执行技术在解析汇编指令时,将循环结构按照预定的次数进行展开,如果预定的次数小于安全漏洞的触发次数,则无法检测到隐含在循环结构内部的安全漏洞。

发明内容
本发明的目的在于,提供一种二进制程序循环写内存安全漏洞的检测方法,从而解决静态分析技术存在的缺陷。本发明的目的通过以下方式实现一种二进制程序循环写内存安全漏洞的检测方法,包括步骤I、获取与二进制程序中潜在安全漏洞相关的二进制程序的循环结构摘要信息;步骤2、根据所述循环结构摘要信息,生成测试数据;步骤3、根据所述测试数据对二进制程序进行循环写内存安全漏洞的检测。本发明实施例提供的方法,在生成测试数据时,不需要遍历二进制程序循环结构的所有路径,仅需要根据生成的循环结构摘要信息得到测试数据。由于循环结构摘要信息是和二进制程序的潜在安全漏洞相关的,因此,生成的测试数据更有针对性,大大降低了展开循环的计算代价。


图I为本发明实施例提供的方法流程图;、
图2为本发明实施例提供的方法对应的系统工作流程图。
具体实施例方式本发明提供了一种二进制程序循环写内存安全漏洞的检测方法,其实现方式如图I所示,包括如下操作步骤I、获取与二进制程序中潜在安全漏洞相关的二进制程序的循环结构摘要信息;步骤2、根据所述循环结构摘要信息,生成测试数据;步骤3、根据所述测试数据对二进制程序进行循环写内存安全漏洞的检测。本发明实施例提供的方法,在生成测试数据时,不需要遍历二进制程序循环结构的所有路径,仅需要根据生成的循环结构摘要信息得到测试数据。由于循环结构摘要信息是和二进制程序的潜在安全漏洞相关的,因此,生成的测试数据更有针对性,大大降低了安 全漏洞检测的计算代价。另外,基于循环结构摘要信息生成测试数据,不需要对循环进行展开,也就避免了无法检测到隐含在循环结构内部的安全漏洞的问题。本发明实施例提供的检测方法中,获取二进制程序的循环结构摘要信息的具体实现方式为首先从二进制程序控制流图中最内部的循环结构开始,依次向外展开,分别对有内存写操作的循环结构生成单循环结构的摘要信息;获取单循环结构的摘要信息的集合,所述单循环结构的摘要信息的集合就是二进制程序的循环结构摘要信息。其中,所述单循环结构的摘要信息包括循环结构的起始地址、循环结构的结束地址、控制循环体的循环次数的变量、循环写内存的缓冲区变量、所述缓冲区的数据的来源变量、输入文件中的关键字节相对于输入文件的文件头的偏移地址。因此,对于二进制程序中复杂的嵌套循环结构来说,最终会归结为单循环结构的摘要信息的生成。二进制程序的循环结构摘要信息是单循环结构的摘要信息的集合。本发明实施例中,单循环结构的摘要信息的生成依赖于二进制程序中循环结构的识别和动态的数据结构重构。动态的数据结构重构不需要源码,不依赖于关于二进制程序的任何注释信息。相应的,在生成单循环结构的摘要信息之前,本发明实施例提供的方法还包括如下操作步骤11、对所述二进制程序的循环结构进行识别;步骤12、基于识别出的循环结构,对二进制程序进行动态数据结构重构。本发明实施例提供的方法可以抽象地认为由各个功能模块来实现相应的步骤。具体的可以包括以下模块二进制程序循环识别模块、动态数据结构重构模块、循环结构摘要信息生成模块、测试数据生成模块、和二进制程序执行监控模块。相应的,本发明实施例提供的方法可以由图2所示的系统工作流程图来表示。二进制程序循环识别模块二进制程序循环识别模块用于实现上述步骤11。二进制程序循环识别模块是基于IDAPro (Interactive Disassembler,反汇编工具)的插件。本发明实施例中,二进制程序循环识别模块对二进制程序的循环结构进行识别的具体实现方式可以是步骤111、初始化一个回边链表和一个循环结构链表,所述回边链表和所述循环结构链表的初始值均为空;步骤112、查找所述二进制程序控制流图中的所有回边,将查找到的回边集合保存在所述回边链表中;步骤113、顺序遍历保存了回边集合的回边链表,得到一条回边,记为NodeBB- >NodeSB。将NodeSB标记为I (I表示已访问过,0表示为访问过),以NodeBB为起点,在控制流图中作反向的深度遍历;步骤114、反向的深度遍历经过的节点、NodeBBjP NodeSB组成了一个循环结构,将该循环结构添加到所述的循环结构链表中;步骤115、判断对回边链表的遍历是否到达回边链表尾,如果是,则完成循环结构的识别,否则,返回步骤113。通过上述操作,完成了对二进制程序中循环结构的识别,并把循环结构的识别结 果保存在循环结构链表中。循环结构链表中每个结点保存有循环结构的起始地址、循环结构的结束地址、表示控制循环体的循环次数的变量等信息。动态数据结构重构模块动态数据结构重构模块用于实现上述步骤12。动态数据结构重构模块建立在PIN 的基础之上,PIN是一个可以动态进行插桩的框架。动态数据结构重构模块利用PIN的例程插桩能力来监控二进制程序的执行过程,并在二进制程序的执行过程中重构和恢复二进制程序中关键数据结构的布局信息和相关的语义信息,同时跟踪二进制程序输入文件在二进制程序中的传递过程。在描述动态数据结构重构模块的工作流程之前,先对需要用到的概念进行简单说明MemAddrconset :内存地址MemAddr的约束集合,是指和内存地址MemAddr有相同数据类型的所有内存地址的集合;TypeSet :类型集合,是内存地址(该内存地址是指用来保存不同数据类型的内存地址)的已解析过的数据类型的集合(包括句法结构和语义类型);TimeTag:时间标签集合,记录变量在某个内存地址出现的时间,时间标签TimeLable的引入是为了区别相同的内存地址可能被不同变量重用的现象;threadld :表示一个线程的 ID ;regStype :表示寄存器的类型。为了进一步从内存或者寄存器恢复变量的类型,对每一个变量实例使用一个三元数组〈memAddr, timeLable, threadld〉(或者〈regStype, timeLable, thredld〉)来表不,该三元数组在程序的执行过程中被不断更新。动态数据结构重构模块对二进制程序进行动态的数据结构重构的具体实现方式包括如下操作步骤121、记录输入文件读入内存的起始位置和读入的字节数,将读入内存的字节标记为数据污染源;其中,输入文件读入内存的起始位置为进行动态数据结构重构的起始点StartAddr ;
该步骤具体可以通过PIN提供的API函数实现。如PIN_AddSyscallEntryFunction (其功能是注册一个回调函数,该回调函数在一个系统调用之前被立即执行),PIN_AddSyscallEXit(其功能是注册一个回调函数,该回调函数在一个系统调用执行完以后被立即执行)挂钩Windows的一些读文件的底层系统函数NtReadFile,NtCreateFile等等来实现。然后使用PIN_GetSysealIArgument (其功能是在明确的上下文环境中获取被执行的系统调用的参数值)和PIN_GetSyScalIReturn (其功能是在明确的上下文环境中获取一个刚返回的系统调用的返回值)获取输入文件读入内存的起始位置和读入的字节数,标记该内存范围的字节为数据污染源。步骤122、定义一个记录污染数据传递的链表pTaintList,初始化为NULL。从起始点StartAddr处开始解析汇编指令,解析的过程如下步骤123、抽取当前的汇编指令的类型INSTYPE ;
对不同的汇编指令类型使用不同的方法进行解析,如果当前的汇编指令是危险函数调用类型的指令,则执行步骤124,如果当前的汇编指令不是危险函数调用类型的指令,则执行步骤125。步骤124、抽取当前的汇编指令调用的危险函数的参数,得到一个该危险函数的参数列表,对该危险函数的参数列表进行变量的数据结构逆向数据流跟踪分析获取该危险函数的参数列表中参数变量的三元数组信息,并查找记录污染数据传递的链表pTaintList,判断该参数变量的参数值是否在该链表pTaintList中,如果在,则输出该危险函数调用地址、该危险函数的参数列表,和该参数列表相关联的输入文件中的关键字节相对于输入文件的文件头的偏移地址等相关信息,然后EIP(寄存器地址)+1(即跳转到下一条汇编指令),返回步骤123继续执行,如果不在,则EIP+1,返回步骤123继续执行。本发明实施例中所述的输入文件的关键字节指的是输入文件中的字节,这些字节在二进制程序的执行过程中传递到控制循环写内存的变量或者是作为控制循环执行次数的变量,或者是传递到循环结构中调用的危险函数,并且作为该危险函数的输入参数。步骤125、判断当前的汇编指令的操作数的变量值是否被污染如果该汇编指令的操作数的变量值直接来自数据污染源或来自记录污染数据传递的链表pTaintList,则变量值被污染,更新目的操作数的污染状态信息(将新的污染状态信息替换掉原来的污染状态信息),并把更新后的污染状态信息添加入记录污染数据传递的链表pTaintList,EIP+1,返回步骤123继续执行;如果该汇编指令的操作数的变量值不是直接来自数据污染源且不是来自记录污染数据传递的链表pTainList,则变量值没有被污染,EIP+1,返回步骤123继续执行。步骤126、执行完所有的汇编指令,如果程序正常退出,数据结构动态重构结束。在步骤126中,如果程序没有正常退出,导致被测程序出现异常,则记录当前使用的测试数据,该测试数据会触发二进制程序中安全漏洞的可能性较大。数据结构动态重构完成后,得到记录污染数据在二进制程序中的传递过程,以及二进制程序中关键的数据结构。其中,记录污染数据在二进制程序中的传递过程以记录污染数据传递的链表pTaintList形式体现;二进制程序中关键的数据结构主要和循环结构中调用的危险函数的输入参数相关。常见的危险函数有MultiByteToWideChar, bcopy、memccpy、memset、strncat、getwd、gets、_getws> strcpy、wcscpy、_mbscpy> IstrcpyA、lstrcpyff> strcat、wcscat、_mbscat、IstrcatA> lstrcatff> strncpy、wcsncpy、_mbscbcpy> IstrcpynA、lstrcpynff>strncat、wcsncat、_mbsnbcat、memcpy、memmove、CopyMemory、MoveMemory> printf>fprintf> sprintf> wprintf> fwprintf> swprintf> vprintf> vfprintf vsprintf>vwprintf> vfwprintf> vswprintf> scanf> fscanf> sscanf> wscanf> fwscanf> swscanf>wsprintfA、wsprintfW。影响污染数据传递的汇编指令有以下类型Mov类型的汇编指令,如mov、movd、movq,等约20条;一元操作数类型的汇编指令,如and、xor、or、inc、dec、neg,等等;跳转类的汇编指令,如jmp、jz,等等;栈操作汇编指令集,如pop、push、pusha,等等;其它汇编指令 集,如xchg、cbw、cwd、cwde,等汇编指令;其它的二元操作数类型的汇编指令,如add、sub汇编指令集、比较运算汇编指令集、乘除运算汇编指令集等汇编指令集;内存分配类型的函数,如malloc、heapAlloc等等;内存释放类型的函数,如free、heapFree等等。循环摘要生成模块本发明并不是对二进制程序中所有的循环结构都感兴趣,如果循环结构中没有包含任何循环写内存(或者内存拷贝)的操作,或者循环结构中每次写内存的位置相同,这类循环结构一般情况下不会包含潜在的安全漏洞,因此也没有必要生成测试数据来测试这类循环结构的安全性。从检测二进制程序中复杂的循环结构包含的潜在安全漏洞的角度出发,本发明重点关注二进制程序中具有以下特征的循环结构在循环体的内部,有内存写操作(在每次循环迭代过程中都向不同的内存位置写入输入文件)。如果每次循环迭代过程中写入输入文件的位置是相同的,则该循环结构不是一个写内存操作的循环结构。如果循环写一个类似“register+offset”位置,则该操作可能是访问一个局部变量或者结构体成员,而不是写内存操作。具体可以根据动态数据结构重构的结果来判断循环结构中是否包含循环写操作。循环体的迭代变量的值是可控的,即该迭代变量的值与用户的输入相关或者直接来自用户控制的输入。循环摘要生成模块用于实现上述步骤I。本发明实施例中,循环摘要生成模块获取二进制程序的循环结构摘要信息的具体实现方式可以是根据二进制程序循环识别模块得到的循环结构链表,从二进制程序控制流图中最内部的循环结构开始,依次向外展开,分别对有内存写操作的循环结构生成单循环结构的摘要信息,最终生成二进制程序的循环结构摘要信息。其中,生成单循环结构的摘要信息的具体实现方式可以是从二进制程序循环识别模块得到的循环结构链表中获取循环结构的起始地址、循环结构的结束地址、表示控制循环体的循环次数的变量;从动态数据结构重构模块获取输入文件中的关键字节相对于输入文件的文件头的偏移地址。单循环结构的摘要信息具有如下形式〈LStAddr,LEnAddr, IterVar, MemWrToVar, MemWrFrVar, KByte0ffsetAddr>其中LStAddr表示循环结构的起始地址,LEnAddr表示循环结构的结束地址,IterVar表示控制循环体的循环次数的变量,MemffrToVar表示循环写内存的缓冲区变量,MemffrFrVar表示所述缓冲区的数据的来源变量,KByteOffsetAddr表示输入文件中的关键字节相对于输入文件的文件头的偏移地址。测试数据生成模块测试数据生成模块用于实现上述步骤2。本发明实施例中,测试数据生成模块根据循环摘要生成模块提供的循环摘要信息生成测试数据的具体实现方式可以是首先把循环摘要模块提供的输入文件中的关键字节相对于输入文 件的文件头的偏移地址写入一个偏移地址链表,该偏移地址链表的每一个结点都存有关键字节的值和该关键字节相对于输入文件的文件头的偏移地址等信息;然后计算该偏移地址链表的长度LengthList,随机生成0到LengthList之间的一个随机数RandNum,将RandNum存放在偏移地址链表中;最后随机生成0x00到OxFF的一个随机值,使用该值替换偏移地址链表中RandNum位置存放的字节值,把修改后的偏移地址链表中存放的字节值按照其相对于输入文件的偏移地址写入输入文件中生成测试数据。其中,测试数据生成模块可以按照需求生成一定数量的测试数据。本发明实施例中,测试数据生成模块不是对输入文件的全部字节进行模糊测试,而是仅仅对循环摘要模块提供的、和二进制程序中潜在安全漏洞相关的输入文件的关键字节进行模糊测试。 二进制程序执行监控模块二进制程序执行监控模块用于实现上述步骤3。本发明实施例中,二进制程序执行监控模块利用测试数据生成模块提供的测试数据,以调试方式启动被测试的二进制程序并加载测试数据进行测试。使用Windows系统提供的API函数监控程序的执行,若某个测试数据导致被测试的二进制程序出现异常或者直接崩溃,则记录该测试数据和二进制程序出现异常的类型、位置和异常位置的上下文环境信息。若测试数据没有出现异常,则继续下一个测试数据的测试。当某个测试数据导致被测试的二进制程序出现异常或者直接崩溃时,可以根据记录的该测试数据、二进制程序出现异常的类型、异常位置和异常位置的上下文环境信息,结合二进制程序循环结构摘要信息中的参数,进行漏洞的调试分析。以上所述,仅为本发明较佳的具体实施方式
,但本发明的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本发明揭露的技术范围内,可轻易想到的变化或替换,都应涵盖在本发明的保护范围之内。因此,本发明的保护范围应该以权利要求书的保护范围为准。
权利要求
1.一种二进制程序循环写内存安全漏洞的检测方法,其特征在于,包括 步骤I、获取与二进制程序中潜在安全漏洞相关的二进制程序的循环结构摘要信息; 步骤2、根据所述循环结构摘要信息,生成测试数据; 步骤3、根据所述测试数据对二进制程序进行循环写内存安全漏洞的检测。
2.根据权利要求I所述的方法,其特征在于,所述步骤I包括 从二进制程序控制流图中最内部的循环结构开始,依次向外展开,分别对有内存写操作的循环结构生成单循环结构的摘要信息,所述单循环结构的摘要信息包括循环结构的起始地址、循环结构的结束地址、控制循环体的循环次数的变量、循环写内存的缓冲区变量、所述缓冲区的数据的来源变量、输入文件中的关键字节相对于输入文件的文件头的偏移地址; 获取单循环结构的摘要信息的集合,所述单循环结构的摘要信息的集合就是二进制程序的循环结构摘要信息。
3.根据权利要求2所述的方法,其特征在于,该方法还包括 步骤11、对所述二进制程序的循环结构进行识别; 步骤12、对二进制程序进行动态数据结构重构。
4.根据权利要求3所述的方法,其特征在于,所述生成单循环结构的摘要信息具体包括 根据循环结构识别结果和动态数据结构重构结果,生成单循环结构的摘要信息。
5.根据权利要求4所述的方法,其特征在于,对所述二进制程序的循环结构进行识别具体包括 步骤111、初始化一个回边链表和一个循环结构链表,所述回边链表和所述循环结构链表的初始值均为空; 步骤112、查找所述二进制程序控制流图中的所有回边,将查找到的回边集合保存在所述回边链表中; 步骤113、顺序遍历保存了回边集合的回边链表,得到一条回边,将所述回边记为NodeBB- > NodeSBJf NodeSB标记为“已访问过”,以NodeBB为起点,在所述二进制程序控制流图中作反向的深度遍历; 步骤114、将反向的深度遍历经过的节点、
6.根据权利要求5所述的方法,其特征在于,对二进制程序进行动态数据结构重构具体包括 步骤121、记录输入文件读入内存的起始位置和读入的字节数,将读入内存的字节标记为数据污染源,将所述输入文件读入内存的起始位置作为动态数据结构重构的起始点;步骤122、定义一个记录污染数据传递的链表pTaintList,所述pTaintList的初始值为空; 从所述起始点处开始解析所述二进制程序的汇编指令,解析的过程如下 步骤123、抽取当前的汇编指令的类型INSTYPE,如果当前的汇编指令是危险函数调用类型的指令,则执行步骤124,如果当前的汇编指令不是危险函数调用类型的指令,则执行步骤125 ; 步骤124、抽取当前的汇编指令调用的危险函数的参数,得到一个所述危险函数的参数列表,获取所述危险函数的参数列表中参数变量的三元数组信息,并查找所述pTaintList中是否包含所述参数变量的参数值,如果是,则输出所述危险函数调用地址、所述危险函数的参数列表,和所述参数列表相关联的输入文件中的关键字节相对于输入文件的文件头的偏移地址等相关信息,然后跳转到下一条汇编指令,返回步骤123继续执行,如果不是,则跳转到下一条汇编指令,返回步骤3继续执行; 步骤125、判断当前的汇编指令的操作数的变量值是否被污染如果变量值被污染,更新目的操作数的污染状态信息,并把更新后的污染状态信息添加到所述pTaintList中,跳转到下一条汇编指令,返回步骤123继续执行;如果变量值没有被污染,跳转到下一条汇编指令,返回步骤123继续执行; 步骤126、如果程序正常退出,数据结构动态重构结束。
7.根据权利要求6所述的方法,其特征在于,根据所述循环结构摘要信息,生成测试数据具体包括 将所述输入文件中的关键字节相对于输入文件的文件头的偏移地址写入一个偏移地址链表,所述偏移地址链表的每一个结点保存有关键字节的值和该关键字节相对于输入文件的文件头的偏移地址; 计算所述偏移地址链表的长度LengthList,随机生成O到LengthList之间的一个随机数RandNum,将RandNum存放在所述偏移地址链表中; 随机生成OxOO到OxFF的一个随机值,使用所述随机值替换所述偏移地址链表中RandNum位置存放的字节值,把修改后的偏移地址链表中存放的字节值按照其相对于输入文件的偏移地址写入输入文件中生成测试数据。
8.根据权利要求7所述的方法,其特征在于,根据所述测试数据对二进制程序进行循环写内存安全漏洞的检测进一步包括 如果当前测试数据导致被测试的二进制程序出现异常或者直接崩溃,则记录所述测试数据、所述二进制程序出现异常的类型、异常位置和所述异常位置的上下文环境信息;根据所述当前测试数据、二进制程序出现异常的类型、异常位置和异常位置的上下文环境信息,结合二进制程序循环结构摘要信息中的参数,进行漏洞的调试分析; 如果测试数据没有导致二进制程序出现异常,则继续下一个测试数据对二进制程序的测试。
全文摘要
本发明的目的在于,提供一种二进制程序循环写内存安全漏洞的检测方法,包括步骤1、获取与二进制程序中潜在安全漏洞相关的二进制程序的循环结构摘要信息;步骤2、根据所述循环结构摘要信息,生成测试数据;步骤3、根据所述测试数据对二进制程序进行循环写内存安全漏洞的检测。本发明实施例提供的方法,在生成测试数据时,不需要遍历二进制程序循环结构的所有路径,仅需要根据生成的循环结构摘要信息得到测试数据。由于循环结构摘要信息是和二进制程序的潜在安全漏洞相关的,因此,生成的测试数据更有针对性,大大降低了安全漏洞检测的计算代价。
文档编号G06F11/36GK102708054SQ201210138459
公开日2012年10月3日 申请日期2012年5月8日 优先权日2012年5月8日
发明者吴世忠, 崔宝江, 梁晓兵, 郝永乐, 郭涛 申请人:中国信息安全测评中心, 北京邮电大学
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1