针对闭源函数库生成模糊测试驱动器的方法和装置与流程

文档序号:26139471发布日期:2021-08-03 14:23阅读:253来源:国知局
针对闭源函数库生成模糊测试驱动器的方法和装置与流程

本说明书一个或多个实施例涉及计算机程序的模糊测试,尤其涉及针对函数库生成模糊测试驱动器的方法和装置。



背景技术:

模糊测试(fuzzing)是检测和发掘程序漏洞的重要而常用的测试技术。可以理解,若要对一个程序进行模糊测试,需要找到馈送输入数据的入口点。若要对一个函数库进行模糊测试,则需要一段应用程序,作为馈送输入数据的入口点。这样的应用程序被称为模糊测试驱动器(fuzzdriver)。

常规实践中,模糊测试驱动器的创建和生成,主要依赖于安全分析师的人工工作。相应地,模糊测试驱动器的质量,取决于其编写者的个人知识和技巧。因此,创建和编写有效的模糊测试驱动器,通常是耗时而极具挑战性的工作。

为了减轻模糊测试的人工工作,确保测试质量,近来开始提出一些自动生成模糊测试驱动器的技术。然而,这些技术基本都依赖于对源代码的分析。对于无法获取到源代码的闭源函数库,如何为其生成模糊测试驱动器仍然是一项挑战。



技术实现要素:

本说明书一个或多个实施例描述了生成模糊测试驱动器的方法,可以针对闭源的函数库,自动生成符合预设的驱动器优化指标的模糊测试驱动器。

根据第一方面,提供了一种针对闭源函数库生成模糊测试驱动器的方法,包括:

获取使用目标函数库的若干应用程序执行过程中的执行轨迹,所述目标函数库为闭源函数库;

根据所述执行轨迹,确定所述目标函数库中包含的多个接口函数之间的依赖关系,形成依赖信息集,其中包括具有依赖关系的多个函数对;

根据预设的驱动器优化指标,对所述多个函数对进行选择性组合操作,得到多个组合函数集,并生成所述多个组合函数集对应的多个驱动器,将所述多个驱动器的集合作为所述模糊测试驱动器。

在一个实施例中,获取使用目标函数库的若干应用程序执行过程中的执行轨迹,具体包括:通过hook工具追踪所述若干应用程序的执行过程,得到所述执行轨迹。

根据一种实施方式,形成依赖信息集,具体包括:从所述执行轨迹中获取通过第一线程执行的第一轨迹;从所述第一轨迹中提取按顺序执行的若干接口函数各自的输入输出数据;从所述目标函数库的元信息中获取所述若干接口函数的输入输出类型;若所述若干接口函数中第一函数输出的第一数据,与输入到第二函数的第二数据类型相同,且数值相等,则形成第二函数依赖于第一函数的函数对,将该函数对作为提取得到的第一类函数对,添加到所述依赖信息集中。

进一步的,上述第一数据可以为所述第一函数的返回值;或者,所述第一数据为所述第一函数的输出参数。

在一个实施例中,第一轨迹还包括,所述若干接口函数的嵌套层级信息;所述形成依赖信息集还包括,在提取所述输入输出数据之前,从所述第一轨迹中筛除嵌套层级大于1的接口函数。

根据一个实施例,形成依赖信息集,还包括:基于已形成的若干第一类函数对之间的依赖关系传递,生成若干第二类函数对,添加到所述依赖信息集。

进一步的,在一个例子中,所述若干第一类函数对包括,第三函数依赖于第四函数的第一函数对,第三函数依赖于第五函数的第二函数对,以及第六函数依赖于第四函数的第三函数对;所述生成若干第二类函数对,包括:基于所述第一函数对,第二函数对和第三函数对,生成第六函数依赖于第五函数的第四函数对,作为第二类函数对。

根据一个实施例,形成依赖信息集,还包括:若所述若干接口函数中第三函数的输出类型包括第一类型,第四函数的输入类型包括该第一类型,则将第三函数和第四函数形成第二类函数对,并添加到所述依赖信息集中。

根据另一实施例,形成依赖信息集,还包括:从所述执行轨迹中获取通过第二线程执行的第二轨迹;若所述若干接口函数中存在第三函数,所述第二轨迹中存在第四函数,其中,第三函数输出的第三数据,与输入到第四函数的第四数据类型相同且数值相等,且第三数据或第四数据类型为指针,则将第三函数和第四函数形成第二类函数对,并添加到所述依赖信息集中。

根据一种实施方式,对所述多个函数对进行选择性组合操作,得到多个函数集,并生成所述多个函数集对应的多个驱动器,具体包括:

根据所述多个函数对,形成多个初代函数集,以及对应的多个初代驱动器;

迭代执行多次遗传演化操作,每次遗传演化操作包括:在多个上一代函数集之间进行函数对的重组,得到由重组生成的函数集和上一代函数集构成的多个备选函数集和对应的多个备选驱动器;根据所述预设的驱动器优化指标,从所述多个备选驱动器中选择部分驱动器,将该部分驱动器对应的函数集作为当代函数集;

