宏病毒检测问题

宏病毒检测问题
Vesselin Bontchev
译者 DoomLeo


        用流行的办公室应用程序(如 MICROSOFT WORD)里的宏编程语言编写的病毒变的非常的普遍。和只有一个实体的MS—DOS病毒不同,宏病毒通常由一整套数个独立的宏组成。这引起了特定病毒的反病毒软件试图准确识别这个病毒时产生的一些有趣的理论问题。两个病毒的宏集能拥有相同的子集----或者一个宏集是另一个宏集的子集。本文论述了由此所引起的问题,其中有的问题如果是并非不可能解决的,其也是非常困难的。重点是病毒作者是如何开发出这些难点的,以及反病毒产品应如何提高以阻止这样的攻击、避免在错误识别文件内的病毒并试图删除错误的病毒变体而对用户文件所造成的损坏。
 
1.识别具体病毒的需要
        在我们开始处理宏病毒识别之前,值得提及一下为什么通常具体的病毒识别尤其是具体的宏病毒识别非常重要。毕竟从历史上来看,大多数扫描器的工作原理是通过找到病毒的一小部分,并把它当作一个‘扫描线索’去检测该病毒的其它所有的实例。然而这种方法也存在几种缺陷。
        首先,该方法带来错误识别的真正危险----也就是说,将一种病毒(例如:一个破坏性的病毒)和另外一种病毒(例如:没有破坏目的的病毒)混淆。在过去的一年中,我们看到一个反病毒制造商通过发布一个新闻警告具有破坏性的病毒(TEDIOUS)即将爆发。根据该发布会,该病毒传播很快----当然它们敦促人人购买哪个反病毒制造商的反病毒程序。哪个新闻的发布一开始在资深的反病毒的研究者中引起了困惑。即使我们抛开利用恐惧战术说服公众购买其产品所引起的伦理问题。众所皆知TEDIOUS病毒并没有传播开来。最重要的是它也没有一个爆发日期也没有一个有效载体。也就是说没有破坏的企图。事实表明,所说的病毒制造商的扫描器使用扫描字符串不能区别TEDIOUS和BANDUNG----后者是即能传播又具有破坏性的病毒----因此导致了新闻发布所引起的混淆,毫无疑问,对那些发布新闻的人带来了负面影响。相对而言这件事对用户而言没有什么危害,但是我们很容易想象错误识别所带来的相反的错误。也就是说,一个具有破坏性的病毒被反病毒制造商报告为无攻击性的病毒而没有向用户报警。
        其次,在去除病毒(杀毒)时对所发现的病毒的精确识别由为重要。错误识别会导致企图去除错误的病毒变体----使被感染体遭受致命的损坏而不能修复。这在DOS病毒领域已经足够重要。然而在宏病毒领域甚至更为重要。因为,令人信服的是恰当移除DOS病毒的方法是用未染毒的备份拷贝覆盖被感染体来破坏被染毒体。在这种情况下,无论染毒体内的病毒是否被准确识别是没有太大关系----被感染体无论如何已被损坏了。然而,宏病毒通常存在于文档里----其必定经常变化,并且其未染毒的备份拷贝通常不可用。因此,通过移除被感染文档内的宏病毒来杀灭宏病毒是必须的----并且最终重要的是正确的完成杀毒,并不破坏文档和内部存在的用户定义的宏。如果没有准确识别病毒的方法,则这一目标完全不能足够稳定的实现。
        第三,准确识别病毒对技术支持的原因通常是必需的。用户经常问我们“这个或那个病毒在做什么?”----因为问题中的病毒在它们的机器中被发现并且它们想知道病毒会对它们的数据做些什么?如果发现病毒的扫描器不能准确的识别病毒,正确回答这样的问题通常是不可能的。通常一个具有巨大破坏力的病毒(如数据骗取病毒 WM/Wazzu.A)和其不做任何事情的变体之间的不同仅仅只是一个字节----甚至是一个二进制位。这种级别的识别仅凭扫描字符串实际上是不可能达到的。达到这种水平的唯一方法是计算病毒体的不改变部分的所有二进制位的某种校验和来完成。
        第四,准确的识别病毒对于正确的报告和跟踪计算机病毒的传播是必要的。这类信息的一个权威资源叫做WildList,由反病毒研究者Joe Wells维护。许多测试者将其用为哪些病毒包含在in-the-wild测试集里的信息源。近来,事实表明这一列表不能准确识别其罗列的一些病毒,使我们的扫描器在一个对比的评论中得到不利的评分。这一列表列举了Plagiarist病毒。事实表明,有几个不同的病毒,其都是Plagiarist家族成员,我们的扫描器可以检测出其中之一----真正的“在野”病毒,其被最初报告给Joe Wells。然而它不能检测出另外一个变体----这一变体并不“在野”。然而由于WildList提到的正是“Plagiarist”并不是识别具体的变体。一个测试者使用一个我们的扫描器不能检测的病毒变体,并在评论中写到我们的产品不能100%检测in-the-wild病毒集所收录的病毒。人们可以想象关于宏病毒相同的灾祸。
        第五,准确识别病毒可以强有利的阻止绝对错误。众所周知仅用单一扫描字符串检测病毒的扫描器经常引起绝对错误----即,报告某些干净的文件内包含有病毒,这些文件包含了被扫描器用来检测病毒的相同的字节序列。相同情况下,准确的病毒检测决不会导致这样的灾祸----因为如果它检测到文件内有病毒,她仅仅意味那儿有病毒;这毫无疑问,因为其每一个二进制位被辩识并发现其存在。实际上,使用准确病毒识别的产品产生的绝对错误通常远小于(几乎没有----除非其试图检测新的病毒变体,而这时准确病毒识别没有被用到)依靠扫描字符串的反病毒产品。
最后,准确病毒识别本质上是处理VBA宏病毒(既,宏病毒用Excel和Office97工具包编程语言所编写的)的唯一方法。这因为,由于其设计,VBA程序包含许多可变的区域(其包含公共标识区的指针----文档中所有VBA模块的公共部分)。其结果是,可能的扫描字符串平均长度仅为两字节----显然不适合所有的实际应用。这一问题可用超长通配符扫描字符串部分地解决----即扫描字符串内公共标识区域变量指针的位置上,包含‘不关心’的字节。不幸的是,这也不是一个好的解决方法,因为不同的VBA代码片段可被编译成为完全相同的映像----不同仅仅在于标识指针被解析之后。显然,这将提高绝对错误的危险甚至情况会更糟。
由于所有上面提到的这些原因,我认为,准确检测其宣称可以检测的病毒对特定病毒的反病毒产品(例如,扫描软件和杀毒软件)是十分重要的。在宏病毒的情况,准确识别甚至更为重要,因为宏病毒行为的明显改变只是其其中一个宏的极小的改变的结果。通常,我们自己的宏病毒扫描器严格地努力准确检测其宣称可检测的每一个单个宏病毒----并且力劝所有其它的反病毒产品在执行其扫描器时也采用相同的方法。幸运的是许多厂商意识到准确宏病毒识别的益处----我们看到许多反病毒产品开始使用这个方法。在许多情况下,即使扫描器没有应用准确检测病毒的方法于其检测的DOS病毒,其至少应用准确检测病毒的方法于其检测的宏病毒。

