掌桥专利:专业的专利平台
掌桥专利
首页

一种动态函数调用的可视化方法

文献发布时间:2023-06-19 19:28:50


一种动态函数调用的可视化方法

技术领域

本发明属于信息可视化技术领域,具体涉及一种动态函数调用的可视化方法。

背景技术

计算机程序是一组由编程语言编写的、计算机能识别和执行的代码指令,用于实现特定的目的;函数是一个具有固定功能的、可复用的代码段;一个程序往往会调用若干个函数。分析程序动态运行过程中产生的函数调用数据,可以更直接地了解程序的行为意图和执行目的,是程序理解、程序测试、漏洞定位、恶意文件检测等工作中不可或缺的一个环节。

动态函数调用数据主要呈现出三大特性:(1)二元性,一条函数调用涉及一个源函数,即调用者(caller),和一个目标函数,即被调用者(callee);(2)层次性,函数调用可以是嵌套的,即一个函数调用另一个函数,另一个函数又调用别的函数,从而形成层次结构;(3)时序性,函数调用是按顺序发生的,有时候会出现单条函数调用或一组函数调用的连续或周期模式。分析动态函数调用数据时需要综合考察其中的二元、层次和时序信息。

查看动态函数调用的原始数据往往耗时耗力,可视化则能够帮助分析人员更加直观、友好地探索。然而,传统的函数调用可视化方法,如力导引节点链接图、热力矩阵、正交树、冰柱图、大规模序列视图等,不能综合呈现函数调用数据中完整的二元、层次和时序信息。分析人员通常需要协同多个视图来完成复杂的分析任务,这意味着分析人员要熟练掌握多种可视化方法,且分析效率会受到限制。此外,传统的函数调用可视化方法还会面临可读性、可比较性和可扩展性等方面的问题——力导引节点链接图可能会产生大量交错的连边;热力矩阵中函数的排列规则很大程度上影响不同函数调用数据的比较;正交树和冰柱图可能会出现空间利用不均的情况;在大规模序列视图中观察单条函数调用容易丢失目标。因此,亟需一种可读性、可比较性和可扩展性较好的动态函数调用数据可视化方法,帮助分析人员综合地探索函数调用中的二元、层次和时序信息。

发明内容

为解决现有技术的缺陷和不足问题;本发明的目的在于一种能够同时呈现函数调用数据中的二元、层次和时序信息,且具有良好的可读性、可比较性和可扩展性的动态函数调用的可视化方法。

为实现上述目的,本发明采用的技术方案是:它包含以下步骤:

步骤1:获取动态函数调用数据

动态函数调用数据为一个程序动态运行一次产生的函数调用记录,这些记录以表格的形式存储,每一条记录包含三个字段:caller、callee和index。其中caller字段保存了调用函数的名称、callee字段保存了被调用函数的名称,这两个字段的数据类型为STRING型;index字段保存了函数调用的索引,数据类型为INT型。通过index字段的值I

步骤2:将原始数据转换为带索引信息的层次结构数据。

将步骤1得到的原始数据转换为层次结构的数据;根据函数之间的调用和被调用关系来确定层次结构中的父子关系,合并同一个父节点下的相同调用边同时记录调用发生所对应的索引;

步骤2.1:初始化集合Funccall_set,用于记录所有的调用边对象;按照index的值,升序遍历步骤1中得到的动态函数调用记录,将每一条记录中caller和callee的组合视为一个调用边对象caller|callee;

如果caller|callee不在Funccall_set中,那么将其添加到Funccall_set中,并记录相应的属性:调用者(caller)、被调用者(callee)和所有调用索引(all_index);

如果caller|callee在Funccall_set中,那么更新all_index属性。

步骤2.2:对Funccall_set进行遍历,生成以程序的入口函数作为根节点的层次结构数据Hie_calldata。

步骤3:基于广度优先遍历算法确定函数节点布局及设置调用连边属性。

根据步骤2.2获得的层次化数据Hie_calldata进行布局,生成相应的树节点数组和连边数组;树节点数组记录每一个函数节点对象,包括基本属性——函数名称、函数节点在树结构中的深度,以及布局属性——在画布上的位置;树连边数组记录每一条连边对象,包括两个基本属性——连边所对应的源节点对象和目标节点对象。