将所述多次遗传演化操作后得到的当代函数集作为所述多个组合函数集。

根据上述实施方式的一个实施例,形成多个初代函数集,以及对应的多个初代驱动器,具体包括:从所述目标函数库中确定与输入相关的若干入口函数;基于所述若干入口函数,形成若干基础驱动器;基于所述依赖信息集,在所述若干入口函数基础上链接若干函数对,形成所述多个初代函数集;并在所述若干基础驱动器基础上链接所述若干函数对对应的代码块,形成所述多个初代驱动器。

在一个实施例中,所述多个上一代函数集包括第一函数集和第二函数集,第一函数集包括第一函数对,第二函数集包括第二函数对,所述在多个上一代函数集之间进行函数对的重组,包括:在第一函数对和第二函数对之间进行元素交换;和/或,基于第一函数对对第二函数对进行元素修改;和/或,基于第二函数对对第一函数对进行元素修改。

进一步的,所述元素交换包括以下之一:交换输入,交换输出;所述元素修改包括,添加来自另一函数对的输出。

在一个实施例中,所述预设的驱动器优化指标包括多个优化指标,所述根据所述预设的驱动器优化指标,从所述多个备选驱动器中选择部分驱动器,包括:确定各备选驱动器针对所述多个优化指标的多个指标值;根据所述多个指标值,选择部分驱动器。

在一个具体例子中,根据所述多个指标值,选择部分驱动器,包括:根据所述多个指标值,确定各备选驱动器的综合优化指标值;根据各备选驱动器的综合优化指标值对所述多个备选驱动器进行排序;根据所述排序,选择预定数目的驱动器。

在另一具体例子中,根据所述多个指标值,选择部分驱动器,包括:根据所述多个指标值,将各个备选驱动器映射为多维空间中的各个点,所述多维空间以所述多个优化指标为维度而形成;根据各个点在所述多维空间的相对分布,对所述多个备选驱动器排序;根据所述排序,选择预定数目的驱动器。

进一步的,根据各个点在所述多维空间的相对分布,对所述多个备选驱动器排序,可以包括:将所述各个点划分到所述多维空间中的多个空间层,根据所属空间层从外到内,对各个点进行第一排序;对于属于同一空间层的多个点,根据其与邻近点的距离确定其稀疏度,根据稀疏度从高到低,对该多个点进行第二排序;

根据第二排序后所述各个点的相对顺序,对所述多个点对应的多个备选驱动器排序。

在一个具体实施例中,所述多个优化指标包括多样性,任一驱动器的多样性,根据该驱动器包含的函数对的数目,以及该驱动器对应的函数集形成的子图中环的数量而计算,其中所述子图中的节点对应于接口函数,连接边对应于函数对所指示的依赖关系。

在一个具体实施例中,所述多个优化指标包括有效性,任一驱动器的有效性通过以下方式计算:针对该驱动器代码中的各个基本块,根据其是否包含循环和调用,为其赋予分数;将各个基本块的分数累加,作为驱动器的有效性分数。

在另一具体实施例中,所述多个优化指标包括紧密度,任一驱动器的紧密度通过以下方式计算:对于驱动器涉及的各个接口函数的各个输入参数,根据该输入参数的来源,为该输入参数赋予紧密分数;对所述各个接口函数的各个输入参数的紧密分数进行累加,根据累加结果,确定所述驱动器的紧密度。

在一个实施例中,每次遗传演化操作还包括,在从所述多个备选驱动器中选择部分驱动器之前,对所述多个备选驱动器进行稳定性测试,将未通过所述稳定性测试的驱动器从所述多个备选驱动器中剔除。

根据第二方面,提供了一种针对闭源函数库生成模糊测试驱动器的装置,包括:

轨迹获取单元,配置为获取使用目标函数库的若干应用程序执行过程中的执行轨迹,所述目标函数库为闭源函数库;

依赖确定单元,配置为根据所述执行轨迹,确定所述目标函数库中包含的多个接口函数之间的依赖关系,形成依赖信息集,其中包括具有依赖关系的多个函数对;

组合单元,配置为根据预设的驱动器优化指标,对所述多个函数对进行选择性组合操作,得到多个组合函数集,并生成所述多个组合函数集对应的多个驱动器,将所述多个驱动器的集合作为所述模糊测试驱动器。

根据第三方面,提供一种计算机可读存储介质,其上存储有计算机程序,当所述计算机程序在计算机中执行时,令计算机执行第一方面所述的方法。

根据第四方面,提供一种计算设备,包括存储器和处理器,所述存储器中存储有可执行代码,所述处理器执行所述可执行代码时,实现第一方面所述的方法。

