一种基于内存对象访问序列的软件动态胎记及抄袭检测方法与流程

文档序号:13282710阅读:179来源:国知局

本发明涉及软件抄袭检测领域,特别涉及一种基于内存对象访问序列的软件动态胎记及抄袭检测方法。



背景技术:

开源程序的初衷是为了更好的发展开源自由软件,打破商业软件垄断,但仍然有部分利益熏心的公司或个人,违背了软件使用许可,将开源的软件代码通过拷贝或稍加修改后作为自己的商业产品发布,这对软件知识产权的保护构成了严重威胁,软件抄袭检测问题迫在眉睫。

目前软件抄袭检测的方法有基于源代码的检测与基于软件胎记的检测。基于源代码的检测有基于属性统计的抄袭检测,基于结构分析的抄袭检测等,但普遍应用场景不广泛,因为检测者无法轻易获得被检测软件的源代码。而软件胎记指是从可执行文件(比如x86机器上的二进制可执行文件或者java字节码)中提取出的软件特征,又分为静态软件胎记与动态软件胎记,区别在于,前者主要是通过分析软件的词法及结构特性抽取出来的,目前有属性分析法、静态控制流法、静态语义分析法等等;而后者则是在程序执行过程中提取出来的,能更好的刻画出程序语义,反映了程序对输入的处理方式,例如基于系统调用的短序列胎记、动态关键指令序列胎记、栈行为动态胎记等。但需要注意的是,像基于系统调用的动态软件胎记当系统调用数量不多或系统调用被混淆替代的时候,也有很大的局限性;而其他许多软件胎记方法由于过于粗粒度的提取程序语义,其检测率不尽人意。

程序在相同输入下或执行相同功能时程序的实际逻辑中会有不同的处理过程,并且程序访问的内存对象具有较好的语义特征保留。基于此,本发明提出了基于内存对象访问序列的动态胎记软件抄袭检测方法,设计思想是将在高级语言层面上与输入数据有映射关系的函数内部数据结构及其在函数执行中的访问过程作为程序特征集合来比较原始程序和对比程序。利用动态污点追踪方式,来获取程序精确的数据流向,来捕获程序输入在动态执行中对内存对象的访问,以此推导程序用来接收和存储外部输入相关数据的关键内存对象,并且提取这些关键内存对象的属性特征及其访问序列进行软件胎记的语义建模。

基于内存对象访问序列的动态胎记软件抄袭检测方法相较以往基于语义分析的方法,通过对内存对象的追踪,能刻画了更细致的语义模型,能有效抵抗针对语义保留的代码混淆攻击,对大多数混淆方法有较高的识别率,漏判率低,同时能够有效识别功能相似但独立开发的程序,误判率低。



技术实现要素:

本发明的目的是提供一种基于内存对象访问序列的动态胎记软件抄袭检测方法。在程序抄袭修改的过程中,程序用来实现所需功能的所必要的数据结构往往没有或只有轻微的改动,并且程序在功能实现的逻辑过程中对这些必要的数据结构的访问过程也没有太大的变化。这也正是本发明的出发点,即通过将高级语言层面上与输入数据有映射关系的函数内部数据结构及其在函数执行过程的访问作为程序特征集合来比较原始程序和对比程序。

需要注意的是数据结构在二进制层面上的表现形式即为程序在内存中读写的内存对象。内存对象的本质为在栈或堆等内存空间中与高级语言层面上数据结构所相对应的连续字节。

同时为了更准确的刻画实现程序功能的逻辑过程,需要去除程序中存在着的大量冗余的数据结构,因此本发明采用动态污点追踪的方法,只对与输入数据有污点传播关系的内存对象进行分析,并且将输入数据按照输入字段的区别,给予不同的污点标签,以更精确的获取程序的数据流向。

通过更高层次的数据结构及其访问过程来刻画程序的语义,可以得到更加细致的程序语义描述模型。并且这种数据结构与访问过程的结合能充分代表程序的独一无二的语义特征,也能保持更好的可信性。

总体设计即利用动态污点追踪方式,获取程序精确的数据流向,来捕获程序输入在动态执行中对内存对象的访问,以此推导程序用来接收和存储外部输入相关数据的关键内存对象,并且提取这些关键内存对象的属性特征及其访问序列进行软件胎记的语义建模。

本发明基于以下技术方案:

一种基于内存对象访问序列的软件动态胎记及抄袭检测方法,其特征在于,包括:

步骤1,生成基于内存对象访问序列的动态胎记:去除冗余无用的数据结构,保留实现程序功能的必要数据结构,然后对必要数据结构的指令序列进行栈帧识别,得到以栈帧划分的指令序列,识别出栈上的局部变量和堆区在栈帧上的指针,得到程序在不同栈帧中的包含污点标签的内存对象,然后通过用内存对象所在栈帧序号与基地址结合来归一化表示区分特定函数中的特定数据结构,最后将内存对象所在栈帧的变化序列与内存对象的访问序列相结合,构建语义模型;

步骤2,比较基于内存对象访问序列的动态胎记:将两个程序的同一污点标签的键值集合相并,重新构造以相并的键值集合为键值的原程序与检测程序的序列键值对,可以得到两个新的同一污点标签的键值对;将两个新的对应同一污点输入的键值对,进行余弦距离计算,得到在该污点输入下,两个程序之间的相似度得分;最后将原程序与检测程序的不同污点标签的相似度得分进行代权平均计算,权重值根据输入的重要性决定。代权平均值结果越接近1,代表两程序越相似;越接近0,代表两程序独立开发的可能性越大。

在上述的一种基于内存对象访问序列的软件动态胎记及抄袭检测方法,所述步骤1具体包括:

步骤1,污点追踪:为了去除冗余无用的数据结构,只保留实现程序功能的必要数据结构,需要对程序进行动态污点追踪。动态追踪程序的执行过程,通过对输入字段数据缓冲区的污点标记,追踪污点数据在内存中的执行过程,对不同输入字段所影响的字节给予不同的污点标签,在污点传播过程中,若两个源操作数有不同的污点标签,则目的操作数的污点标签为两者的合并。通过污点追踪,获取到程序运行过程中所执行与输入相关的指令序列,在后面步骤中,通过对该指令序列处理来获得内存对象序列。

步骤2,栈帧识别:因为基于变量的切片分析在二进制层面不够准确,同时为了解决指针的别名问题,所以内存对象的识别需要与栈帧相结合。因此在污点追踪后,需要对指令序列进行栈帧识别。栈帧的本质是程序为所执行的函数自动分配的一段逻辑上连续的内存,所以可以根据基址寄存器的变化和栈帧切换语句来对栈帧进行回溯。根据对栈帧切换的记录,可以得到程序的栈帧结构,建立栈帧树。

步骤3,内存对象分析:通过追踪污点数据在内存中的执行访问,可以得到步骤1中的指令序列,并通过步骤2的处理,可以得到以栈帧划分的指令序列。又因为在某一函数的栈帧中,若某内存地址不是由其他内存地址所派生,则该内存地址可能就是某内存对象的基址。同一栈帧中拥有相同基址并且偏移量连续的污点字节可被识别同一内存对象。因此我们可以识别出栈上的局部变量和堆区在栈帧上的指针,即二进制层面的内存对象。通过步骤3,可得到程序在不同栈帧中的包含污点标签的内存对象。

步骤4,归一化表示:在程序函数中一个变量可能会被多次使用,这在二进制层面上来看,则为一个栈帧中的某个内存对象被多次读取或写入。又因为栈是动态分配的,所以指针重用的情况可能会经常发生,受此影响,不同数据结构的基地址可能是相同的,因此本发明通过用内存对象所在栈帧序号与基地址结合来归一化表示区分特定函数中的特定数据结构。这些包含污点标签的内存对象即为所求,其在序列切片中还包含的属性有:字节大小,读或写,污点标签。具体是对程序p在输入i下所识别出的内存对象访问序列如公式(1)所示,其中di为程序p在输入i下所访问的一个内存对象。

s(p,i)=<d1,d2,…,dn>(1)

根据污点标签提取出隶属于不同输入字段的子序列,如公式(2)所示,其中t代表输入字段。

s(p,i,t)=<d1,d2,…,dm>(2)

为了对两个访问序列进行对比,我们可以采用基于k-gram频数向量的比较算法,这同样也是在模糊匹配中所常用的方法。通过k-gram算法,分别对隶属于不同输入字段的序列进行处理。首先,对该序列,利用长度为k的窗口按照步长为1进行滑动,生成一系列窗口长度为k的内存对象访问子序列,如公式(3)所示。

si(p,i,t)=<di,di+1,…,di+k-1>(3)

步骤5,胎记生成:为了进一步提高准确率,对内存对象的访问过程需要与栈帧结构相结合,但程序的栈帧结构不适合直接来构造胎记,因为在抄袭修改过程中,程序调用的函数链可能会产生变化。不过,我们可以利用栈帧切换时的栈帧树的深度变化,因此本发明将内存对象所在栈帧的变化序列与内存对象的访问序列相结合,以构建更准确的语义模型。形式化描述如下:各个子序列的栈帧变化序列记录如公式(4)所示,其中cj为dj与dj-1所在栈帧深度的差值。

