国家计算机网络***防范中心博士 宋杨
 
    目前,我们常用的漏洞挖掘有Fuzzing、代码审核等。除此之外,还有一些不是很热门的技术,往往也具有很好的价值。补丁比对技术就是这样一门值得我们关注的“冷门”技术。我们将在接下来的时间里对该技术的现况和发展进行讨论。
 
一、补丁比对技术
    所谓补丁比对技术,在一定意义上上可以被认为是一种漏洞分析技术,或者说,是被用以挖掘以知漏洞的特殊挖掘技术。
    举一个简单的例子对补丁比对技术进行解释:如果一个人的某个手指破了,我们怎样才能知道他究竟是那个手指破了?很简单,只要看他是哪个手指上贴了创可贴就可以了。这里用伤口来比喻安全漏洞,创可贴比喻补丁中修改的代码。那么软件厂商发布安全补丁以后,我们只需要比较补丁里面修改的代码,就能大概知道安全漏洞的位置。
    让我们先简单回顾一下补丁比对技术的历史:
    2004年2月 Halvar Flake第一次提出结构化比对
    2004年4月 Tobb Sabin提出图形化比对作为补充
    2005年12月 iDefense发布了第一款比对工具IDACompare
    2006年11月 eEye发布了 eEve Binary Diffing Suite(EBDS)
    2007年09月 Sabre发布了Bindiff2
    2007年12月 NCNIPC完成了NIPC Binary Differ(NBD)
    2008年01月 David Brumlev等人在IEEE上发表文章,肯定了补丁比对技术在现实环境中的实用价值
    先看一下David Brumlev在IEEE上的文章 是怎么说的:“以补丁比对技术为基础,辅助以数据流分析技术,可以在很短的时间内构建出特定漏洞的***代码。”(根据原文总结)
    按照在这篇文章里所举的几个例子来看,在很短的时间内——不是几天——而是几个小时甚至是在一两个小时,就可以由无到有,从补丁分析开始,到定位漏洞代码,再经过数据流分析,最后得到***代码!这说明补丁比对对于安全人员以及***都是非常有用的技术。我们今天要讨论的主要内容,就是上述四个模块中的补丁自动化分析(比对)。
    一种流行的补丁比对技术被称为结构化比对,其经典算法是这样描述的:结构化比对通过“函数签名”来匹配补丁前后可执行文件中的函数。所谓“函数签名”,是一个三位向量S(i)=(αi,βi,γi)。其中αi表示对应控制流图中的基本块数;βi表示对应控制流图中的边数;γi表示该函数调用的子函数数目。
    当函数签名在补丁前后的可执行文件中唯一且相等的时候,我们就说这两个函数签名所代表的函数是匹配的,即函数之间存在匹配关系。由此,就可以把补丁前后可执行文件中的两个原始函数集合分别划分为两个部分:一部分是存在匹配关系的函数集合;另一部分则是不存在匹配关系的函数集合。根据经典算法的定义,不存在匹配关系的函数就有可能是软件厂商在修复漏洞时,所修改了的函数。因此,我们只需要对这部分函数进行人工审查,就可以大概了解漏洞代码所在的位置,也就降低了逆向分析漏洞代码的工作量,如图1所示。
 
 
图1  IDACompare运行截图
 
    然而,当我们对一个补丁进行分析时,没有匹配关系的函数可能会有很多。从图1可以看出,补丁前后可执行文件中分别有190和173个没有匹配关系的函数。在这种情况下,人工审查的工作量依然很大,远远没有达到理想的状况。因此,一些主流的补丁比对工具,都对经典算法的思路进行了改进。
    图2是EBDS的运行截图。注意图2右侧红色框里的内容。EBDS首先尽可能的把补丁前后可执行文件中的函数匹配出来,无论这些函数是不是存在变动。而后,EBDS依据“Match Rate”(即函数间的相似程度),对配对了的函数进行排序。
 
 
图2  EBDS运行截图
 
    相对的,研究人员首先关注的并不是那些没有配对的函数,而是从配对的函数中,挑选相似程度最低的入手。这就要求补丁比对工具能够将函数尽可能多的进行配对,并且给出一个量化的数值,说明函数的相似程度。当然,这一切都要建立在函数配对的正确性之上。
    依据这样的思路,我们实现了自己的补丁比对工具,称之为NBD(NCNIPC Binary Differ)。相对于经典算法中的简易签名,NBD所采用的签名被大大的扩充了。新增的签名向量是从控制流图、数据流图、函数调用图以及函数之间的其他关系中所引申出来的。
    因为增加了很多些签名向量,我们就能对两个签名向量之间的相似程度进行评分。究竟是有四个签名向量相同还是五个相同?相同的签名向量所占的权重是多大?通过这样的比较,我们就能够给出一个量化了的评分(相似程度)。我们说两个函数是配对的,当且仅当这两个函数同时满足以下两个条件:
    *评分高于门阀值
    *评分相对必须是最高的