2.定义
        每一个设计良好的反病毒方案应基于对它试图解决的问题的仔细的定义。因此,设计一个用于检测,识别、确认和移除宏病毒应基于对什么是宏病毒是什么的好的定义。在DOS病毒的世界,定义病毒为可以复制的程序是足够了。在宏病毒的世界,然而情况并不这样简单。宏病毒并不必须由单个程序组成(即,一个单一宏)。它可以由许多宏组成(例如,病毒WM/Xenixos.A:De由两打宏组成),其中一些或多或少的相互独立。
        独立的含义是什么?这包括三方面。
        第一,由于WordBasic是解释语言,所以容错性高。也就是说,一个宏的一些部分被损坏----但是,如果其从不接收控制(或者接收到的控制很少----例如,如果是在病毒体里),错误从不(或极少)出现。(事实上,这可以用于攻击某种反病毒程序;参阅[Bontchev96]。)此外,用于拷贝的命令(例如 ,MacroCopy)通常占用仅几行(行数与将要拷贝的宏数一样)。也就是说,错误恰好发生在病毒负责拷贝的部分的可能性相对很小。
        第二,WordBasic有高效的错误扑捉功能----并且被病毒作者通常大量使用。例如,如果一个病毒在其宏的开始包含操作
                    On Error Resume Next
即使控制被转换成不完整的行,程序将简单的忽略错误并且从其后,WordBasic解释器能够解释出某些含义的第一行继续执行。
        第三,许多宏病毒的编写使用的巨大的冗余。我们倾向与认为这是十分象是病毒作者的懒惰而不是其有远见。如果它们想要制作一个病毒能够截获几个系统的宏并且因此在好几个可能的用户行为中进行复制(例如,FileSaveAs,FileSave,FileNew等),容易做到的是在所有这些宏内拷贝病毒的复制部分代码而不是将其放在一个被所有这些宏调用的一个单一的宏。结果,即使病毒宏其中的一个被损坏不能再被使用(或者甚至完全丢失),病毒仍旧有繁殖能力----虽然其完全的行为好象有一些改变。
所有这些(还有下一节所描述的其它事实)迫使我们定义宏病毒不是单个的程序----而是宏的集合。特别的我们使用以下定义:
                    定义:宏病毒是能够循环复制自身的一个或多个宏的集合。
        以上定义的一些部分序言更进一步的说明。尤其是‘循环复制’我们所指的是一个被感染的文件能够传播病毒到另一个文档,则另一文档能够继续传播病毒,等等。如果某个宏集合只能在其它地方拷贝自己一次,那么它并不被认为是病毒。(我们称之为‘Intended’----因为病毒作者经常试图制造病毒程序,但由于错误,病毒不能复制自身超过一次----病毒作者从未发现的缺陷,因为象多数的病毒作者,它害怕在自己的计算机上运行测试它。)
        此外,许多宏病毒模仿第一个宏病毒WM/Concept.A,由存在于全局模板和被感染文件中,不同之处较少的宏集组成。因此,根据经验,认为宏病毒是可以复制的一对宏集是有意义的。病毒宏集其一在于被感染的文档中,另一个在于被感染的全局模板中。
        以上定义的主要结果是,不同的宏集组成不同的病毒----即使是一个宏集是另一个的子集。再者,即使一个宏集由两个已知的宏集的一些元素组成,其仍然是第三个新病毒。当下一节讨论不同的和新的病毒时,这一点必须牢记。
        需要强调的是许多本文描述的宏病毒的识别问题与前面给出的术语‘宏病毒’的定义紧密相关。甚至其中有些似乎不可解决的问题在选择该术语的其它定义时能够被完全消除。
        一个非常吸引人的定义依靠于认为宏病毒是完全独立没有任何关系的宏的观点。例如,根据这种提议,文档中没有包含WM/Concept.A病毒,相反,其被认为是包含了宏WM/Concept.A#AAAZAO(这个宏的两个拷贝;第二个在AutoOpen之下),WM/Concept.A#AAAZFS和WM/Concept.A#Payload。
        不幸的是这种定义还存在其它的,十分困难的实际应用问题。例如,报告‘文档中有WM/Concept.A#AAAZFS病毒’似乎很蠢----因为这个宏只依靠自己而不被宏集的其它成员所支持是不能复制的,因此它不是病毒。此外,两个已知病毒的宏在同一台计算机中相遇,能够导致病毒杂交产生新的自我复制的宏集。(这一过程的详细描述,参阅[Botchev98]。)这一新的自我复制的宏集通常其特性和行为与原始的两个宏集中的任何一个的特性和行为都十分不同----并且因此认为其是一个新病毒是十分有意义的。
由于此原因,我们在着一节的开始给出的定义是十分方便实用的。我们不强调其是完美的----但它显然是目前我们可以讨论的最好的一个。因此,我们的反病毒的产品(和我们认识到的其它几个反病毒产品)基于这个定义。在本文的剩余部分,我们将考虑由它引起的一些有趣的宏病毒识别问题。


3.容易的宏病毒识别问题
        在这一节我们将讨论一些相对容易解决的宏病毒识别问题。这些问题按难度增长的顺序给出。


3.1.退化病毒或Rapi病毒问题
        随着所谓的WM/Rapi.A病毒的出现,宏病毒识别的第一个问题就产生了。这一病毒有下面的宏组成:

Document: Global template
AutoOpen RpAO
RpAE RpAE
RpFO RpFO
RpFS RpFS
RpFSA RpFSA
RpTC ToolsCustomize
RpTM ToolsMacro
 AutoExec
 FileOpen
 FileSave
 FileSaveAs

        然而由于此病毒的一个宏内一个缺陷,当病毒通过File/Save(相对应的File/SaveAs)被复制,它的一些宏没有被拷贝。本质上这导致了一个新的宏集----仍旧是病毒并且因此是一个新病毒。这个新的退化病毒看起来是这样的:

Document: Global template
AutoOpen RpAO
RpAE RpAE
RpFS RpFS
RpFSA RpFSA
RpTC 
RpTM 
 AutoExec
 FileSave
 FileSaveAs

        然而这一新的宏集并不稳定。它几乎立即再次退化为一个新的、更为精简的宏集。得到的第三个退化的宏集仍然具有拷贝自身的能力,它仍然不同于前两个宏集----因此,它是一个新的病毒。此外,它变的稳定----在它不再继续退化的意义上。它变为这样:

Document: Global template
AutoOpen RpAO
RpAE RpAE
RpFS RpFS
 AutoExec
 FileSave

        此退化的主要结果是每一个WM/Rapi族的主变种能够潜在的产生两个新的变种。例如,存在WM/Rapi.A会产生WM/Rapi.A1(退化的第二阶段)和WM/Rapi.A2(退化的第三阶段)。此外这样的新变种相对经常的产生。由于病毒的AutoExec/RpAE 宏相对大并且不负责任何方式的拷贝过程(它包含病毒实体),它容易被损坏或夺取----也就是说,被另一个病毒或合法的宏工具包的其它同名宏所取代。(更多关于宏夺取的信息,请参阅[Bontchev98]。)此外,由于这个宏在所有退化的三个时期被保存,意味着单一主变种的损坏导致出现三个新的病毒。改变其它的一些宏(例如,ToolsMacro/RpTM)产生少于三个新的病毒变种,因为这些宏在退化的某些阶段被丢失并且退化变种的结果与其它主变种退化所产生的变种相同。例如,WM/Rapi.C病毒只退化到WM/Rapi.C1;在第三步,先前所知的变种WM/Rapi.A2产生了。这一问题首先被David Chess([ChESS96])发现。其相对容易被解决----扫描器的数据库只须包含WM/Rapi病毒几乎每一个小修改的条目。然而,这将导致这个数据库的大小令人烦恼的快速增长。此外,它有时令人产生迷惑----有些用户很难理解一个包含一种病毒(WM/Rapi.A)的文档如何用两个不同的病毒(WM/Rapi.A1,WM/Rapi.A2)感染它们的文件,其最重要的是不同于原始的那个病毒。


3.2.宏丢失即Dzt病毒问题
        WM/Dzt.A病毒被发现之后不久,第二个问题就出现了。这一病毒由下列宏组成:

Document: Global template
AutoOpen FileSave
FileSaveAs FileSaveAs

        到此为止,一切正常。然而很快我们发现了一个新的WM/Dzt变种,WM/Dzt.B,其组成如下:

Document: Global template
AutoOpen FileSave

        也就是说,病毒的第二个宏丢失了----新病毒仍然具有良好的自身复制能力!更糟的是,我们很快发现市场上的许多扫描器可以制造WM/Dzt.B,如果其不知道WM/Dzt.A以及其处于下列状态:
        1.系统的一个全局模板被WM/Concept.A病毒感染而使其包含宏含了宏WM/Concept.A#AAAZAO,WM/Concept.A#AAAZFS,WM/Concept.A#FileSaveAs和WM/Concept.A#Payload。
        2.随后同一全局模板被WM/Dzt.A病毒感染,结果它的内容变为WM/Concept.A#AAAZAO,WM/Dzt.A#FileSave,WM/Dzt.A#FileSaveAs和WM/Concept.A#Payload。值得注意的是,病毒WM/Dzt.A的宏FileSaveAs覆盖了同名属于病毒WM/Concept.A的宏。
        3.没能准确的检测到宏病毒的杀毒器判断系统感染病毒WM/Concept.A----因为其不知道有病毒WM/Dzt.A并且杀毒器在文件里发现了用于检测病毒WM/Concept.A的扫描字符串。因此杀毒器试图移除通过名字来辩识(而不是根据内容辩识)属于病毒WM/Concept.A的宏。
        结果包含了宏WM/Dzt.A#FileSave的全局模板被保留下来----这正就是WM/Dzt.B病毒!换句话说杀毒器产生了这个新的病毒变种。
这一问题可以通过让杀毒器总是完全准确地辩识染毒的宏集从而被容易的解决。也就是说,根据检测病毒体的固定不变的部分而不是依靠宏的名字来确定其每一个真正的存在的单个的宏。于是,在上面的情况中杀度器会容易地注意到它所认为是WM/Concept.A病毒的一个宏拥有不同的内容。因此,这可能是一个新的病毒并且不应该杀毒----相反,应该要求用户提供一个病毒样本。


3.3.可变宏集即CAP病毒问题
        这一节所描述的问题比前一个问题明显要困难的多。----并且许多反病毒产品对恰当的处理这个病毒的问题几个月来无能为力,此病毒首次呈现出这个特性就引起了我们的注意。这就是WM/CAP.A病毒。
        这个病毒由委内瑞拉的一个14岁男孩制作,在几个星期内野火般的传遍了世界----它仍旧是被经常报道的病毒之一。致使这种结果有接个原因。首先,此病毒与语言版本无关----它可以在世界所有的语言版本上运行。第二,被它感染的文档不表现许多其它WORD宏病毒所表现的典型征兆----WORD并不总是保存它们到模板目录。第三,如上所述,许多反病毒的产品不能恰当的移除这个病毒,因此这个病毒在反病毒产品升级为能处理它之前有相当长的时间传播。
        这个病毒被设计成为由10或者15个宏组成。当感染一个英语版本的WORD系统时,它由宏AutoClose,AutoExec,AutoOpen,Cap,FileColse,FileOpen,FileSave,FileSaveAs,FileTemplates和ToolsMacro组成。宏FileTemplates和ToolsMacro为空。这种表现只为禁止系统的同名的宏,因此避免了‘行窃’的某些限制。保留的宏本质上只是调用宏CAP,宏CAP包含了大部分的病毒并负责自身的拷贝。
        当感染一个非英语版的WORD,除过上面的10个宏外,还有另外5个宏。这5个宏本质上是宏FileColse,FileSave,FileSaveAs,FileTemplates和ToolsMacro不同名的拷贝,其名字决定于具体的WORD的语言版本。
        为达到与WORD语言版本无关,病毒不能通过宏的名字来定位它的宏。相反,它检测菜单的结构,使用处理实现File/Close,File/Save,File/Save As,File/Templates和Tolls/Macro菜单项的系统命令名来作为附加的5个宏的名字。这实际上使得病毒与WORD的语言版本无关。当然它与被感染系统的菜单结构也无关。
        再者,为了确定其宏能被拷贝,它们也不以宏的名字来定位(这使得与WORD的语言版本无关)。病毒在宏的描述里使用百分号(%),并且在复制时,拷贝所有宏到被感染文件时,宏的描述包含这个符号。同样,为了完全确定不和其它任何宏‘杂交’,病毒从想要感染的文档内移除所有的宏。
        不幸的是,由于病毒作者未预料到的WordBasic的怪癖,这一技巧没有达到目的。事实证明,没有描述的宏FOO被拷贝覆盖有描述的宏Bar,结果是宏FOO的宏体替代了宏FOO宏体----然而宏的描述没有被碰到并且保持为宏Bar的描述。(如果两个宏都有描述,则宏FOO替代宏Bar。)结果与病毒作者的期望相反,病毒WM/CAP.A可以与其它病毒的宏或宏工具包的宏杂交----如果这些病毒感染一个已经感染了WM/CAP.A病毒的系统(或如果安装宏工具包到这个已被感染的系统)并且它包含了与病毒WM/CAP.A的宏同名但没有描述的宏。
        最后,由于病毒的所有的复制代码集中在宏CAP内并且所有其它的宏只是调用它,其它的任何宏损坏,替换甚至是删除所产生的结果仍旧具有自身复制的能力,即仍旧是一个病毒。
        这些特性的结果,会产生许多不同的自我复制的宏集,这取决于用户的菜单结构,用户计算机所感染的病毒以及WM/CAP.A。唯一不变的似乎是宏CAP。另外的宏可以冠有奇怪的名字,可以被损坏、攫取甚至丢失(仅宏CAP和其它七个非空宏的其中一个就足够肯定这个宏集是带毒的),或者存在它们中的一些的多次拷贝(当然,宏的名字不同)。将所有这些不同的宏集视为不同的病毒变种明显是愚蠢的。
        因此,我们被迫修订我们关于什么是宏病毒的定义以适用于象WM/CAP.A这样的畸形病毒。实际上我们现在定义病毒WM/CAP.A是包含宏CAP,其它八个宏的一个或数个实例(宏FileTemplates和ToolsMacro都为空,因此它们没有区别),同时至少有一个实例为非空的宏。
如果以上的修订看起来有些复杂是因为它确实复杂。不幸的是,它是到目前为止我们已发现的此类病毒中最好对付的一个。在反病毒产品中实现它也并不容易。作为一个临时的、填补空白的解决方案,一些反病毒产品通过只检测宏CAP来实现病毒检测,并且如果在文档中发现了宏CAP,就删除文档中的所有的宏。这并没有听起来的那样糟,是因为此病毒会删除所以任何方式所感染的文档中的所有的用户宏。
        当然,这整个方法(包括修订定义和它的暂时的部分的解决方案)有一个讨厌的缺点。在其拷贝期间,其会试图攫取一个会极大改变其行为的宏。例如,一个从其它病毒攫取来的自动执行宏使WM/CAP.A会故意破坏一些数据----原始的病毒却没有这一点。用户于是理所当然的想知道,被它的反病毒软件所准确识别的病毒,象WM/CAP.A,一个已知无有意破坏性的病毒是如何突然在13号星期五开始显示信息并且删除文件。不幸的是,如果我们决定认为此病毒的所有可能的不同宏集是不同的病毒的话,将引起是分类和识别的混乱,看起来为解决此问题我们就必须付出这样的代价。