ci(p,i,t)=<ci,ci+1,…,ci+k-1>,c1=0(4)

接着将内存对象访问子序列与栈帧变化序列结合,得公式(5):

sci(p,i,t)=<(di,ci),(di+1,ci+1),…,(di+k-1,ci+k-1)>,1≤i≤m-k+1(5)

最后针对sci(p,i,t)(下若无特殊说明,则简写为sci),统计该子序列在总序列中所出现的频数,最终生成一个键值对集合如公式(6)所示:

{<sc1,freq(sc1)>,<sc2,freq(sc2)>,…,<scm-k+1,freq(scm-k+1)>}(6)

该频数键值对集合即为本发明提出的基于内存对象访问序列的动态胎记的表现形式。

在上述的一种基于内存对象访问序列的软件动态胎记及抄袭检测方法,所述步骤2具体包括:

步骤1,构建胎记:待检测程序p在输入i下输入字段t的基于内存对象访问序列的动态胎记如公式(7)所示;同理可得为程序q在输入i下输入字段t的基于内存对象访问序列的动态胎记。

步骤2,键值合并:令的键值集合,的键值集合,然后将两个待检测程序的键值集合相并,如公式(8):

步骤3,重构频率向量:根据公式(9),构建向量ap=(a1,a2,…,a|s|),其中|s|为集合s中元素的个数,si为集合s中的元素;同理可以构建aq

步骤4,余弦距离比较:根据公式(10)计算我们可以得到检测程序针对特定字段而言的相似度:

步骤5,输入字段带权计算总相似度:在对各个输入字段的内存对象访问序列进行比较后,我们可以得到隶属各个输入字段的内存对象访问序列相似度,然后根据公式(11),可以计算出检测程序之间的相似度,其中wi代表输入字段i的权重,n为输入字段数量:

步骤6,抄袭判断:计算待检测程序之间相似度后,若sim(p,q)≥θ,其中θ为相似度阈值,则两者之间存在抄袭关系;若sim(p,q)<1-θ,则两者为独立不同的程序;否则,不确定两者的相似关系。

本发明能有效识别出功能相近但独立开发的程序,误判率低;并能检测出大多数情况下的抄袭检测行为,漏判率低。

附图说明

图1为本发明基于内存对象访问序列的动态胎记生成过程示意图.

具体实施方式

本发明的目的是提供一种基于内存对象访问序列的动态胎记软件抄袭检测方法。该方法通过将高级语言层面上与输入数据有映射关系的函数内部数据结构及其在函数执行过程的访问作为程序特征集合来比较原始程序和对比程序。通过更高层次的数据结构及其访问过程来刻画程序的语义,可以得到更加细致的程序语义描述模型。并且这种数据结构与访问过程的结合能充分代表程序的独一无二的语义特征,也能保持的更好的可信性。

一、基于内存对象访问序列的软件动态胎记及抄袭检测方法主要分为两部分:基于内存对象访问序列的动态胎记生成与基于内存对象访问序列的动态胎记比较。

(一)基于内存对象访问序列的动态胎记生成

基于内存对象访问序列的动态胎记生成过程如图1所示,过程主要分为五步骤:

步骤1,污点追踪:为了去除冗余无用的数据结构,只保留实现程序功能的必要数据结构,需要对程序进行动态污点追踪。动态追踪程序的执行过程,通过对输入字段数据缓冲区的污点标记,追踪污点数据在内存中的执行过程,对不同输入字段所影响的字节给予不同的污点标签,例如md5sum所比较的两个文件内容即为不同输入字段,并且对污点释放给予特殊标记。需要注意的是,在污点传播过程中,若两个源操作数有不同的污点标签,则目的操作数的污点标签为两者的合并。通过污点追踪,获取到程序运行过程中所执行与输入相关的指令序列,在后面步骤中,通过对该指令序列处理来获得内存对象序列。

步骤2,栈帧识别:因为基于变量的切片分析在二进制层面不够准确,同时为了解决指针的别名问题,所以内存对象的识别需要与栈帧相结合。因此在污点追踪后,需要对指令序列进行栈帧识别。栈帧的本质是程序为所执行的函数自动分配的一段逻辑上连续的内存,所以可以根据基址寄存器的变化和栈帧切换语句来对栈帧进行回溯。常用的栈帧切换语句有pushebp;movebpesp;popebp;leave等;根据对栈帧切换的记录,可以得到程序的栈帧结构,建立栈帧树。