函数节点分层布局,即从根节点到叶子节点从上往下延伸,根节点布局在最上层;此外,实现布局紧凑化和节点左对齐,即不同层之间保留较小的间隙,同一层节点之间也保留较小的、等大的间隙,从左往右延伸;父节点和其每个子节点之间形成一条连边,要判断连边是否为父节点到其第一个子节点的连边,并作为布尔属性isfirstLink记录在连边对象中。

步骤3.1:定义一个起始位置的坐标(start_X,start_Y),函数节点之间的水平间距node_spaceX,节点之间的竖直间距node_spaceY。初始化一个函数节点数组tree_funcnode,和一个函数调用连边数组tree_calllink。

步骤3.2:对步骤2.2中获得的层次化数据Hie_calldata进行广度优先遍历,此步骤基于循环来实现,将函数节点对象添加到tree_funcnode数组中,将函数调用连边对象添加到tree_calllink数组中。根据布局紧凑化和节点左对齐的设计原则,确定函数节点的位置,其中深度为d,即第(d+1)层的第i个节点N

N_x

N_y

也就是说,根节点的坐标为步骤3.2中定义的起始位置坐标;每一层的第一个函数节点的x轴坐标都为start_X,任意一层中第i个节点的x轴坐标为(start_X+(i-1)*node_spaceX);第(d+1)层节点的y轴坐标为(start_Y+d*node_spaceY)。

每一个连边对象中除了该调用边的源节点--父节点和目标节点--子节点,还要记录该调用边是否为父节点到其第一个子节点的连边:如果是,isfirstLink的属性值为TRUE;如果不是,isfirstLink的属性值为FALSE。

步骤3.3:由于程序的入口函数为根节点,单独位于一层中,为了节省竖直方向上的空间,移除步骤3.2得到的tree_funcnode数组中的根节点对象;移除步骤3.2得到的tree_calllink数组中的根节点到其子节点之间的调用连边对象;因此在下一步中不会绘制根节点及与之相关的连边。

步骤4:绘制层次化的函数调用概览;

根据步骤3.3中得到的tree_funcnode和tree_calllink,分层绘制函数节点和调用连边;将函数节点编码为等大的方块,将函数名称标记在方块内部,并显式绘制父节点到其第一个子节点的调用连边。层次化的布局可以确保动态函数调用数据中层次信息的呈现,连边则保证了二元信息的呈现。