3.4.块拷贝即Cebu病毒问题
        一段时间以前,我们的一个客户发给我们一个文档,此文档被怀疑感染了一个新病毒。事实的确如此。这个病毒显然由四个宏组成----AutoClose,AutoExec,AutoOpen和MsRun。(使用‘显然’这样不严密的术语的原因等一会就会清楚。)当然,只有宏AutoOpen负责病毒的拷贝。宏AutoClose也企图复制病毒,但由于一个愚蠢的错误,总是失败。宏AutoExec是战斗部,宏MsRun被用做“此文件已被感染”的标记。
        问题是病毒的作者显然是一个没有经验的程序员,它作了一些没根据的假设。实际上,它似乎断定它病毒的宏是文档中唯一存在的宏。毕竟可能所有没有染毒的文档在它看来没有包含任何宏。因此,它作了如此的断定并被象一条一条拷贝病毒的宏和指出是否文档或全局模板被感染这样复杂的事所困扰。有一个十分简单的方法----只写一个拷贝所有宏从当前文档到正在被感染的文档的循环就行了(这只需要三行WordBasic代码)。
        因此,如果被感染的文件本身已经包含了一些宏的话会发生什么呢?如果是这样的,那么这些宏将成为病毒的一部分并且被传播到所有其它的被感染的文档。事实表明,病毒的宏集只能增加获取新的的成员而决不会减少!
        第二个问题是,当我们的客户开始怀疑一个宏病毒不能被它的反病毒程序所检测,它会下载ScanPort----微软自己的反宏病毒的反病毒工具。不幸的是,除了ScanPort只能Concept宏病毒外而几乎不能检测任何东西的事实以外,它本身由WordBasic编写并且包含有数个宏。因此,当我们的客户与我们联系时,它所有的文档都含有ScanPort的宏,令人十分不快。
        随后我们收到了同一病毒的另一样本。它从另外的宏工具包攫取了宏,宏AutoExec和AutoOpen被某个反病毒宏所覆盖并且宏MsRun完全丢失。然而这个宏集仍然具有自身复制的能力----也就是说,它是一个病毒。现在,我们称这样的病毒为‘块复制器’。WM/Cebu.A(上面所描述的病毒)并不是此类病毒唯一的一个;还有另外的一对。看起来处理它们的实用方法是只检测负责拷贝的最少的宏,并且,一旦它们被检测到,删除被感染文档的所有宏。毕竟它们已经成为病毒的一部分。这一方法含有上一节所提到的相同的缺陷----一些被攫取的宏会导致病毒行为的剧烈变化。然而,这又似乎是为避免讨厌的使用其它定义方法就会发生的分类混乱所值得付的代价。


4.较难的宏病毒识别问题
        本节阐述一些更难的宏病毒识别问题。第一个问题只在很少的几个反病毒产品中得到了解决。到目前为止,第二个问题尚无另人满意的解决方案。


4.1.理查得(Richard)问题
        下面这个有趣的问题是理查得.福特(Richard Ford)引起我们注意的----当时它是Command软体的一个反病毒研究员,因此我们以它的名字命名此病毒。
        让我们假设我们已知的一个宏病毒FOO,是一个由宏集{A1,B1,C1}组成。然后有人拿到这个病毒,对其中的两个宏进行了修改,因而产生了第二个病毒Bar,Bar是由宏集{A2,B1,C2}组成,其中A1与A2不同,C1与C2不同。该病毒不能被可以查杀已知病毒的具体病毒反病毒产品所识别。
        反病毒产品能够判断出一个含有病毒Bar的文件包含病毒FOO的变种,(也就是说,宏B1是反病毒产品能够识别的)。能够作到这一点,已经很不错了,然而,如果反病毒产品企图对该文件进行杀毒,它也只能移除宏B1----因为这是它能够唯一识别的宏。
        对此,我们假设所产生的宏集{A2,C2}能够进行自身复制(即,是一个病毒)。当然,在复制过程中会产生一个错误----因为其企图复制宏B1----一个不存在的宏,因为它已经被反病毒产品的所移除,然而,如果染毒的宏利用某些形式的错误陷阱(例如:Error Resume Next),复制过程将会成功的完成。
        结果是反病毒产品可能产生一个新的、完全不同于现存的(即FOO和Bar)的病毒。多数反病毒制造商不愿意知道它们的产品会产生新的病毒。
        对该问题的解决有几种可能的途径。首先,有可能将扫描器和与某种归纳分析仪结合起来,并将所有可能的宏从发现了感染已知病毒的文档中删除。不幸的是,正如[Bontchev96]中所演示的那样,有可能利用一大系列的反归纳攻击,并诱使归纳分析仪产生一个“错误否定”----即,使病毒不能被归纳分析仪所探测出来。
        其次,一个杀毒软件能够删除所发现的被某一已知病毒(或某一已知病毒的变种)所感染的文件内的所有的宏。不幸的是,很多的用户历来它们本身的宏,它们发现这个“解决方案”是令人非常不满意的。根据我们的经验来判断,该解决方案从商业角度来看是行不通的。
        第三,一个可能的途径是永远不对发现含有以知病毒残体的文档进行杀毒。该方法有一个很大的缺陷,那就是在很多情况下,完全可行并安全时不进行杀毒是不够现实的。该类例子包括错误杀除的病毒(如,当一些而不是全部的病毒的宏被用户或一些低级的反病毒产品删除时),宏被WORD破坏而不能繁殖的病毒,等等。
        第四,可以将“删除病毒残体”这一动作为可选项(默认为关闭),使用户在必要的时候将其打开。不幸的是,经验表明,大多数的用户缺少在危险的情形下作出正确决定的所必要的反病毒知识和专业知识。我们可以肯定的是,无论开发商给什么样的警告,告诉用户除非知道自己再做什么,否则不要打开这一选项,很多用户以不恰当的方式使用该选项,或者只是“以防万一”时将其打开。事实上,值得争论的是,是用户本身而不是反病毒产品的对新病毒的产生应负责任,它们甚至使用WORD的组合命令来删除一些病毒的宏而产生新的病毒。尽管如此,反病毒产品也不将这个责任推给没有经验的用户反到还好些。
        第五种方法由理查得.福特提出,该方法是对每一个具体的宏来确定判定其存在所必须出现的最小宏集,以用来安全的删除病毒的残体(被称为病毒的最小安全子集)。例如,如果病毒WM/Conceot.A的除了宏PayLoad的所有宏在一个文档中被发现,显然删除这些宏是安全的。也就是说,删除它们不会产生新的病毒,不论文档中是否含有其它的宏----因为宏PayLoad不再会被WM/Conceot.A执行并且其自身不具有病毒的特性。(注意。这只是举个例子;我们并不能说WM/Conceot.A的其它三个宏组成了这个病毒的“最小安全子集”;完全有可能排除其它不是宏PayLoad的多余的宏使宏集进一步缩小。)
        该方法存在这样的缺点,有时它会误把新病毒当作一个旧病毒的残体而破坏(因此,对反病毒研究者来说,是“丢失”)。例如,让我们假设也WM/Conceot.A病毒的变种,其与原来病毒的差异进在于其PayLoad宏的内容。根据上一段所描述的算法所制作的杀毒软件会错误的把它当作原来病毒的残体而将病毒的其它宏从文档中删除。尽管这一行为是“安全的”(从它不会产生新病毒的意义上来讲),文件仍不能被恰当的修复(文件还包含一个不需要的宏----PayLoad,而且这会使杀毒软件无法关闭它们的模板块),并且对反病毒研究者来说,“丢失”了一个新的病毒变种。
        对该方法的稍加改进是删除那些名字与病毒的宏的名字“相同”,却不包括在“最小安全子集”的宏。然而,首先我们认为通过名字对宏的识别是相当不安全、相当不可靠的(应该使用宏的校验和和宏的长度),其次,这种改善仍不能解决新病毒变种“丢失”的问题。