根据本说明书实施例提供的方法和装置,考虑到针对闭源函数库生成模糊测试驱动器的困难,采用两阶段方案自动生成模糊测试驱动器。在第一阶段中,追踪使用目标函数库的应用程序的执行轨迹,将其作为正确调用api函数的参考信息,从而获取到目标函数库中各个api函数之间的依赖关系。在第二阶段,根据预设的驱动器优化指标,对收集到的api函数依赖关系进行组合,从而构建具有期望的指标性能的驱动器组,作为模糊测试驱动器。特别地,在该阶段,可以采用多目标遗传演化算法,朝向多个预定的优化目标来调整api函数组合,以及对应的驱动器,从而得到满足多个优化目标的理想的模糊测试驱动器。

附图说明

为了更清楚地说明本发明实施例的技术方案,下面将对实施例描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本发明的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其它的附图。

图1示意性示出生成模糊测试驱动器的构思框架;

图2示出根据一个实施例针对闭源函数库生成模糊测试驱动器的方法流程图;

图3示出在一个实施例中采用遗传演化算法,得到模糊测试驱动器的步骤流程;

图4示出在一个实施例中函数对重组的示意图;

图5示出根据一个实施例的生成模糊测试驱动器的装置的结构示意图。

具体实施方式

下面结合附图,对本说明书提供的方案进行描述。

如前所述,存在针对函数库(library)进行模糊测试,生成模糊测试驱动器的需求。典型地,模糊测试所针对的函数库可以是各种开发工具包sdk函数库。已有的为函数库自动生成模糊测试驱动器的技术基本都依赖于对源代码的分析。对于无法获取到源代码的闭源函数库,如何为其生成模糊测试驱动器是一项挑战。

针对闭源函数库生成模糊测试驱动器的挑战性和困难性主要来自于两个方面。第一,对于闭源函数库来说,能够从中提取到的信息非常有限。由于没有库函数的源代码,获取到正确的接口函数api使用信息进而利用这样的使用信息来合成模糊测试驱动器变得非常困难。更糟糕的是,很多时候,使用这样的函数库的应用程序也是闭源的。例如,macos操作系统中提供有关于字体的sdk函数库,这样的函数库都是闭源的。进一步地,使用该函数库的应用程序(例如macos系统中的浏览器应用程序)也是闭源的。源代码的缺失,使得无法提取得到函数库中各个接口函数之间的控制流和数据流关系。

第二项挑战在于,函数库的多个api函数之间的语义关系往往非常复杂,而若要生成适用的模糊测试驱动器,需要确保api函数之间正确的调用关系和语义关系。api调用的组合方式数量巨大,确保api调用序列的语义正确性非常困难。

有鉴于此,发明人通过深入研究,提出了本说明书中的若干实施方式,以针对闭源函数库,自动生成适用的模糊测试驱动器。

图1示意性示出生成模糊测试驱动器的构思框架。该框架的输入为目标sdk函数库以及使用该函数库的应用程序,输出为生成的模糊测试驱动器。为生成适用的模糊测试驱动器,该框架的实施流程包含两个阶段。第一阶段为,收集目标sdk函数库中各个api函数之间的依赖关系。为此,根据该框架的实施例,可以采集使用该sdk函数库的应用程序的执行轨迹,将该执行轨迹作为正确调用api函数的参考信息。具体的,可以基于该参考信息确定出api函数之间的数据依赖关系。然后,在第二阶段,根据预设的驱动器优化指标,对收集到的api函数依赖关系进行组合,从而构建具有期望的指标性能的驱动器组,作为模糊测试驱动器。具体的,根据一些实施方式,上述优化指标可以包含多项指标,也即,驱动器具有多个优化目标,这多个优化目标之间在有些情况下存在一定矛盾和冲突。为此,在优选的实施方案中,可以采用多目标遗传演化算法,朝向多个预定的优化目标来调整api函数组合,以及对应的驱动器,从而得到满足多个优化目标的理想的模糊测试驱动器。

下面描述以上构思框架的具体实现过程。

图2示出根据一个实施例针对闭源函数库生成模糊测试驱动器的方法流程图。可以理解,该方法流程可以通过任何具有计算、处理能力的设备、装置、平台、设备集群来实现。如图2所示,该实施例的方法包括以下步骤。首先,在步骤21,获取使用目标函数库的若干应用程序执行过程中的执行轨迹,其中目标函数库为闭源函数库;在步骤22,根据上述执行轨迹,确定目标函数库中包含的多个接口函数之间的依赖关系,形成依赖信息集,其中包括具有依赖关系的多个函数对;然后,在步骤23,根据预设的驱动器优化指标,对所述多个函数对进行选择性组合操作,得到多个组合函数集,并生成所述多个组合函数集对应的多个驱动器,将所述多个驱动器的集合作为所述模糊测试驱动器。下面描述上述各个步骤的具体实施方式。