举例而言,假设我们分别有A、B、C和X、Y、Z这六个函数,它们之间的相似程度如表1所示。
    表1  相似程度示例(门阀值:0.4)
     
    X
    Y
    Z
    A
    0.9
    0.8
    0.7
    B
    0.6
    0.5
    0.4
    C
    0.3
    0.2
    0.1
    可以看出,A和X相似程度是最高的,是0.9,所以NBD会把A和X配对。尽管对于B而言,它和X相似程度响度是最高,但因为0.6小于0.9,所以B只能退而求其次,和Y相匹配。最后,C只能尝试着和Z匹配,但是它俩的相似程度只有0.1,低于我们预设的门阀值0.4,所以C和Z是不能被配对的。
    图3是NBD的运行截图,同样也将配对的函数按照相似程度升序排列。同时,NBD还对依据函数类型对函数进行进一步的划分,比如“Import Function”和“Export Function”等等,以便于研究人员进一步得分析。这些都是软件的一些细节工作,就不深入展开了。
 
 
图3  NBD运行截图
 
    NBD不仅仅只是完成了上述工作。为了引出NBD的其他特性,我们先把这个阶段的NBD和EBDS进行一下比较。
    表2给出了NBD和EBDS在配对准确性方面的比较。第一列说明了测试的对象,包括微软公司编号为MS07-042,MS07-043,MS07-046,MS07-050四个补丁;第二列说明了补丁前后可执行文件的大小;第三列说明了补丁前后可执行文件中所包含的函数数目。这里给出函数数目并不仅仅是IDA自动生成的函数。而是在IDA的基础上进行了二次处理,目的是为了纠正IDA可能产生的一些错误。第四列是NBD和EBDS两个软件的结果中相同的部分。对于这些相同的配对函数,我们并没有人工验证它的正确性,因为两个软件给出的结果都是一样的,要错大家一起错,要对大家一起对。
 
表2  NBD和EBDS准确性比较
 
文件大小 (KB)
(补丁前/补丁后 )
函数数目
( 补丁前/补丁后)
相同的
函数配对
EBDS独有的
函数配对
NBD独有的
函数配对
07042
1059/1079
7130/6893
6430
38
138
07043
541/537
2993/2993
2967
4
19
07046
275/276
1630/1630
1622
0
7
07050
833/832
4238/4238
4056
0
2
 
第五列是EBDS独有的函数配对。这说明EBDS正确的对这些函数进行了配对,而NBD则没有正确进行配对;第六列则相反,是NBD独有的函数配对。可以看得出来,NBD在函数配对的准确性方面比EBDS要好。
然而,单单把函数匹配起来还是不够的。可执行文件里面有成百上千个函数,配对的目的是为了让人们只需要研究其中的一部分,降低逆向分析的工作量。单将函数配对,并不一定能够降低研究人员的工作量。我们还要看在这些配对的函数里,有多少是需要人工审查的。对于那些没有修改的函数(相似程度100%),就不用去管它了。
这里用MS08-067做一个例子,如表3所示。在这个例子里,EBDS显示有22个函数是修改了的,Bindiff2只有9个。NBD得到的结果显然是最差的,有39个。造成这样结果的原因有很多:有可能是因为NBD配对了更多的函数,也有可能是NBD计算Match Rate的算法有问题。但是无论责任是不是在NBD身上,这个结果都不能让我们满意。
表3  各个工具对MS08-067的性能比较
MS08-067
EBDS
Bindiff2
NBD
修改了的函数(B)
(Match Rate < 1)
22
9
39
是否包含漏洞代码
 
    为了进一步的改进NBD的结果,我们需要跳出补丁比对的框架。我们知道,补丁比对是一种静态代码分析的方法(至少根据现有的材料来看),那么能不能将补丁比对和其他的静态代码分析方法整合到一起呢?答案是肯定的。我们采取的方法,就是把补丁比对技术和代码审核技术整合在一起。
 
二、代码审核技术与补丁比对技术的结合
    大家对代码审核技术应该都有大概的了解。代码审核可以通过词法分析、控制流、数据流分析等方式,找出一个可执行文件里面可能存在漏洞的位置。
    通过把补丁比对技术和代码审核技术整合在一起,我们就能得到两类函数集合:一类是独立的用代码审核工具对补丁前可执行文件进行审核分析以后得出的结果;另一类则是通过补丁比对得到的结果。我们重点关注的就是这两类集合的交集,这也就进一步的缩小了需要人工审查的函数范围。
 
未完待续……