对理查得问题,基于下面的观察,我们已提出了一个较好的解决方案。如果文件中所有发现的宏就是构成病毒残体的宏的话,那么显然删除它们是安全的。如果有任何多余的宏存在,便有可能出现以下情况:
        1、多余的宏属于某个已知病毒的新的,不被人所了解的病毒变种。删除它们是否能够产生新的病毒,新的病毒变种是否是有意制作的,或者是否是一个已知病毒的一个被随即破坏的宏都无关紧要。所有这些情况下,我们都有一个新的病毒变种(尽管一些破坏可能导致一个不能运行的病毒)。因此,正确的方法是不要进行杀毒(即使是病毒的残体----也就是说这些宏可以被识别为一个已知病毒的变种),并且请求用户提供一个病毒样本。
        2、多余的宏属于用户。这种情况几乎不可能发生----只有一个已经包含了合理的宏(这本身就十分罕见)的文件被某种已知的病毒感染,并且不恰当的试图删除病毒----该做法仅仅删除了病毒的一部分宏。由于这种情况相对罕见,我们认为不对文档进行杀毒并且请求用户提供一个病毒样本。
        3、文件被不同的病毒感染,一个已知,一个完全未知,并且我们作了不恰当的努力删除已知的病毒,该努力只删除了病毒的一部分宏。在这种情况下,该文件包含了一个新的病毒。请求用户提供一个病毒样本以便可以对新的病毒进行分析。因此,对不对文档进行杀毒是值得的。大多数的用户可以理解具体病毒的反病毒程序是不能够杀灭未知病毒的。
        以上所讲的内容我们可以用如下简单原则进写概括:
        删除文件中能确切识别的宏病毒的所有宏之后,被感染文档中的宏只是以知病毒的残体,那么删除它们;否则不要删除文档内的任何宏,并请求用户提供一个病毒样本。


4.2.伊格(Igor)问题
        在讨论理查得问题以及其可能的解决方案和对具体病毒识别的总体要求时,伊格.穆特克(Igor Muuttik),博士所罗门软体的一个反病毒研究者将我们的注意力转向理查得问题的自然扩展上,暗示这个扩展含有更多的危险([Muuttik98])。因此,我们以它的名字命名该问题。
        让我们设想一个已知的病毒,Foo由宏集{AotoOpen,Palyload}组成。当一个被感染的文档在一个干净的WORD环境中被打开时,宏AotoOpen被执行。它检测到自己从一个文档中运行(相对于从全局模板中运行),就从被感染的的文档内拷贝宏AotoOpen和Palyload到全局模板然后运行宏Palyload。当一个干净的文档在一个被感染的系统中被打开时,宏AotoOpen又掌握控制。它检测到自己从全局模板中运行(相对于从一个文档中运行),就从全局模板拷贝宏AotoOpen和Palyload到这个文档并且运行宏Palyload。
        现在,让我们假设一个病毒的作者得到这个病并毒建造了另外一个由宏集{AotoOpen,Palyload,AotoClose,NewPalyload}组成的病毒Bar。宏AotoOpen和Palyload与病毒Foo内相同名字的宏相一致并且以绝对相同的方式运行。另外,当一个被感染的文档在一个干净的WORD环境中被打开,宏AotoOpen就被运行了。它检测到自己从一个文档中运行(相对于从全局模板中运行),就从被感染的的文档内拷贝宏AotoOpen和Palyload到全局模板然后运行宏Palyload。当文档被关闭,宏AotoClose得到控制权。它检测到存在宏AotoOpen和Palyload并且被拷贝到全局模板。于是它也拷贝宏AotoClose,NewPalyload到全局模板并且运行宏NewPalyload。同样的,当一个被感染的文档在一个干净的WORD环境中被打开时,宏AotoOpen被执行。它检测到自己从一个文档中运行(相对于从全局模板中运行),就从被感染的的文档内拷贝宏AotoOpen和Palyload到全局模板然后运行宏Palyload。当文档被关闭,宏AotoClose得到控制权。它探测到自己从全局模板中运行,检测是否宏AotoOpen和Palyload存在并被拷贝到正在被感染的文件中,然后也拷贝宏AotoClose,NewPalyload到这个文档并且运行宏NewPalyload。
        如果一个只知道病毒Foo而不知道病毒Bar的扫描器扫描一个被病毒Bar感染的文件,它看起来好象一个感染了病毒Foo的文档----即使扫描器精确识别它所知道的病毒所有宏的每一二进制位。(应当注意的是所有的处理宏病毒的具体病毒反病毒程序对于这种攻击是十分脆弱的,不论是进行精确的病毒检测还是依赖于简单的特征码检测。)如果运行于杀毒模式,它将会删除它所认为的病毒Foo----也就是宏集{AotoOpen和Palyload}。
        宏集{AotoClose,NewPalyload}将继续保留在文档中。然而,以这种方法建造这些宏集是十分可能的,这些宏集组成了第三种不同的病毒,我们称之为Snafu。事实上,当反病毒程序试图从感染了病毒Bar的文档中删除它所认为的病毒Foo时,这第三种病毒将由反病毒程序产生。
        有人会争论,病毒Bar实际上由两个病毒,Foo和Snafu,组成。然而,如果宏集Snafu的宏复杂的方法(检测这些宏是否存在,拷贝这些宏,运行这些宏,等等)引用宏集Foo的宏,这种将宏集Bar分为两个宏集Foo和Snafu的做法使得事情变的含糊不清。再者,病毒Bar可能由许多宏组成并且将它们分为独立的病毒子集会十分困难、不明显的甚至存在几种不同的分法。
        上面描述的攻击方法可以用十分狡猾的方法实现。子集宏Snafu可以不是一个病毒。相反的,它的宏(也就是NewPalyload)只用来检测病毒Foo的宏是否存在。如果它们不存在,一个破坏性的“战斗部”被触发。从用户的角度来看,情况是这样的:用户运行扫描器。扫描器报告一个已知的具体的病毒(甚至可能声称对它已准确识别)并且对它进行删除。用户用WORD打开一个“已消毒”的文档,结果硬盘上的信息被销毁。自然地,用户可能谴责扫描器没能作好这件工作。在这种情况下,争论这个文档被两个病毒Foo和Snafu所感染是十分困难的,因为Snafu自身不是一个病毒。因为它的宏在许多被感染的文档中出现,它甚至不是一个“特洛依”病毒。它仅仅是一个新病毒Bar的一部分。然而,没有可靠的方法使不知道病毒Bar的扫描器指出文档不是被病毒Foo感染而是被病毒Bar感染。通过取得一个流行的病毒,如WM/Concept.A或WM/Wazzu.A,并按上面介绍的方法来设置陷阱,实现这种攻击十分容易的。
        只有这个问题部分解决方案似乎可行。扫描器应该删除被感染文件中的所有的宏,并且用户必须知道这是唯一杀除宏病毒的方法。有用的是,如果具体病毒扫描器与某种归纳分析器联合,文档中发现包含以知病毒时,所有怀疑的宏(可以自身拷贝宏)应该从文档中删除。不幸的是,如[Bontchev96]所述,有许多方法用来攻击归纳分析器并迫使它们产生错误否定-----即,使病毒不能被归纳分析仪所探测出来。


4.3.宏名识别的重要性
        乍一看来,对一个宏病毒扫描器来说,只识别属于病毒的宏的宏体已经足够了,不需要特别留意它们的名字。的确,改变一个宏的名字可以将一个宏病毒转为非病毒。例如,病毒WM/Wazzu.A由单个名为autoOpen的宏组成。如果将其改成其它名字,例如ButoOpen,它将变的不能复制(甚至手动运行----因为宏体用名字“autoOpen”来定位自己),也就是说,它不再是病毒。
        然而,这种特性看起来十分肤浅的。首先,改回宏名是用户容易作到的,因此,警告用户文档中包含的宏可被十分容易的转换为能复制的宏病毒是值得的。第二,宏名看起来属于病毒的环境而不是病毒自身。类似的,一个扩展名优先伴随的DOS病毒如果其寄居的文件扩展名从COM改为其它扩展名,它将停止复制。