首先,在步骤21,获取使用目标函数库的若干应用程序执行过程中的执行轨迹。这里的目标函数库为闭源函数库。在不同实施例中,可以是闭源的系统函数库,也可以是闭源的sdk函数库。为了分析闭源的目标函数库中各个函数的正确使用,可以找到使用或调用目标函数库的若干应用程序作为参照,这样的应用程序又可称为消费者应用程序(consumerprogram)。例如,当目标函数库为提供字体渲染的sdk函数库(或称为字体库)时,使用该字体库的应用程序,例如使用该字体库渲染字体的浏览器应用、文档处理应用等等,均可作为参照用的应用程序。

在不同实施例中,可以采用多种技术手段,来追踪或监测上述应用程序使用目标函数库的执行过程,从而获得执行轨迹(trace)。例如,可以使用一些hook工具追踪所述若干应用程序的执行过程。还可以通过污点追踪、程序插针(instrumentation)等手段,追踪和记录使用目标函数库的应用程序的执行过程,得到执行轨迹。

如此得到的执行轨迹,可以包括应用程序执行过程中与调用接口函数(apifunction)相关的多种信息,例如,所占用的线程id,接口函数的嵌套层级,内存转储数据,等等。其中,接口函数的嵌套层级用于表示被嵌套调用的接口函数的嵌套深度。如果一个接口函数是被消费者应用程序直接调用,则其嵌套层级为1。如果一个接口函数被嵌套层级为x的另一接口函数调用,则其嵌套层级为x+1。而内存转储数据中则包含接口函数的输入输出数据集,其中包括,函数的入参,返回值,输出参数。

基于这样的执行轨迹,可以对其进行分析处理,试图从中学习到,目标函数库中的接口函数的正确使用方式。

相应的,接下来,在步骤22,根据上述执行轨迹,确定目标函数库中包含的多个接口函数之间的依赖关系,形成依赖信息集。

可以理解,通过步骤21得到的执行轨迹一般是多条轨迹,该多条轨迹可以是多个应用程序执行过程中产生的,或者一个应用程序的多次执行过程产生的。为了更加高效准确地进行分析,在一个实施例中,可以先将以上得到的执行轨迹按照线程id,划分为更为短小的轨迹。例如,可以从执行轨迹中获取通过任意具体线程执行的子轨迹。为了描述的简便,将该具体线程称为第一线程,将对应的子轨迹称为第一轨迹。进一步的,在一个可选实施例中,可以从前述第一轨迹中筛除嵌套层级大于1的接口函数,再进行后续分析。这是因为,嵌套层级大于1的接口函数并不是由消费者应用程序直接调用的,在分析函数依赖关系时重要度不及直接调用的函数,为简化分析,可以将其过滤筛除。于是,可以针对上述第一轨迹,从中提取和分析所涉及的接口函数的依赖关系。

根据一种实施方式,驱动器的生成主要关注接口函数之间的数据依赖关系。具体的,对于一个给定的接口函数f,可以用if表示其输入集,用of表示其输出集,这两个数据集分别表示接口函数f消费(使用)的数据和产出的数据。对于给定的两个接口函数fa和fb,当且仅当这两个接口函数具有数据依赖关系。具体的,如果接口函数fa的输出被用作接口函数fb的一项输入,则认为fb依赖于fa,形成fb依赖于fa的函数对,记为<fa,out,fb,in>,其中,

更具体的,上述数据依赖关系<fa,out,fb,in>可以有多种具体表现形式。例如,在一个例子中,函数fa的返回值被用作函数fb的输入参数。在另一例子中,函数fa的输出参数(通常是指针形式)被用作函数fb的输入参数。

为了发掘出上述数据依赖关系,需要考虑各个接口函数的输入输出的数据类型和数据值。在一个实施例中,可以获取目标函数库的元信息,例如,目标函数库的头文件,描述文件,元数据等,其中一般会记录各个接口函数所声明的数据类型。另一方面,如前获取的执行轨迹中可以包含内存转储信息,通过分析内存转储信息,可以得到各个接口函数的输入输出数据值。如此,可以进行数据依赖关系的发掘。

具体的,以前述第一轨迹为例,可以从第一轨迹中提取按顺序执行的若干接口函数各自的输入输出数据。另一方面,可以从目标函数库的元信息中获取上述若干接口函数的输入输出类型。然后基于上述两种数据进行分析。如果第一轨迹涉及的若干接口函数中存在第一函数和第二函数,其中第一函数输出的第一数据,与输入到第二函数的第二数据类型相同,且数值相等,则认为第二函数依赖于第一函数,形成第二函数依赖于第一函数的函数对,添加到依赖信息集中。具体的,上述第一数据可以是第一函数的返回值;也可以是第一函数的输出参数。

可以理解,前述第一函数、第二函数中的“第一”,“第二”,仅用于区分和标记不同函数,并不具有其他限定作用。后续出现的“第三”、“第四”函数等用词,作用与之类似,不再赘述。

需要说明的是,前述根据依赖关系形成的函数对,是一种有向的函数对。例如,第二函数依赖于第一函数的函数对,与第一函数依赖于第二函数的函数对,是不同的函数对。此外,通过以上原则得到的函数对,是基于从单条轨迹提取的数据得到的具有确定依赖关系的函数对,可以将这样的函数对称为第一类函数对。如此,前述第二函数依赖于第一函数的函数对,属于第一类函数对,添加到依赖信息集中。