步骤4.1:定义方块的边长为node_size(node_size

步骤4.2:定义连边颜色为中灰色(#595959),样式为正交折线。

步骤4.3:遍历步骤3.3中得到的tree_funcnode,以函数节点的x轴和y轴坐标为方块的左上角,在画布的相应位置绘制边长为node_size的函数节点;根据函数节点对象中all_index属性值中记录的索引数目确定函数节点的填充颜色;并在方块内部居中显示函数名称。

步骤4.4:遍历步骤3.3中得到的tree_calllink,判断连边对象中isfirstLink的属性值,只有属性值为TRUE时,才绘制连边。

步骤5:将函数调用的索引区间映射到节点高度上。

由于节点是等大的,方块状的,因此将节点的高度作为时间轴,将动态函数调用数据的索引区间映射到节点高度上,以展示细粒度的动态函数调用的时序信息。

获取动态函数调用数据的index区间[0,I

h_singleIndex=node_size/(1+I

步骤6:绘制细粒度的函数调用。

在函数节点上进行图元设计,使用绘制在方块相应高度上,与节点同宽的水平条来表示该方块所对应的函数被其父节点调用的时序信息;同时借助水平条的颜色来编码被调用函数的类型。

步骤6.1:定义水平条的高度为步骤5中计算得到的h_singleIndex;定义水平条的宽度和节点边长相等,为node_size;定义水平条的默认颜色为深灰色;用户按需通过水平条的颜色来编码其他类型的信息;

步骤6.2:步骤3.3得到的tree_funcnode中,每个函数节点对象中都记录了函数的名称,函数被其父节点调用时对应的索引all_index、函数节点的x、y坐标等属性。循环遍历tree_funcnode,对于每一个函数节点对象N

H_x

H_y

本发明所述的动态函数调用的可视化方法对函数调用的二元、层次和时序等多类型的信息进行了有效的可视化;该方法具有以下有益效果:

1、采用了层次化的树状布局,确保二元和层次信息的呈现;

2、同时做了布局紧凑化和函数节点左对齐的处理,一方面可以提高空间利用率,另一方面可以帮助分析人员快速比较单个样本中不同层的函数数目、比较不同样本中函数调用的层次结构。

3、本发明在函数节点上进行了图元设计,简洁美观地展示了细粒度的函数调用时序信息,方便分析人员快速定位多次发生的调用、高效识别连续或周期调用模式。

4、本发明为程序开发人员、程序测试人员、安全管理员等目标用户提供了强有力的动态函数调用数据分析手段,可以帮助他们精简工作流程,节约工作时间。用户能够很好地感知和辨别动态函数调用数据所蕴含的丰富的二元、层次和时序信息,为程序理解、程序测试、恶意文件检测打下了坚实基础。

附图说明

为了更清楚地说明本发明实施例或现有技术中的技术方案,本发明由下述的具体实施及附图作以详细描述。

图1是本发明所述方法的流程图;

图2是动态函数调用可视化每个设计步骤的示意图;

图3是动态函数调用可视化在程序测试过程中的实施例示意图;

图4是动态函数调用可视化的若干实施例。

具体实施方式

为使本发明的目的、技术方案和优点更加清楚明了,下面通过附图中示出的具体实施例来描述本发明。但是应该理解,这些描述只是示例性的,而并非要限制本发明的范围。此外,在以下说明中,省略了对公知结构和技术的描述,以避免不必要地混淆本发明的概念。

在此,还需要说明的是,为了避免因不必要的细节而模糊了本发明,在附图中仅仅示出了与根据本发明的方案密切相关的结构和/或处理步骤,而省略了与本发明关系不大的其他细节。

参看如图1所示,本具体实施方式采用以下技术方案:它包含以下步骤:

步骤1:获取动态函数调用数据

动态函数调用数据为一个程序动态运行一次产生的函数调用记录,这些记录以表格的形式存储,每一条记录包含三个字段:caller、callee和index。

其中caller字段保存了调用函数的名称、callee字段保存了被调用函数的名称,这两个字段的数据类型为STRING型;

index字段保存了函数调用的索引,数据类型为INT型。

通过index字段的值I

如表1所示,为一个PHP程序动态运行一次产生的函数调用数据示例:

表1:

步骤2:将原始数据转换为带索引信息的层次结构数据。

将步骤1得到的原始数据(一种二元时间事件序列模型)转换为层次结构的数据(树模型)。根据函数之间的调用和被调用关系来确定层次结构中的父子关系,合并同一个父节点下的相同调用边同时记录调用发生所对应的索引。

步骤2.1:初始化集合Funccall_set,用于记录所有的调用边对象。按照index的值,升序遍历步骤1中得到的动态函数调用记录,将每一条记录中caller和callee的组合视为一个调用边对象caller|callee。如果caller|callee不在Funccall_set中,那么将其添加到Funccall_set中,并记录相应的属性:调用者(caller)、被调用者(callee)和所有调用索引(all_index);如果caller|callee在Funccall_set中,那么更新all_index属性。例如,在表1所示的数据中,调用者为_func2函数,被调用者为hex2bin函数的调用,对应的调用边对象为:

{name:"_func2|hex2bin",//调用边对象的名称caller:"_func2",//调用者,即调用边对应的源函数callee:"hex2bin",//被调用者,即调用边对应的目标函数all_index:[3,4,5,6]//调用边所对应的所有索引组成的数组

}

步骤2.2:对Funccall_set进行遍历,生成以程序的入口函数作为根节点的层次结构数据Hie_calldata。例如,在表1所示的数据中,__main__函数为根节点,它作为程序的入口函数调用其他函数,而自身不会被调用。被__main__直接调用的函数作为__main__函数的子节点,以此类推,完成递归。最终会将表1中的原始数据转换成如下所示json格式的树形结构数据:记录函数节点名称(name)、函数节点所在深度(depth)、函数节点的子节点(children,如没有子节点则不记录该属性)、函数节点被其父函数调用所对应的所有调用索引(all_index,根节点不存在该属性)。

/>

步骤3:基于广度优先遍历算法确定函数节点布局及设置调用连边属性。

根据步骤2.2获得的层次化数据Hie_calldata进行布局,生成相应的树节点数组和连边数组。树节点数组记录每一个函数节点对象,包括基本属性——函数名称、函数节点在树结构中的深度,以及布局属性——在画布上的位置(x、y轴的坐标)。树连边数组记录每一条连边对象,包括两个基本属性——连边所对应的源节点对象和目标节点对象。

函数节点分层布局,即从根节点到叶子节点从上往下延伸,根节点布局在最上层;此外,实现布局紧凑化和节点左对齐,即不同层之间保留较小的间隙,同一层节点之间也保留较小的、等大的间隙,从左往右延伸。父节点和其每个子节点之间形成一条连边,要判断连边是否为父节点到其第一个子节点的连边,并作为布尔属性isfirstLink记录在连边对象中。

步骤3.1:定义一个起始位置的坐标(start_X,start_Y),函数节点之间的水平间距node_spaceX,节点之间的竖直间距node_spaceY。初始化一个函数节点数组tree_funcnode,和一个函数调用连边数组tree_calllink。

步骤3.2:对步骤2.2中获得的层次化数据Hie_calldata进行广度优先遍历,此步骤基于循环来实现,将函数节点对象添加到tree_funcnode数组中,将函数调用连边对象添加到tree_calllink数组中。根据布局紧凑化和节点左对齐的设计原则,确定函数节点的位置,其中深度为d,即第(d+1)层的第i个节点N

N_x

N_y

也就是说,根节点的坐标为步骤3.2中定义的起始位置坐标;每一层的第一个函数节点的x轴坐标都为start_X,任意一层中第i个节点的x轴坐标为(start_X+(i-1)*node_spaceX);第(d+1)层节点的y轴坐标为(start_Y+d*node_spaceY)。

每一个连边对象中除了该调用边的源节点(父节点)和目标节点(子节点),还要记录该调用边是否为父节点到其第一个子节点的连边:如果是,isfirstLink的属性值为TRUE;如果不是,isfirstLink的属性值为FALSE。

步骤3.3:由于程序的入口函数为根节点,单独位于一层中,为了节省竖直方向上的空间,移除步骤3.2得到的tree_funcnode数组中的根节点对象(本例中为__main__()函数节点对象);移除步骤3.2得到的tree_calllink数组中的根节点到其子节点之间的调用连边对象。因此在下一步中不会绘制根节点及与之相关的连边。

步骤4:绘制层次化的函数调用概览。

根据步骤3.3中得到的tree_funcnode和tree_calllink,分层绘制函数节点和调用连边。将函数节点编码为等大的方块,将函数名称标记在方块内部,并显式绘制父节点到其第一个子节点的调用连边。层次化的布局可以确保动态函数调用数据中层次信息的呈现,连边则保证了二元信息的呈现。

步骤4.1:定义方块的边长为node_size(node_size

步骤4.2:定义连边颜色为中灰色(#595959),样式为正交折线。

步骤4.3:遍历步骤3.3中得到的tree_funcnode,以函数节点的x轴和y轴坐标为方块的左上角,在画布的相应位置绘制边长为node_size的函数节点;根据函数节点对象中all_index属性值中记录的索引数目确定函数节点的填充颜色;并在方块内部居中显示函数名称。

步骤4.4:遍历步骤3.3中得到的tree_calllink,判断连边对象中isfirstLink的属性值,只有属性值为TRUE时,才绘制连边。这一连边绘制原则是为了消除紧凑布局中折线连边带来的二义性(如图2(b)所示)。步骤4绘制好的动态函数调用概览视图如图2(c)所示。

步骤5:将函数调用的索引区间映射到节点高度上。

由于节点是等大的,方块状的,因此将节点的高度作为时间轴,将动态函数调用数据的索引区间映射到节点高度上,以展示细粒度的动态函数调用的时序信息。

获取动态函数调用数据的index区间[0,I

h_singleIndex=node_size/(1+I

步骤6:绘制细粒度的函数调用。

在函数节点上进行图元设计,使用绘制在方块相应高度上,与节点同宽的水平条来表示该方块所对应的函数被其父节点调用的时序信息;同时借助水平条的颜色来编码被调用函数的类型。

步骤6.1:定义水平条的高度为步骤5中计算得到的h_singleIndex;定义水平条的宽度和节点边长相等,为node_size;定义水平条的默认颜色为深灰色(#888888)。

用户可以按需通过水平条的颜色来编码其他类型的信息,如本例中借助水平条的颜色来编码被调用函数的类型,颜色映射比例尺如下:

var typecolor=d3.scale.ordinal()

.domain(["COMMAND","FILE","STRING","ENCODE","ENVIRONMENT","OTHER"])

.range(["#EF8AB0","#997AC9","#5BCAE8","#5AC599","#F7C848","#888888"])

步骤6.2:步骤3.3得到的tree_funcnode中,每个函数节点对象中都记录了函数的名称,函数被其父节点调用时对应的索引all_index、函数节点的x、y坐标等属性。循环遍历tree_funcnode,对于每一个函数节点对象N

H_x

H_y

进一步地,水平条的颜色按照步骤6.1中设置的比例尺typecolor进行设置(此步骤需要用户按照自身需求维护一个关于函数名称与函数类型的字典,在字典中查找函数节点对象N

另外,由于单个函数节点内部水平条的数目同样可以反映函数被调用的频率,因此用户可以选择性地取消函数节点本身的灰色饱和度编码。

绘制完成以后的效果如图2(d)所示,相比于传统的Reingold-Tilford算法下的树布局(图2(a)),本发明提出的布局紧凑化和节点左对齐能够在可视化动态函数调用数据时取得更好的可比较性和可扩展性。

此外,相比于传统的力导引节点链接图,正交树、冰柱图、大规模序列视图等,本发明能更全面、综合地展示动态函数调用数据中的二元、层次和时序信息。

本发明为程序开发人员、程序测试人员、安全管理员等目标用户提供了强有力的动态函数调用数据分析手段,帮助用户高效完成程序理解、程序测试、恶意文件检测等工作。

图3展示了一组程序测试过程中的实施例,

图3(a)是一个PHP程序的源代码;

图3(b)和图3(c)分别是该程序在不同输入“68656C6C6F77”、“6576616C”下捕获到的动态函数调用数据;

图3(d)和图3(e)分别是相应的可视化结果。

分析可视化结果可以发现,在输入“68656C6C6F77”的情况下(图3(d)),程序共调用了9个函数,产生了26条函数调用记录,嵌套深度为2层;其中substr()、hexdec和chr函数对应的方块中均有6条蓝色的水平条,表明存在对字符串类型函数的连续调用模式(strProc→substr、strProc→hexdec、strProc→chr)。

相比之下,在输入“6576616C”的情况下(图3(e)),嵌套深度同样为2层,但一共调用了12个函数,产生了23条函数调用记录;同样存在对字符串类型函数的连续调用模式,但是连续调用的次数有所差异。这是由于输入的字符串不同导致的。进一步分析可以发现,第一层中的eval函数是系统命令类型的函数,属于PHP语言中的敏感函数,可以将字符串当作PHP代码来运行,具有一定的危险性,eval调用的phpinfo函数,会导致环境信息或配置信息的泄漏。

因此,测试人员可以通过本发明提出的动态函数调用可视化方法快速发现该程序具有一定的安全风险,应该修改完善。

更多的实施如图4所示。

对于本领域技术人员而言,显然本发明不限于上述示范性实施例的细节,而且在不背离本发明的精神或基本特征的情况下,能够以其他的具体形式实现本发明。因此,无论从哪一点来看,均应将实施例看作是示范性的,而且是非限制性的,本发明的范围由所附权利要求而不是上述说明限定,因此旨在将落在权利要求的等同要件的含义和范围内的所有变化囊括在本发明内。

此外,应当理解,虽然本说明书按照实施方式加以描述,但并非每个实施方式仅包含一个独立的技术方案,说明书的这种叙述方式仅仅是为清楚起见,本领域技术人员应当将说明书作为一个整体,各实施例中的技术方案也可以经适当组合,形成本领域技术人员可以理解的其他实施方式。

相关技术
  • 一种油井生产动态监测数据的集中可视化展示方法
  • 一种面向多源全球海洋大数据的动态可视化方法及系统
  • 一种支持项目管理的动态协作关系可视化技术评估方法
  • 一种基于恶意行为函数调用图的安卓应用程序安全可视化分析方法
  • 一种基于恶意行为函数调用图的安卓应用程序安全可视化分析方法
技术分类

06120115921269