不幸的是,事情并不象其一看起来的那样简单。设想下面的例子([Chess97]):
        一个宏病毒,Foo,由两的宏,AutoOpen和Bar组成。宏AutoOpen拷贝自己到正被感染的文档(或全局模板)。然后,它检测宏Bar是否存在。如果宏Bar存在,它正常拷贝;否则破坏性的战斗部被触发。到目前为止,一切正常。其中的技巧是宏Bar的内容与病毒WM/Wazzu.A的宏autoOpen一样。
现在,如果一个不知道病毒Foo也没有注意病毒宏名字的扫描器遭遇一个感染了这个病毒的文档,它会产生伊格问题。它将会“识别”出病毒WM/Wazzu.A并且删除宏Bar,因此留下了有良好自身复制能力的宏AutoOpen。因此,扫描器产生了一个新病毒。另一方面,对于坚持象识别病毒宏的宏体一样识别识别宏名在上面描述的情况中不会出现这样的问题。它将会报告文档被感染(由于在文档内发现已知病毒宏的宏体)但会声明它包含了一个新的病毒----因为宏名不匹配而且文档内还有其它的宏。

5.VBA5识别问题
        Office 97 的到来和一种新的宏编程语言在它应用程序中的普及,VBA5,给我们带来了一大堆新的宏病毒识别问题。虽然许多问题没有上一节所说的困难的宏病毒识别问题那么复杂,反病毒制造商仍然应该知道这些问题。大部分这些问题的引起是由于当包含有WORD宏病毒和EXCEL宏病毒的文档用各自的Office 97的应用程序打开时,存在的WORD宏病毒和EXCEL宏病毒被自动的用VBA5语言重写。不幸的是,正如我们所见,这种转换是不直截了当的、不合乎逻辑的、有缺陷的和不明确的。


5.1.空行
        事实表明,不论从WordBasic还是从VBA3转换为VBA5,在转换时,在程序的开始加一空行。对它自己来说,着并不很糟。不幸的是,Excal97包含双向的转换。也就是说,当它打开一个包含VB3模块的Excal95工作簿时转换它们为VB5模块。然而,允许Excal97的工作簿被存为Excal95格式----并且,不象Word97,然后把VB5模块向下转换为VB3模块。(当保存Word97的文档为Word6.x/7.x时Word97的转换只是简单的忽略VB5模块。)
        实际上,你可以将一个VBA3的模块转换为一个VBA5模块,这在模块的一开始加入一空行。然后你可以将这个VBA5模块转换回VBA3的模块,空行仍被保留。如果你现在再将转换过的VBA3的模块再转换为一个VBA5模块,另外的一个空行又被添加在模块的一开始。在有宏病毒的情况,一个组织刚刚转换到Office 97并且仍旧有许多Office 95的机器,这样的“向上/下转换”循环许多次(因为用户希望以旧的格式保存文件以便于与还没有升级的机器保持兼容)----因此,在病毒的开始处加入了许多的空行。但是,这仍旧是同一病毒。因此,反病毒程序在识别VBA(3或5)病毒时,应该忽略空行。
        或者至少似乎应该忽略Excel病毒一开始的空行。不幸的是,情况要要比这稍微复杂一些。
        最初的错误迹象由病毒W97M/ambler.A---Word97土生土长的(即不是已存的WM病毒向上转换的结果)病毒带来。这一个病毒为了哄骗Tools/Macro对话框并秘密提供一些基本的表格所设计为包含了许多用户的表格。当我们复制它,我们注意到病毒代码的校验和包含了用户的表格,这些表格随不同的拷贝而不同。如它表现的那样,病毒的每次拷贝,一个空行被插入到一个用户表格的代码中。不断的拷贝导致不断插入新的空行。更糟的是,空行不是插入在代码的开始,而是在代码中的任何位置,在表格的定义和被设计用来处理与表格不同部分相关的不同事件(例如,鼠标的点击) 的过程的执行代码之间。为什么会有这样的现象的原因已超出了我们理解范围。这应当去问微软。
        总之,看起来在识别VBA宏病毒时忽略空行是明智的,不论它是用VBA3还是用VBA5写成的,不论是Excel病毒还是Word病毒,无论是空行处于病毒代码的什么地方。


5.2.空格
        另一个WM病毒向上转换为W97M病毒的识别问题由转换器采用对空格一般处理和对制表符特出处理的方法所引起。最初的报告来自Dmitry Gryaznov,就职于博士所罗门的一个反病毒研究者所发现的一些可疑的信息([Gryaznov97])。根据它提供的情况,病毒W97M/Appder.A的第一次繁殖(即,在新病毒获取机会复制之前,就立即被转换器所产生)不知何故与它的复制体不同。
        仔细的检查揭示此不同由包含一个制表符的算子和它结尾的撇号注解引起的。这促使我们研究在不同位置包含制表符WordBasic宏如何向上转换为VBA5模式。结果十分有趣。
        应当注意的是,制表符在VBA5不存在。如果在编辑一个VBA5程序时按下制表键,输入的是一些空格。空格的确切数目决定于光标的当前位置和VBA5编辑器Tools/Options/Editor/Tab的宽度设定的内容。然而,制表符在WordBasic可以自由的使用,并常被用来缩进行。
        显然,当WordBasic程序到VBA5时,转换器将对那些制表符进行处理。它所做的十分合乎逻辑----至少第一眼看起来如此。转换器用上面所述的“制表符宽”项的当前设置转换制表符为相应数目的空格,因此,看起来程序至少被基本保留下来。
        不幸的是,当包含这样的制表符的WM病毒被向上转换时麻烦出现了。事实上,这意味着如果一个WM病毒包含有许多用于行缩进的制表符,不同对制表符宽度设置的计算机将从一个相同的WM病毒产生不同的W97M病毒。而且,用户可能不知道此项的设置值,或者根本不知道存在此设置。显然,如果认为所有的这些W97M病毒是不同的,是非常不方便的。因此,它们被认为是相同的,认为是一个病毒。由于我们通常不知道,是否WM病毒在制造时包含了一些用于行缩进的制表符,所以在识别一个染毒的VBA5模块时,行的缩进必须被忽略。
        但这并不是全部。如它所表现的,制表符只能被用做行缩进。唯一的好消息是它可被用于其它的地方并不多。如果用户插入多余的空格到一个运算符中间,WordBasic和VB5将自动丢弃它。WordBasic当宏编辑窗口被关闭时丢弃它们(因此,它表现为多余的空格在第二次宏被打开编辑时被删除),而VBA5编辑器当光标离开所编辑的行是删除这些空格(因此,这种变化可以马上表现出来)。例如,行


X   =   2   *   2
被自动的转换为
X = 2 * 2
但并不总是这样。有几个例外,在下面给出。
首先,空格在撇号注解的前面。即,行
X = 2 * 2 ' This is a comment

X = 2 * 2  ' This is a comment
产生不同的代码。在VBA5里,撇号注解开始的位置包含在第一个“撇号注解”的P代码指令的操作数里。
第二,空格在操作符:“:”后出现。即,行
X = 2 : Y = 4
和 
X = 2 :  Y = 4
产生不同的代码。在VBA5里,第二个操作符的开始位置包含在“:”P代码的参数里。
第三,空格在Dim声明里AS关键字之前出现。即
Dim X As Integer

Dim X  As Integer

产生不同的代码。这种情况比上两种情况稍微复杂一点。看起来VBA5能够用两种不同的Dim P代码指令,一种用于“在As之前没有空格的Dim”,另一种用于“在As之前有空格的Dim”。第二个的P代码指令包含一个附加的操作数,含有As关键字在行内的位置。
        第四,空格可以用来一个缩进被写成数行的VBA5行的不同部分(在行尾用字符“_”表示续行符)。这与WordBasic里(这里字符“/”被用做续行符)分割行的一部分用制表符来缩进是一样的。因此,当计算VBA5模块的校验和时,用于续行的VBA5P代码指令相应部分应被忽略。