实践中,基于执行轨迹得到的第一类函数对,通常数目相对有限。为了进一步丰富依赖信息集,根据一种实施方式,还基于从执行轨迹中获得的已知信息进行依赖关系的推断,从而生成推断的依赖关系和推断的函数对。这类函数对称为第二类函数对。依赖关系的推断,可以基于以下假设:同一函数库中的接口函数往往具有相同的设计或执行模式。因此,可以基于执行轨迹中出现的确定依赖关系,推断出应用程序的执行过程中没有明确出现的依赖关系。

根据一种实施方式,可以基于已形成的若干第一类函数对之间的依赖关系传递,生成若干第二类函数对,添加到依赖信息集中。

在一个具体实施例中,假定从第一执行轨迹中提取得到的第一类函数对包括,第三函数fc依赖于第四函数fa的第一函数对<fa,outa,fc,inc>,第三函数fc依赖于第五函数fb的第二函数对<fb,outb,fc,inc>。当在第一类函数对中又发现第六函数fd依赖于第四函数fa的第三函数对<fa,outa,fd,ind>时,则可以基于上述第一函数对,第二函数对和第三函数对,生成第六函数fd依赖于第五函数fb的第四函数对<fb,outb,fd,ind>,作为第二类函数对,添加到依赖信息集中。

可以理解,还可以基于更多函数对之间的依赖关系传递,生成第二类函数对。例如,可以根据先验知识设定一些依赖规则,通过检测更多函数对之间是否满足该依赖规则,来推断新的依赖关系。

根据一种实施方式,还可以基于数据类型的传递,生成第二类函数对。具体的,在一个例子中,若第一轨迹涉及的若干接口函数中第三函数f3的输出类型包括第一类型,第四函数f4的输入类型包括该第一类型,则将第三函数和第四函数形成第二类函数对,并添加到所述依赖信息集中。

根据又一种实施方式,还可以基于线程间的数据流传递,生成第二类函数对。如前所述,第一轨迹是从执行轨迹中提取的通过第一线程执行的轨迹。在执行轨迹划分阶段,还可以得到通过第二线程执行的第二轨迹。如果第一线程涉及的接口函数中存在第三函数f3,第二轨迹中存在第四函数f4,其中,第三函数输出的第三数据,与输入到第四函数的第四数据类型相同且数值相等,且第三数据或第四数据类型为指针,则将第三函数和第四函数形成第二类函数对,并添加到所述依赖信息集中。可以看到,跨线程的函数对的形成,仅考虑两个线程间通过指针类型关联的两个接口函数。

如此,通过以上多种方式进行依赖关系的推断,生成多种第二类函数对,添加到依赖信息集中。

通过逐线程分析对应的轨迹,提取第一类函数对,再基于第一类函数对和线程间信息进行依赖关系的推断和扩充,生成第二类函数对,使得依赖信息集中包含了大量丰富的函数对。这些函数对可以视为,应用程序正确使用目标函数库中的接口函数的范例。

接下来,可以以依赖信息集中的函数对为基本元素,对这些基本元素进行组合,得到具有链接关系的函数集,基于对函数集的调用,生成对应的驱动器。即,在步骤23,根据预设的驱动器优化指标,对依赖信息集中的多个函数对进行选择性组合操作,得到多个组合函数集,并生成所述多个组合函数集对应的多个驱动器,将所述多个驱动器的集合作为所述模糊测试驱动器。

可以理解,如果将目标函数库中的接口函数作为节点,则依赖信息集中的函数对可以作为节点之间的有向连接边。因此,步骤23的目标是,寻找到经由连接边而链接在一起的节点集合构成的若干子图,根据这些子图构建对应的驱动器,并对构建的驱动器进行优化指标的衡量,从而得到满足优化指标的驱动器,作为期望的模糊测试驱动器。

为此,根据一种实施方式,可以从依赖信息集中获取函数对,按照一定规则选取一些接口函数作为起点,将从起点开始依次具有依赖关系的函数对进行顺次组合,得到多个组合函数集,或者说,得到多个以函数为节点、以依赖关系为边的子图。针对各个子图,根据子图中的函数调用关系构建对应的驱动器,从而得到多个备选驱动器。然后,按照预设的驱动器优化指标,例如,覆盖的接口函数的数量,接口函数的类型数,等等,衡量上述多个备选驱动器,从中选择较优的若干驱动器,将这些驱动器的组合,作为针对目标函数库的模糊测试驱动器。

根据另一种实施方式,为了进一步丰富接口函数的组合方式,同时更好地符合驱动器优化指标,采用遗传演化算法,来得到多个组合函数集及其对应的多个驱动器,形成最终的模糊测试驱动器。

