发明内容
本文发明了一种基于程序图的栈缓冲区溢出脆弱性检测方法。首先对源代码进行静态分析后构造相应的程序图。遍历生成的程序图寻找到危险函数,得到溢出点位置。并且通过比较函数操作的缓冲区空间与所要覆盖空间的大小计算地址的偏移。最后通过判断是否出现地址偏移而得到脆弱性检测的结果。
本发明的技术方案如下:
步骤1,对源代码进行静态分析后构造相应的程序图;
步骤2,遍历生成的程序图寻找到危险函数,得到溢出点位置;
步骤3,在溢出点比较函数操作的缓冲区空间与所要覆盖空间的大小计算地址的偏移;
步骤4,通过判断是否出现地址偏移而得到脆弱性检测的结果。
进一步方案,上述步骤1的具体步骤如下:
步骤1.1,对源代码进行控制流分析获得控制流信息和程序图有向边的信息,再对源代码进行数据流分析获得数据流信息和程序图节点的信息,推断代码中变量间的关系及实际特征;
步骤1.2,通过对源代码的控制流信息和数据流信息进行分析获取源代码中变量的初始化和被函数调用的信息,得到变量间的关系和变量与调用函数之间的关系;
步骤1.3,将变量的初始化和使用作为属性节点,按照控制流信息的顺序构造源代码的程序图。
进一步方案,上述步骤2的具体步骤如下:
步骤2.1,通过TRAVERSAL方法遍历程序图,返回的节点是图中所有变量的初始化节点和变量被调用节点;
步骤2.2,使用ToSet方法将变量初始化节点和变量被调用节点转换成节点集合,该节点集合包含了所有的变量初始化的节点和函数使用变量的节点;
步骤2.3,在节点集合中提取出调用变量的函数与危险函数集合Da比较得到源代码中存在的危险函数,得到溢出点位置。
进一步方案,上述步骤3的具体步骤如下:
步骤3.1,在溢出点位置找到变量的调用函数,通过与危险函数库的对比判断危险函数的类型。本发明主要说明“Strncpy()”“Memcpy()”和“Gets()”三种危险函数的脆弱性检测方法;
步骤3.2,分析“Strncpy()”“Memcpy()”和“Gets()”等危险函数类型的脆弱性成因。对于Strncpy()和Memcpy()函数,获取函数操作的缓冲区空间O和覆盖空间C,但对于Gets()函数只需要获取函数的缓冲区空间O;
进一步方案,上述步骤4的具体步骤如下:
步骤4.1,对于Strncpy函数,如果复制的长度n<O,则没有脆弱性。如果n>O且O<C,则存在脆弱性;
步骤4.2,对于Memcpy函数,如果复制的长度n<O,则没有脆弱性。如果n<O且O<C,则存在脆弱性;
步骤4.3,对于Gets函数,如果O=[0,∞],则存在脆弱性。
与现有技术相比,本发明的有益效果:
1、本发明提出了一种基于程序图的栈缓冲区溢出脆弱性检测方法,可以更好地适用于资源访问类软件脆弱性检测,提高检测效率。
2、在程序图的基础上提出了一个栈缓冲区溢出脆弱性检测方法,用于指导构建缓冲区溢出的脆弱性检测模型,使其能够更好地适用于缓冲区溢出脆弱性检测。
3、本发明有常见脆弱性的实例验证来证明此检测方法的准确性,目的是更加精准地检测到软件系统中的脆弱性,提高系统的安全性。
具体实施方式
为了更好地理解本发明一种基于程序图的栈缓冲区溢出脆弱性检测方法,下面结合附图和具体实施案例对本发明作进一步说明,须指出的是,所描述给出的实施案例旨在便于对本发明的理解,而对其没有任何限定要求。
本发明提出了一种基于程序图的栈缓冲区溢出脆弱性检测方法,可以更好地适用于资源访问类软件脆弱性检测,提高检测效率。
首先,定义本发明所涉及到的几个概念定义和计算公式如下。
定义1程序图:又称程序流程图,以图形的方式来表达代码的逻辑功能、数据在代码中的逻辑流向和逻辑变换的过程,是结构化系统分析方法用于表示代码的一种图示方法,是有向边和属性节点的集合。形如G=<V,λ>,V是程序图上属性节点的集合,λ是有向边的集合。
定义2危险函数:指一些危险的、使用时容易造成缓冲区溢出的函数如表1所示,主要存在于C/C++语言中。如一些拷贝函数Strncpy()、Memcpy()在分配内存空间时容易造成缓冲区的溢出,外部输入函数Gets()在输入长度时经常会造成缓冲区的溢出。
表1
定义3危险函数集:Da=<D,E>,其中D={d1,d2,d3,…,dm}是危险函数名集合,E={e1,e2,e3,…,em}是危险函数描述内容。
定义4图的遍历:是指从图中的任意节点出发,按照某种规则访问图中的所有节点,并且所有节点有且仅访问一遍。目前图遍历主要有深度优先遍历和广度优先遍历两种。深度优先遍历的思想是从图的某个节点出发,访问后选择一个与这个节点相邻且没有被访问过的节点访问,再从这个节点出发选择一个与它相邻且没有被访问的节点访问,以此类推继续直到所有节点都被访问到。广度优先遍历的基本思想是按层次的访问。
定义5 TRAVERSAL遍历:指图的深度优先向下遍历,返回的是节点的集合。形如:
TRAVERSALl(X)=∪v∈X{t:(v,t)∈λandλ((v,t))=1},表示TRAVERSAL遍历所返回的节点集合X中包含图的所有节点,t为节点的属性值。TRAVERSAL1表示TRAVERSAL遍历返回所有标签值为l的边。
定义6 ToSet操作:将多个元素转换成以这些元素为集合的操作。
定义7 Strncpy函数:是C语言的库函数之一,来自C语言标准库。形如char*strncpy(char*dest,const char*src,size n),把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,返回的是dest。
定义8 Memcpy函数:是C语言的库函数之一,来自C语言标准库。形如char*Memcpy(char*dest,const char*src,size n),把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,返回的是dest的指针。
定义9Gets函数:是C语言的库函数之一,来自C语言标准库。功能是从输入缓冲区中读取一个字符串存储到字符指针变量str所指向的内存空间。
如图1所示,本发明的一种基于程序图的栈缓冲区溢出脆弱性检测方法流程图,包括:
步骤1,对源代码进行静态分析后构造相应的程序图。
上述步骤1中,参照图2,构造相应的程序图的步骤如下:
步骤1.1,对源代码进行控制流分析获得控制流信息和程序图有向边λ的信息,再对源代码进行数据流分析获得数据流信息和程序图节点V的信息,推断代码中变量间的关系及实际特征;
步骤1.2,通过对源代码的控制流信息和数据流信息进行分析获取源代码中变量的初始化和被函数调用的信息,提取源代码的控制流信息、指针变量、内存块、常量和函数结构等数据信息,并得到变量间的关系和变量与调用函数之间的关系;
步骤1.3,给源代码中的每一行代码进行编号,在确定完程序图的开始节点和终止节点后分析每一行代码明确每一个变量的初始化节点、变量的使用节点和有向边。将这些节点和有向边作为属性节点和属性边构建源代码的程序图。可以比较全面地展示出代码的语法结构具有较高的遍历效率。
步骤2,遍历生成的程序图寻找到危险函数,得到溢出点位置。
上述步骤2中,参照图3,寻找危险函数得到溢出点位置的步骤如下:
步骤2.1,通过TRAVERSAL方法遍历程序图,返回的节点是图中所有变量的初始化节点和变量被调用节点。使用ToSet方法将变量初始化节点和变量被调用节点转换成节点集合,该节点集合包含了所有的变量初始化的节点和函数使用变量的节点;
步骤2.2,TRAVERSAL遍历结合ToSet方法的规则如下:
其中用于遍历程序图获得到所有变量的初始化节点。同理用于遍历程序图获得到所有变量的使用即被调用的节点。最后结合ToSet方法所有变量的初始化节点和被调用节点集中转换成节点集合。
步骤2.3,在节点集合中提取出调用变量的函数与危险函数集合Da比较得到源代码中存在的危险函数,得到溢出点位置。
上述步骤3中,参照图4,比较函数操作的缓冲区空间与覆盖空间大小的步骤如下:
步骤3.1,在溢出点位置找到变量的调用函数,通过与危险函数库的对比判断危险函数的类型。本发明主要说明“Strncpy()”“Memcpy()”和“Gets()”三种危险函数的脆弱性检测方法,Strncpy()、Memcpy()等一些拷贝函数在分配内存空间时容易造成缓冲区的溢出,而外部输入函数Gets()在输入长度时经常会造成缓冲区的溢出;
步骤3.2,对于Strncpy函数,函数操作的缓存区空间operate(dest)=[p1,q1],覆盖空间covered(src)=[i1,j1],其中p1,q1分别是缓冲区空间的初始地址和终止地址,i1,j1分别是覆盖空间的初始地址和终止地址。对于Memcpy函数,函数操作的缓存区空间operate(dest)=[p2,q2],覆盖空间covered(src)=[i2,j2],其中p2,q2分别是缓冲区空间的初始地址和终止地址,i2,j2分别是覆盖空间的初始地址和终止地址。对于Gets函数,函数操作的缓存区空间operate(dest)=[p3,q3],其中p3,q3分别是缓冲区空间的初始地址和终止地址。
上述步骤4中,参照图5,脆弱性判断的步骤如下:
步骤4.1,对于Strncpy函数,如果复制的长度n<p1-q1,则没有脆弱性。如果n>p1-q1且(p1-q1)<(i1-j1),则存在脆弱性;
步骤4.2,对于Memcpy函数,如果复制的长度n<p2-q2,则没有脆弱性。如果n<p2-q2且(p2-q2)<(i2-j2),则存在脆弱性;
步骤4.3,对于Gets函数,如果p3-q3=[0,∞],则存在脆弱性。
本发明分析给定的脆弱性代码,按照上面所描述的脆弱性检测方法进行脆弱性的验证。所要分析的代码如下所示。
(1)对上述所示代码进行分析后构造的程序图如图6所示;
(2)遍历图6所示程序图找到危险函数在代码的第6行;
(3)确定危险函数的类型是字符串类型中的Memcpy,操作的缓存区空间O=12,覆盖空间C=6;
(4)n=5<O-C=6并且O>C,所有该代码没有缓冲区溢出的脆弱性。
上文所列出的一系列的详细说明仅仅是针对本发明的可行性实施方式的具体说明,它们并非用以限制本发明的保护范围,凡未脱离本发明技艺精神所作的等效实施方式或变更均应包含在本发明的保护范围之内。