由于上面所描述的所有情况在WordBasic里有相同的情况,并且WordBasic里相同情况可以把制表符当作空格的一部分,着意味着这样的行向上转换的不同决定于VBA5P编辑器制表符宽度的设定。因此,当识别VBA宏病毒时上面所提到的与空格相关的P代码指令的操作符应当忽略。
另一个与空格相关的问题是由VBA注解中连续的空格引起的。简单的说,VBA3允许注解中有连续的空格,而VBA5却不允许(并且删除这些空格)。下面的例子表明了这个问题。
        1)运行Excel95,产生一个新的空的工作簿,然后插入一个模块页。
        2)在模块页输入下面的短程序:

' The following comment has trailing spaces:
'
Sub Test()
 MsgBox "This is a test.", vbOKOnly + vbInformation, "Test"
End Sub

 

        在第二行,开始的撇号后输入几个空格。在光标离开注解里包含有连续空格的行后,如果使光标再回到这一行,然后按End键,光标立即回到撇号的后面,好象没有了连续的空格一样。恐怕不是这样的,相反保存工作簿到一个文件,检查生成的P代码,就会发现连续的空格(与你输入的个数一样)在那里。
        3)退出Excel 95,运行Excel 97打开上一步产生的文档。VBA3宏将被向上转换为VBA5宏。用Excel 97将被转换的文档以Excel 95格式(而不是Excel 97格式)保存到另一个文件,这又宏将向下转换为VBA3格式。
        检查新文件的P代码,会发现不仅在开始初加入了一个空行,而且注释中的连续的空格也不见了。
        因此,识别一个VBA病毒时忽略注解中的连续的空格。
        事实上,还有一种空格被应用的情况,然而,可以证明,这种情况没有引起任何宏病毒的识别问题。尤其制表符可以用于字符串中。然而,转换器处理这种问题十分漂亮,它找出字符串中的所有这些字符,并替换为Chr(9)  。例如,WordBasic行

x$ = "This is a Tab -> <-"
被向上转换为下面的VBA5行:
x$ = "This id a Tab ->" + Chr(9) + "<-"

5.3不确定的向上转换
        由于以上的两个问题迫使我们在识别一个VBA病毒时忽略空行和空格(用于缩进或其它),这引起出现两个(或更多)不同WM病毒能被向上转换为同一个W97M病毒的真正可能。例如,我们研究表明,三个不同的病毒WM/Wazzu----Q,W和AD----会向上转换为同一个W97M/Wazz病毒。(如果使用的是Word的一个早期的beta版,当然正式发行版可以识别WM/Wazzu病毒并拒绝向上转换它们。)这种不确定的向上转换同样会发生在一些其它的WM病毒身上。
        在类似这种情况中,如何命名这些被向上转换的病毒是不清楚的。通常具体的WM病毒向上转换后被分配与原始的病毒相同的名字和变种的联合和W97M平台的前缀。例如,由向上转换病毒WM/Wazzu.A到VBA5病毒所产生的病毒被命名为W97M/Wazzu.A。然而,向上转换不确定的事实打破了这个命名方案。
为了弥补这个问题,我们建议,在这种情况下当向上转换不确定时,由它产生的病毒被标记为能够产生它的最低的变种名。即,在上面的例子中,得到的W97M/Wazzu病毒被命名为W97M/Wazzu.K,而不是W97M/Wazzu.Q或者W97M/Wazzu.AC。


5.4标识符中字母的大小写
        如在本文的其它地方所提到的那样,文件中所有VBA(包括VBA3和VBA5)模块共享一个共用的标识符区(变量名,过程名等)。但不全是这样。此外,当一个新的模块被定位,而且其使用标识符与已存模块的相同,则没有新的标识符被加入到共用的标识符区。问题是,当检测到新的标识符与已存在的“相同”,字母的大小写被忽略。
这让人十分迷惑。例如,如果建立一个VBA模块包含下行的内容


fOO = Bar
然后建立另一个模块,包含下行的内容
bAR = Foo
然后打开编辑第一个模块,它的内容如下所示
Foo = bAR


        哪一个是用户最先输入的并不十分明确。实际上,这两行可以输入到同一个模块内,并且当输入第二个时,第一个字母的大小写被改变。
        在相应宏病毒识别方面应该怎么办呢?这需要在计算模块的校验和和分解指向共用标识符区的指针时(这些指针必须被分解,因为一些十分不同的程序可以被编译为同一个P代码,只是被这些指针指向的标识不同,因此如果这些指针不被分解,对宏病毒的识别会不准确甚至引起错误的判断),忽略标识符的字母的大小写。
        不幸的是,在VBA5的环境中,带来了另外的问题。忽略标识符字母的大小写通常在对比它们之前通过无条件的转换它们为大写或小写的方法来实现。但是,VBA5的标识符允许包含外国(即非ASCII)字符。例如,Francais 在这儿是一个合法标识符。
        不幸的是,没有简单可靠的方法转换外国字符为大写或小写。Windows API 包含有用于这个目的的一些函数(如,AnsiUpper)。然而,它们只适用与Windows程序(即DOS的病毒扫描器不能使用它们)。再者,它们只能在合适的语言版本的Windows环境中正常工作。例如,函数AnsiUpper只能在换捷克语的Windows(或者Windows环境被设为捷克语)环境中才可以正确的转换捷克语字符到相应的捷克语的大写字符。
        一个依靠这些函数的扫描器在识别VBA5病毒时产生的问题暗示,如果在错误的Windows版本中扫描文档,会错过一个包含有外国字符的标识符的病毒。很明显,这种情况不能被接受,特别是病毒本身被存心作成在那种环境中复制没有一点问题。
        此问题最好的解决方案是在转换标识符为大写和生成校验和之前,将包含在标识符内所有的非ASCII字符转换为一些普通的ASCII字符(例如“_”)。这种解决方案所导致的识别算法不能区分两个差别十分小的病毒,但总比完全错过一个病毒要好的多。


5.5其它VBA5识别问题
        不祥WordBasic,VBA含有不是一层而是两层级别的设置。第一层是模块,与WordBaic的宏基本一样。第二层是模块的函数和子程序。它们中被声明为Public(默认的声明)的那些在Tools/Macro对话框可以被看到。
        VBA病毒的功能组件的两层设置使理查得问题和伊格问题可能在出现两个层上。并且,一旦VBA病毒被写成不仅可以攫取其VBA包的模块而且可以攫取这些模块的独立的函数和子程序,这种情况就会发生。
        解决这两种问题的方法看起来类似(所以,伊格问题的解决方法将同样不存在);它们将被应用与两个层上。实际上,改变宏病毒的定义认为宏病毒是一组模块,每一个模块由一组函数和子程序组成,并且将模块当作集合来识别而不但是一个整体,是有道理的。不幸的是,这可能需要一些反病毒产品的一些大的重新设计,被事实所迫之前(即,在VBA子程序攫取病毒被制造之前),这好象不会发生。

6.人工制造的宏病毒检测问题
        上面几节所讨论的宏病毒识别问题可以被称作“自然的”。也就是说,它们的发生不是因为所有宏病毒的一些固有特性(例如,它们不是由单个程序,而是由一系列的宏组成),就是因为宏编程语言及其环境的一些设计缺点。在这最后一节,我们将考虑由病毒作者为了使识别它们的病毒更为困难而人为创造的一些问题。这些问题的分涉及到多态性(也就是宏病毒在自身复制过程中修改自身的能力)的不同形式。
        我们将实现多态性的不同方法的故意的概括描述,因为我们想减少本文对病毒作者有用的部分。同样,我们只列出处理这些问题的基本思想。不幸的是,目前我们的解决方案详细公开的描述可能使它们容易被攻击。因此,除非达到我们能够提出更稳健的解决方案,否则我们仍然依靠通过隐匿来保密,不论这种保护有多么不可靠。