根据遗传演化算法的思想,可以将一个函数对视为一个基因,将通过依赖关系链接在一起的多个函数对的组合,视为一个染色体。换而言之,在将接口函数作为节点的情况下,一个基因可以对应于两个节点之间的一条有向连接边,一个染色体则对应于一个连通子图。在遗传演化过程中,基于已有的染色体进行组合,通过基因重组和/或基因突变,产生新一代染色体。然后,评估新一代染色体的适应度,该适应度基于前述驱动器优化指标而确定,从而选择出具有较高适应度的染色体,进行下一轮遗传演化。如此迭代,最终可以得到多种染色体对应的多种函数集及其对应的多个驱动器,这样的多个驱动器可构成最终所需的模糊测试驱动器。下面描述其具体实施过程。

图3示出在一个实施例中采用遗传演化算法,得到模糊测试驱动器的步骤流程。该步骤流程可视为在一种实施例下,图2中步骤23的子步骤。

如图3所示,首先在步骤231,根据依赖信息集中的多个函数对,形成多个初代函数集,以及对应的多个初代驱动器。

在一个实施例中,可以从前述多个函数对包含的函数中随机选择一些函数作为起点,将从起点开始具有依赖关系的若干函数对进行组合,得到多个函数集作为初代函数集,并相应形成对应的多个初代驱动器。

在另一实施例中,基于入口函数形成初代函数集。具体的,首先从目标函数库中确定与输入相关的若干入口函数。入口函数是与输入相关的函数,其处理输入文件的描述符或者直接处理输入文件的内容。实践操作中,可以通过将输入文件的关键特征,例如输入文件名,与接口函数转储的参数值进行匹配而定位得到。

在识别出入口函数后,可以基于这些入口函数,形成若干基础驱动器。该基础驱动器是最小单元的驱动器,可以通过填入入口函数的各个参数值并将其代码化而生成。

然后,基于前述依赖信息集,在若干入口函数基础上链接若干函数对,形成多个初代函数集;并在所述若干基础驱动器基础上链接所述若干函数对对应的代码块,形成多个初代驱动器。如此形成的多个初代函数集/多个初代驱动器,即作为多个初代染色体。该多个初代染色体形成初代“人群”。

例如,假定接口函数e1和e2均为入口函数,函数a依赖于e1和e2,函数b依赖于函数a,函数c依赖于e2,则可以基于函数e1和e2分别形成两个基础驱动器,此外通过链接函数对,形成函数集(e1-a-b),(e2-a-b),(e2-c),作为初代函数集,并对应形成初代驱动器。这些函数集/驱动器,构成初代人群。

在形成初代人群后,就可以迭代地进行多轮遗传演化操作。任意的第t轮遗传演化操作包括以下步骤。

在步骤232,在多个上一代函数集(t-1代函数集)之间进行函数对的重组,得到由重组生成的函数集和上一代函数集构成的多个备选函数集和对应的多个备选驱动器。也就是说,通过对t-1代函数集(t-1代染色体)进行函数对重组(基因变异),生成新的函数集;将新生成的函数集(新居民)添加到已有函数集(已有人群)中,形成整个备选函数集(新的人群)。

在多个上一代函数集之间进行函数对的重组,也就是进行所谓的基因重组/基因突变,可以有多种操作方式。具体的,假定上一代函数集包括第一函数集和第二函数集,第一函数集包括第一函数对,第二函数集包括第二函数对,则函数对的重组可以包括,在第一函数对和第二函数对之间进行元素交换。具体的,元素交换可以包括,交换输入,交换输出。此外,函数对的重组还可以包括,基于一个函数对,对另一函数对进行元素修改。这样的元素修改可以包括,删减输入/输出,添加来自另一函数对的输出,等等。

图4示出在一个实施例中函数对重组的示意图。在图4中,假定d1为来自第一函数集的第一函数对,d2为来自第二函数集的第二函数对。图4中示意性示出4种函数对重组操作,其中op1为双方交换输出,op2为双方交换输入,op3为添加输出,op4为删减输出。

需要理解,图4的示意仅为举例。还可以进行更多种函数对的重组,从而实现染色体中的“基因突变”。并且,在两个上一代函数集之间,可以各自随机选择一个或多个函数对,进行上述重组,其目的是得到更多种可能的组合方式,丰富染色体的形态。

通过重组新生成的函数集,加上原有的上一代函数集,共同构成多个备选函数集。针对各个备选函数集,基于其中的函数调用关系将其代码化,得到对应的各个备选驱动器。

接下来,可选的,在步骤233,对各个备选驱动器进行稳定性测试。该稳定性测试可以通过使用多种输入数据作为种子,多次运行编译的备选驱动器而执行。对于没有通过稳定性测试的驱动器,可以将其从备选驱动器集合中剔除。

接着,在步骤234,根据预设的驱动器优化指标,从多个备选驱动器中选择部分驱动器,将该部分驱动器对应的函数集作为当代函数集。

在一个实施例中,驱动器优化指标包含单一优化指标。在这样的情况下,逐个计算各个备选驱动器的优化指标值,根据该指标值对备选驱动器进行排序,根据排序结果,选择序次靠前的预定数目的驱动器。