步骤3,内存对象分析:通过追踪污点数据在内存中的执行访问,可以得到步骤1中的指令序列,并通过步骤2的处理,可以得到以栈帧划分的指令序列。又因为在某一函数的栈帧中,若某内存地址不是由其他内存地址所派生,则该内存地址可能就是某内存对象的基址。同一栈帧中拥有相同基址并且偏移量连续的污点字节可被识别同一内存对象。因此我们可以识别出栈上的局部变量和堆区在栈帧上的指针,即二进制层面的内存对象。通过步骤3,可得到程序在不同栈帧中的包含污点标签的内存对象。

步骤4,归一化表示:在程序函数中一个变量可能会被多次使用,这在二进制层面上来看,则为一个栈帧中的某个内存对象被多次读取或写入。又因为栈是动态分配的,所以指针重用的情况可能会经常发生,受此影响,不同数据结构的基地址可能是相同的,因此本发明通过用内存对象所在栈帧序号与基地址结合来归一化表示区分特定函数中的特定数据结构。这些包含污点标签的内存对象即为所求,其在序列切片中还包含的属性有:字节大小,读或写,污点标签。

步骤5,胎记生成:为了进一步提高准确率,对内存对象的访问过程需要与栈帧结构相结合,但程序的栈帧结构不适合直接来构造胎记,因为在抄袭修改过程中,程序调用的函数链可能会产生变化。不过,我们可以利用栈帧切换时的栈帧树的深度变化,因此本发明将内存对象所在栈帧的变化序列与内存对象的访问序列相结合,以构建更准确的语义模型。

基于内存对象访问序列的动态胎记生成的准确形式化描述如下:

对程序p在输入i下所识别出的内存访问序列如公式(1)所示,其中di为程序p在输入i下所访问的一个内存对象。

s(p,i)=<d1,d2,…,dn>(1)

本发明从中根据污点标签提取出隶属于不同输入字段的子序列,如公式(2)所示,其中t代表输入字段。

s(p,i,t)=<d1,d2,…,dm>(2)

接下来,为了对两个访问序列进行对比,我们可以采用基于k-gram频数向量的比较算法,这同样也是在模糊匹配中所常用的方法。通过k-gram算法,分别对隶属于不同输入字段的序列进行处理。首先,对该序列,利用长度为k的窗口按照步长为1进行滑动,生成一系列窗口长度为k的内存对象访问子序列,如公式(3)所示。

si(p,i,t)=<di,di+1,…,di+k-1>(3)

然后,各个子序列的栈帧变化序列记录如公式(4)所示,其中cj为dj与dj-1所在栈帧深度的差值。

ci(p,i,t)=<ci,ci+1,…,ci+k-1>,c1=0(4)

接着将内存对象访问子序列与栈帧变化序列结合,得公式(5):

sci(p,i,t)=<(di,ci),(di+1,ci+1),…,(di+k-1,ci+k-1)>,1≤i≤m-k+1(5)

最后针对sci(p,i,t)(下若无特殊说明,则简写为sci),统计其出现个数及频数,最终生成一个键值对集合如公式(6)所示:

{<sc1,freq(sc1)>,<sc2,freq(sc2)>,…,<scm-k+1,freq(scm-k+1)>}(6)

该频数键值对集合即为本发明提出的基于内存对象访问序列的动态胎记的表现形式。

(二)基于内存对象访问序列的动态胎记比较

本发明通过以下步骤来进行对两个基于内存对象访问序列的动态胎记相似度的比较:

步骤1,构建胎记:待检测程序p在输入i下输入字段t的基于内存对象访问序列的动态胎记如公式(7)所示;同理可得为程序q在输入i下输入字段t的基于内存对象访问序列的动态胎记。

步骤2,键值合并:令的键值集合,的键值集合,然后将两个待检测程序的键值集合相并,如公式(8):

步骤3,重构频率向量:根据公式(9),构建向量ap=(a1,a2,…,a|s|),其中|s|为集合s中元素的个数,si为集合s中的元素;同理可以构建aq

步骤4,余弦距离比较:根据公式(10)计算我们可以得到检测程序针对特定字段而言的相似度:

步骤5,输入字段带权计算总相似度:在对各个输入字段的内存对象访问序列进行比较后,我们可以得到隶属各个输入字段的内存对象访问序列相似度,然后根据公式(11),可以计算出检测程序之间的相似度,其中wi代表输入字段i的权重,n为输入字段数量:

步骤6,抄袭判断:计算待检测程序之间相似度后,若sim(p,q)≥θ,其中θ为相似度阈值,则两者之间存在抄袭关系;若sim(p,q)<1-θ,则两者为独立不同的程序;否则,不确定两者的相似关系。