6.1.插入无用行
        宏病毒界中多态性的最简单形式是通过在病毒代码中任意的位置插入无用的行来实现的。它们是WordBaisc运算符,不对病毒的运行产生任何影响并且可以插入到病毒代码的任何位置而对病毒的操作没有任何害(或修改)。通常许多这些无用行由随机产生的注释组成----但它们几乎可以是任何动西,如变量分配,空函数调用等。
        处理多态性的这种形式的最简单的方法是使反病毒程序在识别病毒的宏时能够识别用于不同多态性病毒的无用指令并跳过它们。不幸的是这种方法有两个严重的缺点。
        首先,无用的操作符几乎有无穷的选择。因而不同的多态性病毒何以(并且是经常)采用不同的操作符用做“填充物”。如果一个扫描器认识一系列的无用操作符(被用于扫描器已知的多态性病毒),一个采用不同的无用操作符的新的多态性病毒的出现,将使扫描器必须升级以便于能够处理新的操作符。我们强调的是扫描器的程序将必须升级----仅仅升级病毒检测信息数据库是不够的。这种需要将妨碍扫描器完全通过它的数据库来驱动的尝试。更糟的是,在许多情况下,由于识别算法的改变用来跳过某些后加入的操作符,以前的基于这种算法的数据库内所有条目将必须修正或者升级。这个过程十分耗时而且容易出错。
        第二。病毒作者可能直接瞄准这种方法。例如,让我们假设一个已知的多态性宏病毒使用下面的程序段作为无用的填充物。


If <条件> then
    <操作1>
    <操作2>
    :
    <操作N>
EndIf


        这里,<条件>是永远不为真。如果一个宏病毒扫描器决定通过跳过整个If...EndIf程序块来处理这种类型的多态性,那么另一个被完全写成仅仅使用操作符<操作1>,<操作2>,...,<操作N>的病毒会被扫描器的算法完全跳过。
        为了处理这类问题,扫描器必须有更灵活的特定病毒的算法来忽略无用的操作符,并且这种算法应能被扫描器的数据库所整个控制。


6.2.修改变量字符串
        另一个被多态性病毒所经常应用的技巧是,使病毒随机改变它所用到的标识符(通常被用为变量名)。当然,这种随机改变总在发生----的确,同一个标识符总是被另一个随机产生的名字所代替。同样,病毒也可以以随机的方式改变所使用的一些文字字符串的内容。
        回击这两个技巧相对容易一些。为了解决文字字符串的改动问题,在识别病毒的宏(或模块)时,用于多态性病毒的文字字符串可以被简单的忽略。
        解决随机标识符的技巧稍微复杂一点。扫描器应当建立一个用于宏或模块的标识符的表,并且替换每一个标识符为任意的数字(例如,001,002,003等),使同一个标识符总被替换成同一个数字,不同的标识符总被替换成不同的数字。一旦病毒体被这样封装,就可以计算它的校验和了,而且是唯一的一个,无论病毒如何在复制的过程中改变它的标识符。


6.3.行交换
        另一种可能的多态性可以通过交换附近的代码行来实现,这些行的严格的顺序对病毒的正常运行是不重要的。就我们所知,现在没有以知的病毒使用这个技巧,但这很容易实现。幸运的是,它同样容易被反击。
        为了解决这个问题,使用精确病毒识别的病毒扫描器应该基于每行的计算病毒宏(或模块)的校验和。然后每一行的部分校验和应当相互异或,以组成宏(或模块)的最终的校验和。当用这种方法计算,其校验和与任何行的交换都无关。


6.3.注释行和非注释行
        用于多态性病毒的下一个技巧由增加和删除病毒体某些行之前的注释来实现。这种方法的影响完全改变了这些行内在的表现,并且因此改变可病毒整体的表现。在已知的多态性宏病毒中,WM/Dakota病毒在很大程度上采用这种多态性。它将一个宏的整个内容保存为注释模式(它伴随一随机字符散布,为了使它的每一个复本看起来不同)。在运行中,病毒删除注释,使这个宏可以运行并执行它的任务。
        解决多态性这种办法的简单方法是忽略这个注释行。不幸的是,它有降低识别准确性的缺点。

6.5.加密
        当宏被当作“只执行体”拷贝时 Word使用的宏体的加密(与一字节长的密码异或;密码自身保存在文档中)是微不足道的,并且市场上的许多宏病毒扫描器容易的识破它。此外,病毒作者不能控制所使用的特定的加密密码也不能改变它。最后,这种加密在Word97中不可用----在被保护的工程不能拷贝它们各处的模块。因此,这种加密不适合实现多态性。
        然而,对病毒作者来说,实现一些其它的病毒体的加密方法是可能的。这通过把病毒体的行当作为文本字符串并使用某种扰乱字符串来处理它们。这是一个相对慢的过程,但病毒作者很少有兴趣编制有效率的代码。病毒WM/Slow和WM/UglyKid
        是应用这样的自定义的加密法的多态性宏病毒的例子。
        有几种可能的的办法对付多态性这种方法。不幸的是,它们中的多数依靠病毒中的多态性机制的具体执行----即,依靠具体的病毒。最简单的方法是把病毒加密部分当作文字字符串并忽略它们。这种方法对付WM/Slow时工作很好。不幸的是,它有降低识别准确度的缺点。
更老到的方法的是实现至少是部分的WordBasic(或VBA)模拟器并模拟在运行时病毒执行解密的部分----直到加密的部分被解密,随后,它可以被识别了。这中办法实现起来十分困难。然而我们希望在不久以后,出现更多的多态性病毒,这是恰当处理这类病毒的需要。

6.6.寄生感染
        当前存在的病毒所采用的感染技术基本类似于DOS病毒的写覆盖和伴随病毒。然而,如[Bontchev96]所描述的,为什么真正的寄生感染没有被实现没有实际的原因。这样的寄生病毒不能自身包含;相反,它们寻找其文档中其它的它们试图感染的宏,并修改这些宏来或者完全包含它们的病毒宏,或者至少调用它们。由于很少遇到用户宏,所以只采用这种感染方式的病毒好象不可能成功的传播。然而,这种技术可以联合传统方法,使病毒在缺少可感染的用户宏时可以借助于这个传统的方法。这种联合的感染策略既保证了病毒传播又使对它的识别(有时候是删除)变的十分困难。
        已知的病毒中没有病毒故意使用寄生感染。然而,一些病毒(如WM/Googles)可以修改一些特殊名字(如FileSaveAs)的宏,如果它试图感染的文档中已经存在这些特殊名字的宏。幸运的是,虽然这不是故意的(),这种情况一旦发生,已存在的宏只是被破坏并且病毒不能正常工作。然而,寄生感染技术的彻底实现是十分容易设想的。
为了准确识别这些病毒,宏病毒扫描器不得不借助与识别DOS病毒中的寄生病毒类似的方法。替换使用整个病毒宏体的单一的校验和,扫描器将必须在它的数据库内引入包含由产生校验和的字节范围组成的病毒的映像。再者,扫描器将必须具有某种机制,这种机制被设计成为可以跟踪可以传输控制到病毒体的用户宏内部的指令,这与DOS扫描器采用的跟踪最初的JMP和定位DOS程序中病毒的入口点的机制相似。

7.参考书目
[Bontchev96] Vesselin Bontchev,"Possible Macro Virus Attacks And How to Prevent Them" computers & security, 1996, Vol.15, No.7, pp.595-626
[Chess96] David Chess, 私人信息
[Chess97] David Chess, 私人信息
[Ford96] Richard Ford, 私人信息
[Gryaznov97] Dmitry Gryaznov, 私人信息
[Muttik96] Igor Muttik, 私人信息

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值