在另一实施例中,预设的驱动器优化指标可以包括多个优化指标。在这样的情况下,则需要确定各备选驱动器针对该多个优化指标的多个指标值;并根据所述多个指标值,选择部分驱动器。

在一个具体例子中,在确定出各备选驱动器的多个指标值之后,可以根据该多个指标值,确定各备选驱动器的综合优化指标值;然后根据各备选驱动器的综合优化指标值对多个备选驱动器进行排序,并根据排序结果,选择预定数目的驱动器。

例如,假定存在3个优化指标i1,i2,和i3。某个驱动器针对该三个优化指标的指标值分别为m1,m2和m3。则可以通过加权求和等方式,得到该驱动器的综合优化指标值p,例如p=k1*m1+k2*m2+k3+m3,其中,k1,k2和k3为权重系数。然后根据各个备选驱动器的综合优化指标值,即p值,对备选驱动器进行排序,进而进行选择。

然而,采用上述方式,常常出现权重系数不易确定的问题。为此,在另一实施例中,当存在多个优化指标时,可以以该多个优化指标为多个维度,形成一个多维空间。在计算出某个驱动器针对该多个优化指标的多个指标值后,可以根据该多个指标值,即以该多个指标值为其在多个维度的坐标值,将该驱动器映射为上述多维空间中的一个点。从而,将各个备选驱动器映射为多维空间中的各个点。然后,根据各个点在所述多维空间的相对分布,对所述多个备选驱动器排序;并根据排序结果,进行驱动器的选择。

在基于各个点的空间分布进行排序时,在一个例子中,可以基于各种多维几何算法,依次确定出在多维空间中处于“最外围”的点,从而进行排序,得到多个备选驱动器的排序。

在另一实施例中,可以将各个点划分到多维空间中的多个空间层,根据所属空间层从外到内,对各个点进行第一排序。该第一排序是层间排序,相当于将各个点划分到几个区段。然后,进行层内排序。对于属于同一空间层的多个点,根据其与邻近点的距离确定其稀疏度,根据稀疏度从高到低,对该多个点进行第二排序。稀疏度越高,分数越高,排序越靠前。如此,通过两个阶段排序,得到各个点的相对顺序,也就是,各个备选驱动器的相对顺序。从而可以基于这样的相对顺序,对备选驱动器进行选择。

以上通过多种方式,从多个备选驱动器中选择出部分驱动器,该部分驱动器可对应于适应度较高的那些染色体,因此,可以将该部分驱动器对应的函数集作为当代函数集,用于进行下一轮的迭代演化。

通过反复多次执行步骤232-234,不断地产生新的染色体(新的函数集),形成新的人群,然后从中选择适应度更好的染色体进行下一代演化。如此,经过一定次数(该次数可以是预先设定的超参数,也可以是根据当前得到的染色体的情况而确定满足迭代停止条件时的次数)的遗传演化操作后,在步骤235,最后一轮遗传演化操作得到的多个当代函数集,就可以作为最终的多个组合函数集,该多个当代函数集对应的多个当代驱动器,就可以作为最终所需的多个驱动器。该多个驱动器的集合,即可作为所需的用于目标函数库的模糊测试驱动器。

通过以上过程可以看到,采用遗传演化算法,可以根据任意数量的优化指标来进行函数对组合。多个优化指标情况下的遗传演化算法,可称为多目标遗传演化算法。根据上述实施例的多目标遗传演化算法,可以适用于根据需要设定的多个优化指标,即使这多个优化指标之间,在一些情况下存在一定的冲突和矛盾。

在一个具体实施例中,上述多个优化指标包括多样性,用于衡量驱动器覆盖的接口函数的丰富程度。一个驱动器的多样性可以正比于其包含的函数对的数目。进一步的,多样性还可以衡量驱动器的接口函数之间调用的复杂程度。具体的,当以接口函数作为节点,以函数对指示的依赖关系作为连接边,驱动器对应的函数集可形成对应子图。子图的圈复杂度(cyclomaticcomplexity),可用于衡量函数之间调用的复杂程度。更具体的,该圈复杂度可以正比于该子图中形成的环的数量。

在一个例子中,一个驱动器的多样性div可以通过以下公式(1)确定:

div=e+cc(1)

其中,e表示驱动器中包含的不同函数对的数量;cc表示基于子图中环的数量确定的圈复杂度。进一步的,在一个例子中,公式(1)第一项中的e,仅考虑不同核心函数对的数量,其中核心函数对表示,被依赖的接口函数的输入来自于外部输入数据,或来自于另一核心函数对。核心函数对中的函数可称为核心函数。当以入口函数作为根节点,根据各个函数对形成树状图时,数据自根节点流入,核心函数对帮助数据流向不同的接口函数。换而言之,核心函数对是对输入数据流有直接影响的函数对。在计算多样性时,可以仅考虑这样的核心函数对。