二、下面是一个具体的实施案例。

本发明的技术方案为一种基于内存对象访问序列的动态胎记软件抄袭检测方法,软件抄袭检测过程包括基于内存对象访问序列的动态胎记生成和基于内存对象访问序列的动态胎记比较两个过程。

基于内存对象访问序列的动态胎记生成过程实施步骤:

步骤1,对程序进行动态污点追踪,去除冗余无用的数据结构,只保留实现程序功能的必要数据结构。动态追踪程序的执行过程中,通过对输入字段数据缓冲区的污点标记,追踪污点数据在内存中的执行过程,对不同输入字段所影响的字节给予不同的污点标签,获取到程序运行过程中所执行与输入相关的指令序列。

采用字节级的动态污点追踪的方法,以输入字段数据缓冲区为初始污点数据,并遵守如下规则:

1)对不同输入字段所影响的内存字节给予不同的污点标签。

2)在污点传播过程中,若指令的两个源操作数有不同的污点标签,则目的操作数的污点标签为两者的并集。

3)为了丰富对程序语义的描述,同样需要记录目的操作数有污点标签的释放污点行为指令。

步骤2,在污点追踪后,对指令序列进行栈帧识别。由于基于变量的切片分析在二进制层面不够准确,同时单纯用基地址标识无法解决指针的别名问题,而在分析内存对象的访问序列时需要区别各个内存对象,即内存对象的归一化识别问题。因此需要栈帧识别,为了到达将基地址与栈帧相结合来区分表示各个内存对象的目的。

栈帧的本质是程序为所执行的函数自动分配的一段逻辑上连续的内存,所以可以根据基址寄存器的变化和栈帧切换语句来对栈帧进行回溯。

常用的栈帧切换语句有pushebp;movebpesp;popebp;leave等;我们可以根据对栈帧切换的记录来重现栈帧,基本原则就是一个新的栈帧开始于pushebp、movesp,ebp指令,结束于跟在popebp或leave,以此得到程序的栈帧结构,建立栈帧树。

步骤3,通过追踪污点数据在内存中的执行访问,可以得到步骤1中的污点指令序列,并通过步骤2的处理,可以得到以栈帧划分的污点指令序列。又因为在某一函数的栈帧中,若某内存地址不是由其他内存地址所派生,则该内存地址可能就是某内存对象的基址。同一栈帧中拥有相同基址并且偏移量连续的污点字节可被识别同一内存对象。通过回溯函数栈帧中的执行上下文来分析内存地址的派生关系,以此定位内存空间地址在当前栈帧中的根地址,并使该根地址作为内存对象的基址。因此我们可以识别出栈上的局部变量和堆区在栈帧上的指针,即二进制层面的内存对象。通过步骤3,可得到程序在不同栈帧中的包含污点标签的内存对象。

步骤4,在获取到程序在不同栈帧中的包含污点标签的内存对象序列后,通过用内存对象所在栈帧序号与基地址结合来归一化表示区分特定函数中的特定数据结构。

步骤5,基于内存对象访问序列的动态胎记的表现形式即为有关该检测程序不同输入污点的键值对集合。利用栈帧切换时的栈帧树的深度变化,以固定窗口大小(通常取值3~5),前进步长为1,将同一污点标签的内存对象所在栈帧的变化序列窗口与内存对象的访问序列窗口相结合,作为同一污点键值对的键值,并将对应这些序列的出现频数作为键值所对应的值。

基于内存对象访问序列的动态胎记比较过程实施步骤:

步骤1,对原程序与检测程序而言,其基于内存对象访问序列的动态胎记均为序列长度相等的序列键值对集合。将两个程序的同一污点标签的键值集合相并,重新构造以相并的键值集合为键值的原程序与检测程序的序列键值对,可以得到两个新的同一污点标签的键值对。

步骤2,将两个新的对应同一污点输入的键值对,进行余弦距离计算,可以得到在该污点输入下,两个程序之间的相似度得分。

步骤3,将原程序与检测程序的不同污点标签的相似度得分进行代权平均计算,权重值根据输入的重要性决定。代权平均值结果越接近1,代表两程序越相似;越接近0,代表两程序独立开发的可能性越大。

本文中所描述的具体实施例仅仅是对本发明精神作举例说明。本发明所属技术领域的技术人员可以对所描述的具体实施例做各种各样的修改或补充或采用类似的方式替代,例如对序列窗口长度的取值选择其他合适的值,或单独使用内存对象序列而不与栈帧深度变化序列结合的灵活性保持相邻相关性,但并不会偏离本发明的精神或者超越所附权利要求书所定义的范围。

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