在一个具体实施例中,上述多个优化指标包括有效性eff,该有效性指标用于衡量驱动器运行时的动态行为,更具体的,用于评估各个接口函数是否被正确地调用。考虑到,核心逻辑代码一般更加复杂,包含更多的循环或调用,而错误调用导致的错误处理路径相较于核心逻辑代码包含更少的基本块,因此,可以针对驱动器代码中的各个基本块,根据其是否包含循环和调用,为其赋予分数。例如,若基本块b同时包含循环和调用,则分数为3;若基本块包含循环或调用,则分数为2;否则分数为1。然后将各个基本块的分数累加,作为驱动器的有效性分数。

在另一具体实施例中,上述多个优化指标包括紧密度。驱动器具有更高的紧密度,意味着,其包含更少的重复函数对,以及使用更少的无关函数对。紧密度指标在一定程度上,与多样性指标存在一些矛盾和冲突。在一个具体例子中,可以通过以下方式计算驱动器的紧密度。对于驱动器涉及的各个接口函数的各个输入参数,根据该输入参数的来源,为该输入参数赋予紧密分数。具体的,输入参数的来源可以分为,1)来自核心函数的输出,2)来自预配置的信息或内存转储,3)来自非核心函数,这三种来源的紧密分数依次减少。然后,对驱动器涉及的各个接口函数的各个输入参数的紧密分数进行累加,根据累加结果,确定所述驱动器的紧密度。

更具体的,在一个例子中,在计算紧密度时,仅考虑所涉及的核心函数的输入参数的紧密分数。在又一例子中,在将各个接口函数的各个输入参数的紧密分数进行累加得到累加结果后,还对累加结果进行归一化,作为最终的驱动器紧密度。在其他例子中,还可以在以上构思基础上,对于求紧密度的方式进行更多修改和变型。

以上举例了驱动器的多样性、有效性、紧密度作为优化指标。需要理解,除此之外,还可以设置其他/更多优化指标,例如,复杂度、运行稳定性、运行效率等等,来指导驱动器的选择,在此不一一详述。更多的或其他的优化指标的组合,也在以上提出的构思框架之内。

回顾以上过程,考虑到针对闭源函数库生成模糊测试驱动器的困难,本说明书的实施例采用两阶段方案自动生成模糊测试驱动器。在第一阶段中,追踪使用目标函数库的应用程序的执行轨迹,将其作为正确调用api函数的参考信息,从而获取到目标函数库中各个api函数之间的依赖关系。在第二阶段,根据预设的驱动器优化指标,对收集到的api函数依赖关系进行组合,从而构建具有期望的指标性能的驱动器组,作为模糊测试驱动器。特别地,在该阶段,可以采用多目标遗传演化算法,朝向多个预定的优化目标来调整api函数组合,以及对应的驱动器,从而得到满足多个优化目标的理想的模糊测试驱动器。如此,解决了针对闭源函数库自动生成模糊测试驱动器的难题。

根据又一方面的实施例,本说明书实施例还提供了一种针对闭源函数库生成模糊测试驱动器的装置,该装置可以部署在任何具有计算、处理能力的计算设备、平台或集群中。图5示出根据一个实施例的生成模糊测试驱动器的装置的结构示意图。如图5所示,该装置500包括:

轨迹获取单元51,配置为获取使用目标函数库的若干应用程序执行过程中的执行轨迹,所述目标函数库为闭源函数库;

依赖确定单元52,配置为根据所述执行轨迹,确定所述目标函数库中包含的多个接口函数之间的依赖关系,形成依赖信息集,其中包括具有依赖关系的多个函数对;

组合单元53,配置为根据预设的驱动器优化指标,对所述多个函数对进行选择性组合操作,得到多个组合函数集,并生成所述多个组合函数集对应的多个驱动器,将所述多个驱动器的集合作为所述模糊测试驱动器。

在具体实施例中,以上各个单元可以配置用于执行,结合图2和图3描述的方法步骤,此处不再赘述。

根据另一方面的实施例,还提供一种计算机可读存储介质,其上存储有计算机程序,当所述计算机程序在计算机中执行时,令计算机执行结合图2所描述的方法。

根据再一方面的实施例,还提供一种计算设备,包括存储器和处理器,所述存储器中存储有可执行代码,所述处理器执行所述可执行代码时,实现结合图2所述的方法。

本领域技术人员应该可以意识到,在上述一个或多个示例中,本发明所描述的功能可以用硬件、软件、固件或它们的任意组合来实现。当使用软件实现时,可以将这些功能存储在计算机可读介质中或者作为计算机可读介质上的一个或多个指令或代码进行传输。

以上所述的具体实施方式,对本发明的目的、技术方案和有益效果进行了进一步详细说明,所应理解的是,以上所述仅为本发明的具体实施方式而已,并不用于限定本发明的保护范围,凡在本发明的技术方案的基础之上,所做的任何修改、等同替换、改进等,均应包括在本发明的保护范围之内。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1