信息安全第6章可信软件和恶意软件防范_第1页
信息安全第6章可信软件和恶意软件防范_第2页
信息安全第6章可信软件和恶意软件防范_第3页
信息安全第6章可信软件和恶意软件防范_第4页
信息安全第6章可信软件和恶意软件防范_第5页
已阅读5页,还剩281页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章可信软件和恶意软件防范

6.1程序安全

程序构成了一个计算机系统的很多部分(操作系统、设备驱动程序、网络基础设施、数据库管理系统和其他应用程序,甚至网页上的可执行命令),因此多种形式保护程序是计算机安全的核心。程序安全除了包括程序的完整性、可用性、保密性外,还包括了程序的运行安全性。众所周知,来自系统外部的恶意攻击的主要目标是计算机系统,其直接的重点目标是信息和数据,以及包含、记录和存储这些信息数据的程序(软件)。程序的丢失、篡改、窃取、非法复制、滥用等对系统造成的后果是灾难性的,对社会造成的影响是严重的和深远的。当一个人在从事软件活动的过程中犯错误时,我们称之为过失(error)。过失可能会在计算机程序中导致一个错误(fault),或者一个不正确的步骤、命令、过程或数据定义。例如,一个设计者可能误解需求,从而创建一个不符合分析员和用户要求的设计。一次失效(failure)就是对系统要求行为的一次违反。在系统发布之前或之后,或在测试过程中,或在运行和维护过程中都能发现失效。早期的计算机安全工作建立在“查找错误并打补丁”(penetrateandpatch)的模式上。分析专家在该模式下寻找错误,并给错误打上补丁。一些顶尖的测试团队尝试各种方法使系统崩溃以测试系统的安全性。这种测试被认为是安全“证明”;如果系统经受住了攻击的考验,就认为是安全的。遗憾的是,这种证明经常成为反面例子,因为系统中隐藏的错误往往不止一个。为了解决这些不断发现的错误,人们迅速开发了许多补丁以修复安全问题,然而,大多数补丁并未起多少作用。相反,它们使系统变得更不安全,因为它们引入了新的错误,其原因有三个:(1)修补指定问题的压力使得人们仅仅关注错误本身,而不是与之相关的上下文环境。特别是分析专家仅专心于研究导致失效的直接原因,而忽视设计或需求方面的原因。

(2)修补一个问题时常导致其他地方的失败,或者说补丁仅仅解决一个地方的问题,而没有解决相关地方的问题。

(3)打补丁可能会影响系统的功能和性能,所以补丁不能适当地修补系统错误。

由于“查找错误并打补丁”模式的不完善,人们不得不考虑其他方法来保证代码满足安全需求。其中一个方法就是对比系统需求和系统行为。也就是说,为了理解程序的安全性,可以检查程序的行为是否符合设计者或用户的需求。6.1.2非恶意的程序漏洞

人都会犯错误,程序员和其他开发者也不例外。其实大部分错误都是无意或非恶意的。大多数错误会造成程序故障,但不会造成特别严重的安全隐患。然而,极少数错误却已困扰了程序员和安全专家几十年之久,并且在短期内无法将其消除。本节将讨论三种典型的错误,并分别解释每种错误,说明它为什么和安全性相关,以及怎样预防或减轻危害。编译器为缓冲区划分了10个字节大小的空间,从buffer[0]到buffer[9],每个都分别占用一个字节的空间,现在我们执行这条语句:

buffer[10]=‘a’;

数组元素的下标超过了缓冲区的大小,从安全的角度出发,这样出现问题了。最好的结果是,编译器在编译过程中就检查出问题并将错误标记出来。然而,如果语句是:

buffer[i]='a';那么,直到i在执行过程中被设置成一个大到越界的下标之前,我们都无法检查出这个错误。如果在执行过程中,系统能产生一个下标越界错误的警告,那将是非常有用的。遗憾的是,在一些语言中,缓冲区大小并不需要预先声明,所以也就无法检查出越界错误。更重要的是,在执行过程中,检查每个下标是否超出可能的最大值需要花费时间和空间,宝贵的系统资源就被这些不常发生的问题浪费了。由于没有合理的方法来定义恰当的限制,所以即使编译器小心翼翼地分析缓冲区的声明和使用,指针也可能引发同样的问题。所以,一些编译器并不产生代码来检查是否越界。我们来更深入地研究这个问题。潜在的缓冲区溢出只是在某种情况下才会造成严重的问题,认识到这一点是非常重要的。问题是否出现取决于邻近buffer数组的内容是什么。假定buffer数组的10个元素的每个字母都用a填充,而错误的引用却使用字母b,如下所示:

for(i=0;i<=9;i++)

buffer[i]=‘a’;

buffer[10]='b';

执行过程中,所有程序和数据都在内存中,它们与操作系统、其他代码和常驻程序共享内存空间。如果这个额外的字符b溢出到用户的数据空间,则它仅仅会覆盖一个已存在的变量值(也可能会写入到一个还未使用的位置),可能会影响程序的运行结果,但不会影响其他程序或数据。如果b被送入用户的程序区域:如果它覆盖了一条已执行的指令,并且该指令以后都不会再执行,用户将不会觉察到影响;如果它覆盖的是一条还未执行的指令,由于b的内码是0x62,机器将会尝试着执行操作码为0x62的指令;如果操作码为0x62的指令并不存在,系统将会由于一个非法指令异常而停机;如果该指令存在,机器就会把后续字节当做这条指令的剩余部分来使用,运行成功与否取决于上下文的含义,只有用户才能感受到缓冲区溢出的影响。综上所述,在带数组的高级语言出现时,缓冲区溢出就随之出现了。最初一段时间,它带给程序员和用户的困扰较小,最多不过出现系统崩溃。而最近,攻击者利用它首先使系统崩溃,然后制造出更多可控制的故障,这就随之导致了严重安全性问题。大量基于缓冲区的溢出漏洞的攻击使人们意识到,开发者不能再像从前那样轻视它,而是必须对缓冲区的溢出给予更多的关注。

2.不完全验证

不完全验证(incompletemediation)是另一个长期存在的安全问题。它常常被攻击者利用。

考虑下面的例子:

/somepage/userinput.asp?parm1=(808)555-1234&parm2=2010Mar11

其中的两个参数看起来一个是电话号码和一个日期。或者客户端的浏览器输入的两个有特定格式的参数值对服务器来说很容易处理,但如果parm2的值被提交为1700Jan1,或者1800Feb30,或是2050Jane31,或是1Rabbit2Many,将会产生错误。一种可能是,如同缓冲区溢出一样,系统将由于尝试处理不正确的数据类型,如年份超过正常能处理的范围(如1700),或者月份超过正常能处理的范围(如Jane),而发生灾难性的故障。另一种可能是接收到这些错误参数的程序将继续运行而得出错误的结果(例如想得到截止到今天的话费账单总额,如果开始日期是1700年1月1日,结果肯定是错误的)。另外,服务器可能会有自己的一套默认处理方式,如将1Rabbit2Many当做1Jan2010来处理。当然,还有其他可能性。然而,改进后的程序仍然是脆弱的。提交的结果最终是包含在URL中进行传递的,而用户可以操作或更改URL,例如:用户可以编辑URL,改变里面待提交的参数值,并重新发送它们。而服务器没有办法分辨出一条回应是来自客户端的浏览器,还是用户直接编辑修改的URL。这样,不安全的参数验证很容易被利用。虽然它没有缓冲区溢出那么频繁,但仍然是一个可能造成严重危害的漏洞,尤其在一些对提交数据要求非常严格的行业和部门。举一简例。一家大型跨国网上购物公司sample进行电子产品的在线销售,这样客户可以通过该公司的购物网站来下订单。一位客户想购买20个编号为123A的物品。如果每个物品的售价是50元,网站将计算出总价格为1000元。然后客户选择运输方式(如快递运输),那么客户端的浏览器会自动按格式填充参数:

3.“检查时刻到使用时刻”错误

第三种漏洞与同步操作有关。访问控制是计算机安全的一个基础部分,确保只是具有访问权限的人或进程才能进行相应的访问。访问请求由访问策略所控制,策略指明了哪些请求允许访问哪些资源。然后,访问策略的执行代理对访问请求进行仲裁。但是,若对访问的检查不全面,就会出现不完善仲裁问题。检查时刻到使用时刻(Time-Of-CheckToTime-Of-Use,TOCTTOU)的漏洞与仲裁在执行中受到诱骗有关。该漏洞也称为序列化漏洞或同步漏洞。举一简例。一位顾客正在买价值100元的衬衣。他从口袋里拿出5张20元的人民币,放在柜台上。店主清点完人民币之后,发现没有问题,于是转过身来开发票。就在店主开发票时,该顾客迅速地从5张人民币中抽出1张,而没有被店主察觉。顾客然后接过店主的发票,拿好衬衣,离开商店。在接受安全性检查(类似该例中的清点钞票)之后到访问(类似该例中的交换衬衣和人民币)之前的这段时间内,一些情况发生了改变。同样的问题,也可能出现在计算机系统中。

假定一个文件访问请求的数据结构包括有文件名和访问方式两个。从本质上来说,该数据结构是一个“工作凭证”,还需要一个“授权盖章”。一旦该操作被授权,它将被放入一个操作队列中。通常,访问控制仲裁器接收该数据结构,并决定是否允许该操作。如不允许,则拒绝该访问并停止操作;否则,将该数据结构送至文件处理器进行处理。为了确定授权顺序,访问控制仲裁器必须在表中查看文件名(及用户ID和其他参数)。仲裁器可以比较表中的文件名与结构体中的文件名以决定这次访问是否适宜。但是,数据结构仍然在用户的区域并在用户的控制之下。这时,就可以对不完整仲裁漏洞进行利用。当仲裁器正在检查文件my_file的访问权限时,用户可以将文件名改为your_file,并将访问方式改为“删除”。由于“工作凭证”已经被读过一次,所以就不能指望仲裁器在批准它之前再去阅读“工作凭证”。仲裁器将批准此次访问并将修改后的描述符送给文件处理器。这个安全问题称为“检查时刻到使用时刻”漏洞。它的安全含义是:检查一个动作而去执行另一个动作,这是一个无效访问控制的例子。我们有两种思路来防止该漏洞被利用。一是确保关键参数在失控时不被暴露,访问检查软件必须拥有请求数据,直到请求完成。另一个方法是确保序列完整性,即在验证期间禁止中断(失控),或者验证程序可以先从用户空间复制数据到程序空间(用户不可访问),并基于该复制执行验证检查,最终,验证程序能够用一个校验来封装请求数据,检测修改。4.非恶意程序漏洞的结合使用

上述三种漏洞在单独使用时都会造成很坏的后果,但更可怕的是,它们还可以结合起来使用。攻击者可以对仅仅使用了缓冲区溢出不大满意,而代之以三重攻击。先借助缓冲区溢出来破坏机器上运行的任意代码,同时它使用“检查时刻到使用时刻”的漏洞来添加一个新的系统用户。接下来,攻击者以新的用户身份登录系统并利用“不完全验证”漏洞获得一定权限来做其他事情。聪明的攻击者可以将这些漏洞当成常用构件块来构造一个复杂的攻击。虽然非恶意漏洞往往造成的危害有限,但一旦被人利用,就会后患无穷。在下一节中我们将会看到,恶意攻击者可以利用看起来无害的程序漏洞编写有害的代码。6.1.3病毒和其他恶意代码

就病毒和其他恶意代码本身而言,程序很少对安全性构成威胁。程序对数据进行操作,只有当数据和状态发生改变并满足其触发条件时,才会执行。程序所做的大多数工作对于用户是不可见的,所以不大可能发现它们在进行危险活动。比如:你知道一个游戏程序在与你的交互行为之外进行了什么其他行为吗?你知道文件档案是以什么方式进行存储的?当你正在对一个文档进行编辑时,其他程序会不会也在非法执行?大多数用户不能回答这些问题。由于用户通常不能直接对计算机数据进行观察,攻击者可以编写自己的程序作为工作来访问和修改其他程序的数据。我们来具体分析恶意代码的特点、产生的原因和分类。1.恶意代码简介

一般没有人会喜欢出乎意料的行为,特别是在程序里面。由于恶意程序员的某种意图,恶意代码是以意料之外的方式运行的。我们把恶意代码看做是系统的潜伏者,它可能是正在运行的程序的全部或一部分,也可能是一个独立程序的一部分,依附于其他正常程序来运行。

计算机病毒并非是最近才出现的新产物。事实上,早在1949年,距离第一部商用计算机的出现仍有好几年时,计算机的先驱者冯·诺依曼(VonNeumann)在他所提出的一篇论文《复杂自动装置的理论及组织的运行》中,已把病毒软件的蓝图勾勒出来了。当时,绝大多数的计算机专家都无法想象到了1983年,计算机病毒的存在被科恩·汤普逊在他的颁奖典礼上向外界正式公开,同时他还告诉听众怎样编写病毒程序。从此,计算机病毒的广泛流传便一发而不可收拾。特别是随着网络化步伐的加快,病毒借助于网络爆炸式地传播,使得很多毫无防备的信息系统遭到破坏,造成了巨大的损失。

恶意代码极具破坏性。恶意代码在非法获取的用户授权下进行,因此,它以相同的方式访问用户所访问的东西。用户有绝对的权限对他自己的程序代码和数据文件进行控制,如读、写、修改、添加或删除。恶意代码往往也能这么做,而且无需用户授权,甚至不需要用户知道。恶意代码长期存在。1984年,Thompson在演讲中提到了“赋予信任的反应”(reflectionsontrustingtrust),用以描述可以通过编译器编译的代码。在那次演讲中,他提到了一份早期的文档—《全面的安全评估》(Themutticssecurityevaluation)。其实,关于病毒行为的文献记录至少可以追溯到1970年。Ware在1970年的研究和Anderson为美国空军所做的计划研究都准确地描述了病毒的威胁、程序的脆弱点和程序安全性漏洞,特别是那些带有恶意性质的。对于病毒代码而言,新出现的东西只不过是不同的实例和变种,以及利用了代码出现的速度。恶意代码存在于我们的周围,其影响比以前更加深远。研究恶意代码的外在表现和工作原理对我们来说非常重要,可以借此逐步阻止它们进行破坏活动,或者至少能减弱它们的影响。本章后面的内容将会讨论常见恶意代码的工作原理、特性、危害等内容。

2.恶意代码的种类

恶意代码(maliciouscode)和欺诈程序(rogueprogram)是以破坏为目的的一类程序,由一个代理(agent)编制,在软件中造成不期望的结果。该定义将无意的程序错误排除在外,也将程序冲突错误排除在外。所谓代理,是指该类程序的作者或发布人。通过此定义我们得出,大多数在软件检查、评估、测试中发现的错误都不属于恶意代码的范畴,因为这些错误都被认为是无意的。然而,无意错误事实上可以引起与恶意代码相同的后果。一个良性原因仍然可以造成一个灾难。病毒(virus)是一种将恶意代码传递给正常程序的程序,它通过修改正常程序做到这一点。“病毒”的得名是因为它与生物学中的病毒具有相似特征,被它感染的系统将继续感染其他系统以破坏其他系统或使病毒与其他系统共存。病毒是潜伏的,以至于不能确定昨天还是干净的系统今天是否干净。此外,一个正常程序也可能被修改以包藏病毒程序的副本,这样该程序的行为就与病毒一样,感染其他程序。被感染的主机数量通常以几何级数递增,最后整个系统都被病毒控制,并继续蔓延以感染其他与本系统相连的系统。表6-1恶意代码的类型

日趋成熟。目前,通过软件业界和可靠性工程界的不懈努力,软件可靠性工程得到了广泛的研究并通过不断实践而取得了显著的成绩。但遗憾的是,直到今天,开发足够可靠的软件并测试和验证其可靠性,仍是十分困难的问题。6.2.1软件可靠性模型的发展历程

软件可靠性工程的产生和发展得益于软件可靠性模型。20世纪80年代之初,软件可靠性工作主要侧重于模型的研究和建立。迄今为止,发表了100多种软件可靠性模型,且新模型还在不断推出,从而导致了所谓的“模型战”。最早的软件可靠性模型是由于1956年提出的一系列公式,但由于它们太复杂,这些公式对后来软件可靠性模型的建立几乎没有什么影响。1967年,Hudson观察到软件开发过程是一个生灭过程,提出了生灭过程模型。模型的关键点是:错误的产生是延期的,错误纠正是死亡期,在任一时刻存在于软件的错误个数可用来定义过程的状态,过程的转移概率与生灭函数有关。

对软件可靠性模型发展起着重要或奠基作用的模型分别是于1971年发表的Shooman模型以及Z.Jelinski和发表的J-M模型。他们都假设:

(1)软件中的初始错误数为N(N≥0);

(2)软件故障与软件中的剩余错误个数成正比;

(3)错误一旦被发现,立即排除且不引入新的错误。另外,J-M模型还假设故障的风险率为分段常数,在首次纠错过程中,它由一个常量来改变,但在两次纠错过程之间保持常数。Jelinski和Moranda应用极大似然估计来估计软件中总的错误数量、剩余错误数量与风险率之间的比例参数。

1972年,B.Littlewood和发表了第一个贝叶斯(Bayes)模型。他们假设:故障间隔时间服从含参数λi的指数分布,且λi服从先验的分布。据此,由标准的Bayes过程获得tn+1 | {t1,t2,…,tn}。同年,与提出了类似的模型,它与其他模型的主要区别就在于,他们假定连续的故障之间的纠错服从瑞利(Rayleigh)分布。1973年,发表了类似模型,但假设了风险函数服从Weibull分布,其特例就是Schick-Wolverton模型。

1975年,发表了执行时间模型,引入了一系列新的显示函数。同年,发表了几何泊松(Possion)过程模型,该模型假设故障率随着时间的增加呈几何级数下降,且下降过程出现在每次故障的纠正期间。因此,在第i个时间段内的错误数满足含参数λKi-1的泊松分布。同年,K.Trividi和发表了第一个马尔可夫(Markov)过程模型。他们将系统状态区分为“UP”和“DOWN”两个状态,并假定“UP”状态和“DOWN”状态,并假定“UP”状态和“DOWN”状态之间的转换概率相同。模型输出结果是一个概率集合,集合的每个元素为:P{在[0,t] 内找出k个错误}。

1976年,和S.Natarajan发表了基于错误排查过程中引入新的错误的模型。他们使用查错率、纠错率以及新错误引入率来处理新的错误引入问题。

1979年,A.Goel和K.Okumoto发表了关于连续时间的NHPP模型,该模型对软件可靠性工程的发展产生了持续的影响。1983年,由Yamada、Ohba和Osaki联合发表的NHPP模型,给出了呈S形的可靠性增长曲线的均值函数。由K.Okumoto和提出的对数泊松过程模型,具有一个初始错误率λ,以及对应于λ的一个递减率。模型的日历时间部分则与执行时间模型的日历时间部分相同。

1989年,Y.Tohma、K.Tokunaga、S.Nagase和Y.Murata提出了超几何分布模型,用户估计软件中的剩余错误数量。(1)随机测试过程中,当观察到的故障次数为0时,如何估计当前版本软件的故障率;

(2)使用分布与测试分布不匹配时,对估计的故障概率进行调整;

(3)故障率估计时,将随机测试的结果与其他信息结合起来进行分析。

N.Karunanith、Y.Malaiya和D.Whitley应用神经网络系统理论预测软件可靠性。他们利用前向神经网络对三个数据集合进行软件可靠性估测,结果发现:神经网络方法在软件可靠性估测中显示出良好的一致性,这是一般现有软件可靠性模型所无法做到的,神经网络方法对于提高估测精度具有显著的效果。6.2.2软件可靠性模型的分类

软件可靠性模型数量众多,表达形式变化多样,适用情况千差万别。为了能够系统而深刻地理解软件可靠性模型,对现有模型进行合理分类是必不可少的。通常分为结构模型和预计模型两大类。

结构模型反映系统的逻辑结构,借助这类模型,在掌握软件单元(构件)可靠性特征的基础上,可以对系统的可靠性特征以及变化趋势做出预测和评价。结构模型是软件系统分析的重要工具,它既可用于软件系统的可靠性综合,也可用于软件系统的可靠性分解。结构模型包括串联系统模型、并联系统模型,以及硬—软件复合系统模型等。预计模型在本质上是一些描述软件失效与软件错误的关系、软件失效与运行剖面的关系的数学方程。借助这类模型,可以对软件的可靠性特征做出定量的预计或评估。例如,可以预计开发过程中的可靠性增长,预计或评估软件在预定工作时间的可靠度,预计软件在任意时刻的失效率等。评估和预计是两个有区别又有联系的概念。评估是指对软件现有的可靠性做出评价。预计是指对软件未来的可靠性特征进行预测。这二者难以分开。常见的分类有:面向时间的模型,面向输入的模型和面向错误的模型。需要指出的是,在使用数学模型进行预计时,蕴含的假定是,事物发展规律在未来的一段时间内保持不变。对于短期预测这个假设是合理但是,随着预测期的延长,其近似性减弱。用可靠性模型进行预计时,为了得到较准确的结果,如果发现软件的失效规律有明显改变,则应该对参数加以修正或重新收集失效数据,重新确定模型参数。

软件可靠性模型的分类如图6-1所示。图6-1软件可靠性模型的分类6.2.4软件可靠性预计模型

软件可靠性预计模型的研究始于20实世纪70年代初期。迄今为止,文章书籍中的可靠性预计模型已有几十种,而且新的模型还在不时出现。这些模型大体上可分为三种类型,即面向时间的模型、面向输入的模型和面向错误的模型。

1.面向时间的模型

面向时间的模型以时间为基准,研究软件的可靠性随时间变化的规律。这种模型建立的基础及其预测结果,符合软件可靠性定义的要求,且与硬件可靠性的概念兼容,可以满足硬、软件的系统综合分析的要求,因此得到了广泛的应用,成为三类模型中最重要的、包含品种最多的一类。根据对数据的要求,这类模型可以分为两类,即失效时间间隔模型(TBF模型)和失效计数模型(FC模型)。(1)失效时间间隔模型(TBF模型)所使用的数据是一定的时间间隔中的失效数,分析方法建立在以失效时间间隔服从特定的概率分布的基础上。

(2)失效计数模型(FC模型)所使用的数据是一定的时间间隔中的失效数,分析方法大多建立在泊松过程理论的基础上。

面向时间的模型最大缺点是其假设的前提条件很高,很难完全满足,因而影响了模型的准确性和人们使用的信心。经过30多年的研究、发展,情况有了很大的改善,再加上模型的数量多,选择余地大,这类模型的应用前景是广阔的。2.面向输入的模型

面向输入的模型的目的是建立软件的可靠性与输入数据的联系,用程序运行中的失效次数与成功次数的比例作为软件可靠性的度量。这种模型概念清晰易懂,易于应用,但是其与时间度量没有直接的关系,在实现硬—软件系统综合时有一定困难,必须经过附加的数学处理,才能用上时间尺度表示可靠度。

3.面向错误的模型

面向错误的模型直接使用软件中现存的错误数来反映软件可靠性。这种模型的结果直观,其缺点是不能反映软件可靠性与时间的关系。6.3.2软件系统的排错过程

1.错误定位

软件系统的排错与之前的测试紧密相连。如果测试的结果与期望结果存在差异,则排错过程先要找出错误原因才能对应地修正错误。软件系统排错的前提是准确地实现错误定位。排错人员应从分析错误的征兆入手,查找错误的位置。比如在软件测试中发现文件记录中丢失了最后一个支付,这就是一个错误征兆,排错人员需要利用各种信息和经验,来判断问题发生的真正原因,找到有错误的程序单元或语句。一种常见的做法是在整个程序中设置若干打印语句,打印中间结果并查看。这种方法有相当好的效果,但是不宜作为第一位的方法使用。正确的做法是遵循以下步骤:

(1)透彻地了解所面临的问题。必须深入地研究程序及其执行结果,分析它在什么情况下得出的结果是正确的,在什么情况下得出的结果是错误的。以这个分析为基础,排错人员应提出关于错误性质及其原因的若干假设。排错出现困难的一个重要原因是,排错人员忽略了程序输出中给出的某些重要信息。要仔细地分析输出数据,看看利用这些数据能否充分实现错误定位。如果信息不充分,则应运行一些追加的测试用例。(2)制定查错计划。这一步要求排错人员提出错误原因、性质和部分的假设,根据这些假设来制定查找错误的计划。

(3)执行查错计划。实施计划以验证各种假设的正确性,对计划执行过程的每一步都要进行检查。

(4)评估查错结果。经过执行计划,如果错误的位置已经查明,则在动手改正之前还要再作认真的检查,分析它们是否确实是测试中出现的错误征兆所引起的原因,验证错误征兆涉及的部分有无遗漏。错误定位上的许多困难其实来源于排错人员心理上的定势,使得错误的实际部分被忽略。这种情况与人们校对文稿中常常忽视某些特定字符的错误很相似。克服这个缺点的方法是排错人员要有“怀疑一切”的思想准备,要注意程序的注释和文档。有经验的排错人员在阅读一个程序时,往往会先看看它的注释,了解一下设计人员的初始意图。此外,反向跟踪也是一种有效的查错策略。反向跟踪指的是从反方向阅读程序,这种做法能从另一个角度展示程序的逻辑结构。反向跟踪是指从反方向阅读程序,这种做法能从另一个角度展示程序的逻辑结构。反向跟踪也是从错误征兆在程序中出现的位置进行反方向搜索,以找出错误发生的确切位置的。如果需要,有时则还要运行一些附加的测试用例,以收集更多的信息。2.改正错误

错误的位置一旦准备判定,下一步的任务就是改正错误。改错的最大困难是判断问题涉及的范围。经常出现的问题是:改正了错误的一部分而忽略了其他的部分。改错不能采用“试试看”的作法。这种做法是排错人员没有把握的表现,因此很难达到预期的排错要求。排错难免对局部的程序进行修改并破坏原有程序的完整性,对程序的结构和可读性产生消极的影响。而且排错又是在开发进度的约束中进行的,这使得问题变得更加尖锐。新的错误很容易在毫无觉察的情况下引入,经验表明,新错误的引进概率高达20%~50%。这种情况表明排错工作不能分配给缺乏经验的新手,而应该由有经验的程序员来担任,必须确保排错的质量,对排错的要求应该像对设计的要求一样严格。如果需要更改与排错有关的文档,则改正后的程序要经过代码的检查。如果错误是在单元测试后发现的,则应追加一些单元测试案例或重新进行单元测试。为了最大限度地避免新错误的引进,应先改动源程序,事后进行编译。这种作法表面上看来似乎费时,但是出错的可能性小。3.排错过程

总之,软件系统的排错过程可以分为以下几步:

(1)从错误的外部表现形式入手,确定程序中的出错位置;

(2)研究有关部分的程序,找出错误的内部原因;

(3)修改设计和代码,以便排除这个错误;

(4)重复进行暴露了这个错误的原始测试或某些相关测试。6.3.3软件系统的排错方法

常用的排错策略主要有以下三类:

(1)强行排错类;

(2)回溯类;

(3)排除类。

以上三种排错策略各对应一种排错方法。

1.强行排错方法

强行排错类方法是最常用,也是效率最低的方法,只有在万般无奈的情况下才考虑使用。其主要思想是“通过计算机找错”。它不需要过多的思考,比较省脑。比如,通过内存全部打印来排错,是将计算机内存和寄存器中的值全部打印出来,然后在这些数据中寻找出错的位置。在程序特定的位置设置打印语句,把打印语句插在出错的源程序的各个关键变量改变部位、重要分支部位、子程序调用部位,来跟踪程序的执行和监视重要变量的变化。使用自动调试工具,利用某些程序语言的调试功能或者专门的交互式调试工具,分析程序的动态运行过程,而不必修改程序。

应用以上任何一种方法之前,都应该对错误的征兆进行全面彻底的分析,得出错误位置及错误性质的推测,再使用一种适当的排错方法来检验推测的正确性。2.回溯方法

回溯类方法能成功地使用在小程序的排错上。它从出现错误征兆处开始,人工地沿控制流程往回追踪,直至发现出错的根源。不幸的是:当程序规模变大后,可能的回溯路线显著增加,这样导致人工进行完全回溯可望而不可及。例如:程序中发现错误处是某个打印语句。通过输出值可以推断程序在这一点上变量的值。再从这一点出发,回溯程序的执行过程,反复考虑:“如果程序在这一点上的状态值是这样,那么程序在上一点的状态一定是这样……”,直到找到错误的位置。3.排除方法

排除方法基于归纳和演绎的原理,采用“分治”的概念。首先收集与错误出现相关的所有数据,假设一个错误原因,用这些数据证明或反驳它;或者一次列出所有可能的原因,通过软件测试一一排除。只要某次测试结果说明某种假设已初具端倪,则立即精化数据,乘胜追击。

(1)归纳法是一种从特殊推断一般的系统化思考方法。归纳法排错的基本思想是:从一些错误的征兆入手,通过分析它们之间的关系来找出错误。其主要步骤大致分为四步,如图6-2所示。图6-2归纳法排错的步骤具体步骤分述如下:

①收集有关数据,列出所有已知的测试用例和程序执行结果。看哪些输入数据的运行结果是正确的,哪些输入数据的运行结果有错误。

②组织数据。由于归纳法是从特殊到一般的推断过程,所以需要组织整理数据,以发现规律。可以使用下面列出的表6-2,What列出的是一般现象,Where说明发现现象的地点,When列出现象发生时所有已知情况,How说明现象的范围和量级。Is描述正确发生的3W1H,Isnot描述错误发生的3W1H。通过分析可以找出矛盾。表6-2归纳法组织数据举例

③提出假设。分析线索之间的关系,利用在线索结构中观察到的矛盾现象,设计一个或多个关于出错原因的假设。如果一个假设也提不出来,就要继续返回到最前的步骤中去,收集更多的数据。此时应当再设计与执行一些测试用例,以获得更多的数据。

④证明与假设。把假设与原始线索或数据进行比较,如果它能完全解释一切现象,则假设得到证明;否则,就认为假设不合理,或者是存在多个错误,以致只能消除部分错误。(2)演绎法是一种从一般原理或前提出发,经过排除和精化的过程来推导出结论的思考方法。演绎法排错是测试人员首先根据已有的测试用例,设想及枚举出所有可能出错的原因作为假设;然后用原始测试数据或新的测试,从中逐个排除不可能正确的假设;最后,用测试数据验证余下的假设是出错的原因。其主要步骤也有四步:

①列举出所有可能出错原因的假设。把所有可能的错误原因列成表,通过它们,可以组织、分析现有数据。②利用已有的测试数据,排除不正确的假设。仔细分析已有的数据,寻找矛盾,力求排除前一步列出的所有原因。如果所有原因都被排除了,则需要补充一些数据,如测试用例,以建立新的假设。

③改进余下的假设。利用已知的线索,进一步改进余下的假设,使之更加具体化,以便可以精确地确定出错位置。

④证明余下的假设。这一步极其重要,具体做法与归纳法的第四步类似。6.3.4软件系统的排错原则

在排错过程中,需要遵循一定的原则。其中,很多原则本质上是属于心理学的问题。排错的原则可分为两组。

1.确定错误的性质和位置的原则

(1)避开死胡同;

(2)用头脑去分析思考与错误有关的信息;

(3)调试工具只是一种工具,利用调试工具帮助思考,但不能代替思考;

(4)避免用试探法,最多只能把它当做最后的手段。2.修改错误的原则

(1)在出现错误的地方,很可能还有别的错误;

(2)修正一个错误的常见失误是只修改了这个错误的表象,而没有修改其本身;

(3)当心修正一个错误的同时可能会引入新的错误;

(4)修改源代码程序,而不是目标程序。6.4软件可信运行环境

以通信、存储和计算为核心的信息基础设施已经渗透到政治、经济、军事、文化以及社会生活的各个层面,成为当代生产力发展和人类文明进步的强大动力。软件是信息基础设施的灵魂,随着人们对功能需求的不断增加,软件系统变得日趋庞大和难以驾驭,缺陷和漏洞难以避免,系统越来越脆弱,很多时候不以人们期望的方式工作,经常发生各种故障和失效,直接或间接地给用户带来损失。软件并不总是让人信任的,这就是我们所说的“软件可信性”问题。软件可信性问题已经成为国际上一个普遍关注的问题,仅在Google上就可以搜索到100多万个与软件错误相关的网页。软件故障和失效所带来的影响也越来越大,2002年美国NIST估算,美国每年因软件失效所造成的年度经济损失近600亿美元,约占其GDP的0.6%。如何构造出缺陷较少的软件并保障其安全可靠运行,已经成为软件研发者义不容辞的责任。“可信性”是在正确性、可靠性、安全性、时效性、完整性、可用性、可预测性、生存性、可控性等众多概念的基础上发展起来的一个新概念,是客观对象诸多属性在人们心目中的一个综合反映。学者们试图从不同角度、不同层次去诠释“可信性”,但尚未形成共识,需要在实践中不断认识和把握。一般认为,“可信”是指一个实体在实现既定目标的过程中,行为及结果可以预期,它强调目标与实现相符,强调行为和结果的可预测性和可控制性。软件的“可信”是指软件系统的动态行为及其结果总是符合人们的预期,在受到干扰时仍能提供连续的服务。这里的“干扰”包括操作错误、环境影响、外部攻击等。例如,Poldelski和Rynbachenko基于线性代数理论提出了一个完备的一类线性程序线性秩函数生成理论,并将其实现,即RANKFINDER。RANKFINDER是他们和微软联合开发的程序终止性分析工具TERMINATOR的核心部分。TERMINATOR已经被成功应用到多个设备驱动程序的终止性分析中,这些C程序的规模从5000行到35000行不等。在对23个设备驱动程序的验证中,TERMINATOR发现了8个终止性错误。基于抽象解释的程序验证工具ASTREE分别对空中客车A340主飞控软件(13.2万行C代码)和A380主飞控软件(35万行C代码)进行了验证,在验证规模上有所突破,但仍然存在一定局限性,只能针对特定软件进行验证和调优,验证的性质也都是程序的内部性质。

实际上,没有必要对软件进行完全加密。首先,这样会严重影响程序的执行效率,其次,攻击者并不会对软件所有代码和数据感兴趣,他只会篡改其中的关键部分,例如对于常见的检测代码的程序,检测代码和决策代码是关键代码,如果攻击者可以篡改这些代码,他就很有可能绕过条件检测,而该检测则是软件设计者所期望执行的。因此应该将保护重点放到软件中的关键数据和代码上来。

经过抽象,一个软件可以表示为

Software = (C,D)

式中C表示代码,D表示数据。软件设计者在设计软件时根据情况将C划分为一般代码Cgeneral和关键代码Ccritical,同时将D划分为一般数据Dgeneral和关键数据Dcritical。需要注意的是,对关键数据有访问操作的代码也应该划分为关键代码,因为关键数据将被加载到安全处理器中,处于安全处理器以外的代码是无法对其进行访问的,只能由同处于安全处理器中的关键代码来访问。

这样,我们有

Software = (Cgeneral,Ccritical,Dgeneral,Dcritical)随后,软件设计者为该软件生成一对密钥KeyPair = (P,S),并用公钥P对Ccritical和Dcritical加密,另外为该软件赋予一个标识符I,I = (URL,ID,Name),其中URL指向一个能提供安全密钥服务的服务器KeyServer,ID是软件设计者的唯一标识符,Name为软件名称,该名称可以包含软件版本号,最后得到:

Software = (Cgeneral,Ep(Ccritical),Dgeneral,Ep(Dcritical))

我们称这样的软件为可信软件,最后软件设计者便可将该可信软件向公众发布,同时把私钥放到服务器KeyServer上。用户在运行可信软件时,系统将把Ep(Ccritical)和Ep(Dcritical)加载到虚拟地址部分,把Cgeneral和Dgeneral加载到用户空间以外的部分。当Ep(Ccritical)和Ep(Dcritical)被载入安全处理器后,安全处理器内核将根据软件标识符I在Flash-Memory中寻找与其对应的私钥S,同时调用解密程序对Ep(Ccritical)和Ep(Dcritical)进行解密。

在可信软件运行过程中,安全处理器内核需要对其RAM进行管理,由于安全处理器RAM可能不足以容纳关键代码和数据,这时需要将暂时无用的页换出。在换出之前,必须先将页面加密,然后再换出到外部存储介质上去。2.提供可信系统服务

将软件关键代码和数据放到安全处理器中,尽管能有效防止篡改,但攻击者仍然有机会攻击可信软件。例如,关键代码可能需要根据某些机器硬件特征来决定程序流程,在使用分级保护的系统中,处于用户空间的代码不能直接去访问硬件,需要通过操作系统的系统调用来获取这些特征,这使得攻击者有机可乘,他可以修改操作系统,使关键代码获得虚假信息,从而影响软件执行流程,以达到其目的。为避免上述情况的出现,应该禁止对操作系统内核的肆意修改,保持一个安全可信运行的内核,但是这对于开放的系统来说是不合适的,尤其对于如Linux操作系统这样的开放系统来说是不合适的。对于Linux这样的开放式操作系统,用户有权利根据自己喜好修改操作系统,并使用自己定制的系统,因此安全处理器本身应提供必要的可信系统服务。

可信系统服务代码处于安全处理器的保护下,攻击者难以对其进行篡改,因此这些由系统服务提供的信息能较为可靠地反映系统的真实状态。3.密钥管理和内核升级

1)密钥管理

没有安全可靠的密钥管理措施,会导致密钥信息外泄,也就无法保证软件的可信运行,对用于解密可信软件关键代码和数据的私钥S,安全处理器内核器将根据软件标识符I的哈希索引值H(I)将其放到索引表中,这样软件在运行时安全处理器可以根据其标识符I找到对应的私钥S来解密关键代码和数据。但是存在一个问题,当一个软件第一次在用户系统上运行时,安全处理器可能找不到与其对应的私钥。这是,安全处理器内核要负责获取私钥,而且要确保在获取过程中不会泄露信息,软件设计者在发布软件时,同时将对应的私钥S放到安全密钥服务器KeyServer上。因此当安全处理器找不到与可信软件对应的私钥时,可以根据软件标识符与KeyServer的通讯以获得对应的私钥。为保证私钥的安全性,安全协处理器在与KeyServer通信时首先需要相互认证身份,其次需要使用加密隧道来传输密钥。2)内核升级

安全处理器内核升级是一个与密钥管理同样重要的问题。不安全的升级也会导致密钥信息的泄露。例如,攻击者假冒更新站点,让安全处理器得到攻击者伪造的更新软件,而该软件将从安全处理器中读出密钥信息。和密钥管理中获取密钥的方法相类似,在更新内核时,安全处理器与更新处理器之间首先需要互相证明合法身份,然后再建立加密隧道,并通过隧道来下载新内核。升级管理需要具有原子性,只有当新软件完整无误地下载到安全处理器后才能替换旧软件。恶意软件具有以下特点:

(1)隐蔽性:以不被用户察觉的方式在软件系统中运行;运行后通常还隐蔽自身的存在,从而逃脱杀毒软件等安全工具的检测,例如,恶意软件常常隐藏自身进程,删除日志记录等。

(2)非法篡改性:恶意软件常常通过篡改正常软件的代码和数据,并加入恶意程序以达到破坏和入侵系统的目的。一旦被篡改后的软件加载到系统中,其恶意代码就会得到执行,从而威胁到系统的安全。另一方面,由于这些被篡改的软件通常是常用的应用程序或者系统的关键文件,用户很难发现并识别出这些被非法篡改的软件。(3)底层化:恶意软件已经更多地由用户级程序向内核级代码转化。

以上是恶意代码的三个特点,但不限于这三点。由于恶意代码破坏软件的完整性,并且不易被用户发觉,给用户的正常使用带来极大的不方便,甚至毁坏数据,破坏系统,给用户带来不小的损失。所以我们有必要研究如何对软件的完整性进行认证。2)软件哨兵

哨兵是一段小程序,插入在程序的不同位置,发挥不同作用(如代码模糊、加密、检验校验和、反汇编等)。基本思想是分布式哨兵构成一个网状保护环,彼此间的相互保护构筑了对软件的多重保护。

3)断言检查

断言检查即检验断言是否正确。所谓断言,是一种特殊表达式,用于说明一个条件或程序变量之间的关系。在软件防篡改中使用断言检查,是因为断言可以对程序进行验证和调试。NGSCB(Next-GenerationSecurityComputingBase),是微软提出的适用于未来Windows操作系统软硬相结合的平台规范。简单地说,NGSC_B实际上是依靠硬件和操作系统软件的配合在PC内建立起第二个操作环境,这个操作环境可提供应用程序、外围硬件、内存与存储设备、输入输出系统的安全连接,以此保护系统免受黑客恶意代码的攻击。微软为NGSCB增加了一个“Nexus”工作模式,意在提供一个受保护的安全分区,在该分区里运行的程序以一种“安全代理”的形态出现。即所有运行中的软件及数据都处于严密的保护状态下,包括密封的存储、受保护的执行、受保护的输入/输出等,而相应的加密操作是由一个“安全支持部件SSC”芯片来完成的。为了提供完整的平台安全和保护机制,NGSCB必须得到整个硬件系统的支持,处理器、芯片组、显示和输出设备都必须做出相应的改变,该部分的工作由Intel来完成。Intel将NGSCB的硬件部分称为LaGrande。(2)多模块哈希模式。依据图6-3树状程序流,将程序P被分解成n个基础模块b1,b2,…,bn。单一路径A的控制流始于b1,b2,…,bn尾随其后。解密路径的跳跃代码放置于基础模块内。作者引入了鉴别程序控制者的概念,主要是用它来完成程序动态的完整性认证,储存于原始程序P的最底部,作为保护程序执行的起点。程序初始化后,开始执行原始程序。在bi执行之前,计算bi-1。哈希值Hi-1 = Hash(bi-1),把它作为bi的解密密钥。从而保证了在程序的执行过程中,①不会涉及到“密钥存储”问题;②避免了哈希值的对比问题。图6-3树状程序流该机制同样也存在着缺点:如只适用于树状控制流程序;不能处理对于单一模块的多点切入问题;如何将该机制应用到网状控制流程序,需做进一步探讨。

2.基于软件哨兵检测机制

软件哨兵检测方法的基本思想是:在程序不同位置插入一些小的安全单元,即哨兵,负责不同的安全工作。

软件哨兵的粗略设计是:嵌入两个哨兵,第一个校验和哨兵负责关键代码段的完整性检测,另一个修复哨兵负责当完整性被破坏时的程序进行自动修复。

哨兵的安装是自动完成的,从而减少了人工操作所带来的繁琐,也减少了人工操作可能产生的各种错误。然而,哨兵也有它的弱点:

(1)攻击者还是可以同时发现所有的哨兵的。

(2)尽管把每个哨兵都设计的不尽相同,但由于基本任务相同,使得哨兵设计中类的结构都差不多,这样也为攻击者最终确定哨兵的分布结构创造了条件。6.6.1计算机病毒的概念

1.计算机病毒的定义

人们对生物病毒并不陌生,如天花、鼠疫、“非典”、“甲流”等许多病毒都曾给世人带来恐慌,它们危及生命、造成财产损失,甚至使文明衰落。计算机病毒也如此,同样威胁着信息文明,它们干扰人们的生产、生活等活动,甚至影响国家的政治、经济和军事事务,给世界带来了无法估量的损失。“计算机病毒”的概念是美国计算机研究专家F.Cohen博士最早提出的。计算机病毒是一段人为编制的计算机程序,这个程序一旦进入计算机并得以执行,它就会搜寻符合其传染条件的程序或存储介质,确定目标后再将自身代码插入其中,并自我繁殖。计算机病毒的特征在很多方面与生物病毒很相似。

人们从不同角度给出了计算机病毒的定义。一种定义是:通过磁盘、磁带和网络等存储媒介传播扩散,能“传染”其他程序的程序;另一种是:能够实现自身复制并且借助一定的载体存在的,具有潜伏性、传染性和破坏性的程序。2) DOS平台阶段

20世纪80年代起,IBM公司的PC系列微机因为性能优良,价格便宜逐渐成为世界微型计算机市场上的主要机型。但是由于IBMPC系列微型计算机自身的弱点,尤其是DOS操作系统的开放性,给计算机病毒的制造者提供了可乘之机。因此,装有DOS操作系统的微型计算机成为病毒攻击的主要对象。1988年5月13日星期五,一些国家的公司和大学遭到了“耶路撒冷”(Jerusalem)病毒的袭击。在这一天,病毒摧毁了计算机上所有想要执行的文件。从某种意义上,“耶路撒冷”病毒首次通过自己的破坏引起了人们对计算机病毒的关注。从欧洲到美洲以及中东都有“耶路撒冷”病毒的报告。该病毒因供给了耶路撒冷大学而得名。

1990年,第一个多态病毒“变色龙”(Chemeleon)出现。多态病毒每感染一次就产生不同的代码,使在此之前杀毒软件使用的“带掩码的特征比较法”无法对付此类病毒,杀毒软件不得不再寻找新的方法来检测和发现病毒。1992年3月,“米开朗琪罗”(Michelanglo)病毒造成1万多台计算机被感染。该病毒是一个恶性的引导区型病毒,在3月6日启动计算机时,米开朗琪罗病毒就会发作,除了像其他病毒一样进行传播外,还将把硬盘和当时插在软驱中的软盘数据破坏掉,给许多计算机用户造成了极大的损失。3) Windows平台阶段

1996年,随着Window95的日益普及,利用Windows进行工作的病毒开始发展。虽然大量DOS环境下的病毒在Windows环境下仍然能够成功运行,但越来越多的病毒对Windows操作系统下独特的可执行文件格式进行感染,这些病毒的出现宣告了病毒发展史上新一页的到来。

1996年1月,第一个Windows95病毒—“博扎”(Win95.Boza)出现。1998年6月,CIH病毒出现。CIH病毒是有史以来影响最大的病毒之一。该病毒是第一个直接攻击和破坏硬件的计算机病毒。它主要感染Windows95/98的可执行程序,发作时可能会破坏计算机FlashBIOS芯片中的系统程序,导致主板烧坏,同时破坏硬盘中的数据。CIH病毒是迄今为止破坏最为严重的病毒。4)互联网阶段

虽然最早的网络病毒“莫里斯蠕虫”(Morris’sWorm)早在1988年11月就已出现,但由于当时因特网的普及不高和操作系统漏洞的不断修补,蠕虫病毒并没有得到快速的复制和传播,因此没有受到足够的重视。1997年起,随着因特网的广泛应用,各种病毒也开始利用因特网进行传播,计算机病毒进入了互联网时代。

1999年3月,一个称为“梅丽莎”(Melissa)的计算机病毒席卷欧、美各国的计算机网络。这种病毒利用邮件系统大量复制、传播,造成网络阻塞,甚至瘫痪。而且,这种病毒在传播过程中还会造成泄密。2001年9月,“尼姆达”(Nimda)病毒在Internet上大规模传播,致使15万家公司网络遭受感染,大量公司不得不暂时关闭自己的因特网服务器。“尼姆达”病毒是一种破坏力很强的病毒。它除了通过利用电子邮件对计算机进行感染外,还像蠕虫病毒那样攻击计算机服务器,在互联网上寻找存在安全漏洞的网站进行攻击,而且还可以潜伏在用户的浏览器中,准备更进一步地攻击活动。2002年4月,一种新的恶意病毒—“求职信”病毒在亚洲地区顷刻爆发,它利用电子邮件方式,迅速向外传播,扩散势头十分凶猛,一股新的病毒风暴就此在全球展开。“求职信”危害之大与“尼姆达”相比有过之而无不及。除了具有同“尼姆达”病毒共同的危害性外,它还能完全覆盖文件,并且“求职信”病毒具有很强的感染性,即使用户不打开邮件附件,都会被自动感染上该病毒。3.计算机病毒的命名

完整的病毒名称一般分为三个部分。其一般格式为

<病毒前缀>.<病毒名>.<病毒后缀>

例如“”,它的病毒名为“Huigezi”,前缀为“Backdoor”,后缀为“ik”。病毒前缀指一个病毒的种类,用来区别病毒的种族分类。不同种类的病毒,其前缀也不同。例如,常见的木马病毒的前缀是Trojan,蠕虫病毒的前缀是Worm,黑客病毒前缀名一般是Hack,宏病毒的前缀是Macro,脚本病毒的前缀是Script,系统病毒的前缀是Win32、PE、Win95、W32、W95等,捆绑机病毒的前缀是Binder,陷门病毒的前缀是Backdoor。有时病毒名称前缀由多个部分组成,除类型外还包含了病毒的运行平台或病毒的一些其他特性。比如:“”,它的前缀是“Trojan.PSW”,代表它是一个可以盗取密码的特洛伊木马;“Backdoor.Win32.PcClient.al”的前缀是“Backdoor.Win32”,代表它是一个运行在32位Windows平台的陷门程序。病毒名指一个病毒的名称,用来区别和标识病毒家族,是一个广义的病毒名称。具有相同家族名称的病毒通常具有相同或相似的特征,比如,凡是病毒名为“Huigezi”的病毒都具有盗取用户密码、隐藏自身、远程控制染毒计算机等特征。著名的CIH病毒的家族名都是唯一的CIH,“振荡波”蠕虫病毒的家族名是Sasser。

病毒后缀指一个病毒的变种特征,用来区别具体某个家族病毒的某个变种。一般采用英文中的26个字母来表示,如就是指振荡波蠕虫病毒的变种B,因此一般称为“振荡波B变种”或者“振荡波变种B”。如果该病毒变种非常多,可以采用数字与字母混合表示变种标识。可以看出,一个病毒的前缀对于快速的判断该病毒属于哪种类型的病毒是有非常大的帮助的。通过判断病毒的类型,就可以对这个病毒有个大概的评估(当然这需要积累一些常见病毒类型的相关知识)。而通过病毒名可以利用查找资料等方式进一步了解该病毒的详细特征。病毒后缀能知道现在在你机子里待着的病毒是哪个变种。6.6.2计算机病毒的特征

计算机病毒一般具有以下六大特征。

1.传染性

传染性是计算机病毒的基本特征,是判别一个程序是否为计算机病毒的最重要条件。在生物界,通过传染病毒从一个生物体扩散到另一个生物体。在适当的条件下,它可得到大量繁殖,并使被感染的生物体表现出病症甚至死亡。同样,计算机病毒也会通过各种渠道从已被感染的计算机扩散到未被感染的计算机,在某些情况下造成被感染的计算机工作失常甚至瘫痪。与生物病毒不同的是,计算机病毒是一段人为编制的计算机程序代码,这段程序代码一旦进入计算机并得以执行,它会搜寻其他符合其传染条件的程序或存储介质,确定目标后再将自身代码插入其中,达到自我繁殖的目的。只要一台计算机染毒,如不及时处理,那么病毒会在这台机子上迅速扩散,其中的大量文件(一般是可执行文件)会被感染。而被感染的文件又成了新的传染源,再与其他机器进行数据交换或通过网络接触,病毒会继续进行传染。

2.非授权性

非授权性即未经授权而执行。一般正常的程序是由用户调用,再由系统分配资源,完成用户交给的任务。其目的对用户是可见的、透明的。而病毒具有正常程序的一切特性,它隐藏在正常程序中,当用户调用正常程序时它窃取到系统的控制权,先于正常程序执行;病毒的动作、目的对用户是未知的,是未经用户允许的。3.隐蔽性

计算机病毒一般是具有很高编程技巧的、短小精悍的程序。通常附在正常程序中或磁盘较隐蔽的地方,也有个别的以隐含文件形式出现。目的是不让用户发现它的存在。如果不经过代码分析,病毒程序与正常程序是不容易区别开来的。一般在没有防护措施的情况下,计算机病毒程序取得系统控制权后,可以在很短的时间里传染大量程序。而且受到传染后,计算机系统通常仍能正常运行,使用户不会感到任何异常。正是由于隐蔽性,计算机病毒得以在用户没有察觉的情况下扩散到上百万台计算机中。4.潜伏性

大部分的病毒感染系统之后一般不会马上发作,它可长期隐藏在系统中。只有在满足其所需要的特定触发条件时才启动其表现(破坏)模块,只有这样它才可进行广泛传播。如“PETER-2”在每年2月27日会提三个问题,答错后会将硬盘加密。著名的“黑色星期五”在逢13号的星期五发作。国内的“上海一号”会在每年三、六、九月的13日发作。当然,最令人难忘的便是26日发作的CIH。这些病毒在平时会隐藏得很好,只有在发作日才会露出本来面目。计算机病毒触发的条件主要有以下几种:

(1)利用系统时钟提供的时间作为触发器。

(2)利用病毒体自带的计数器作为触发器。病毒利用计数器记录某种事件发生的次数,一旦计数器达到设定值,就执行破坏操作。这些事件可以是计算机开机的次数,也可以是病毒程序被运行的次数,还可以是从开机起被运行的程序数量等。

(3)利用计算机内执行的特定操作作为触发器。特定操作可以是用户按下某些特定键的组合,也可以是执行的指令,还可以使对磁盘的读写。

计算机病毒所使用的触发条件是多种多样的,而且往往是由多个条件的组合来触发的。但大多数病毒的组合条件是基于时间的,再辅以读写盘操作、按键操作以及其他条件。5.破坏性

任何病毒只要侵入系统,都会对系统及应用程序产生程度不同的影响。轻者会降低计算机工作效率,占用系统资源,重者可导致系统崩溃。由此特性可将病毒分为良性病毒与恶性病毒。良性病毒可能只显示些画面或出点音乐或出现无聊的语句,或者根本没有任何破坏动作,但会占用系统资源。这类病毒较多,如:GENP、小球、W-BOOT等。恶性病毒则有明确的目的,或破坏数据、删除文件,或加密磁盘、格式化磁盘,有的对数据造成不可挽回的破坏。这也反映出病毒编制者的险恶用心,如CIH病毒。有时几种本没有多大破坏作用的病毒交叉感染,也会导致系统崩溃等重大恶果。6.6.3计算机病毒的工作原理

计算机病毒是一个程序,它在正常程序运行之前运行,并处于特权状态。这段程序代码一旦进入到计算机并得到执行,就会对计算机的某些资源进行监视和控制,会自动搜寻其他符合传染条件的程序或存储介质,并将自身代码插入其中,达到自我繁殖的目的。只要一台计算机染毒,病毒就可能在这台计算机上迅速扩散,甚至殃及与此计算机进行数据交换的其他计算机。1.DOS病毒的原理

现代计算机虽然有严密的保护措施,但总得允许开发人员修改、更新系统,允许用户编写自己的程序,这就使得病毒有了入侵的机会。正常的程序由用户调用,再由系统分配资源。如果一个病毒程序取得了控制权,它就可以对系统程序或其他用户程序进行任意的修改。

计算机病毒具有正常程序的一切特征,它隐藏在正常程序中,当用户调用正常程序时获得系统的控制权,并先于正常程序执行。一个病毒程序可以通过引导含有病毒的系统或执行含有病毒的系统或执行含有病毒的程序获得对计算机系统的控制权。获得控制权后,它可以传染、发作,或把自己安装在系统中。安装好的病毒可以通过某种条件再次获得控制权。当系统从硬盘引导时,主引导记录先被装入内存中执行,然后由主引导程序装入活动分区中BOOT引导记录,最后由DOS引导程序装入DOS操作系统。因此,如果这些引导程序中有病毒程序,该病毒程序就会首先获得控制权。但由于此时DOS还没有安装,病毒程序只能调用ROMBIOS的功能,以扇区为单位进行磁盘操作,无法将病毒程序传染到文件上。引导记录中的病毒程序必须将自己驻留内存,然后才有可能再次获得控制权。由于DOS装入时还要进行初始化工作,病毒程序只能将自己驻留内存高端。它修改ROM自检程序填写的内存最高可用内存地址保留一定空间给自己使用,并修改INT13H中断向量,指向病毒程序的某个入口,然后装入正常的引导记录引导DOS。以后,每次调用INT13H进行磁盘操作,病毒程序便再次获得控制权。获得控制权的病毒程序设法寻找适合感染的硬盘,把自己复制到磁盘的引导分区,完成传染功能。为了满足隐蔽性要求,病毒程序一般都较小,并主动减少对宿主重复感染的可能性。病毒程序一般都是通过某个标记来检查宿主已被感染,因此,这个标记可以人为地加在宿主中以获得免疫。此外,修改DOS并驻留内存的病毒一般给DOS增加了检查感染的功能。一个病毒程序获得控制权时,如果发现系统已感染过同种病毒,自己则不驻留内存,以免将内存耗尽或使系统速度下降太多而被人发现。2.Windows病毒的原理

Win32中的可执行文件,如 .exe、.dll、.ocx等都是PE(PortableExecutable)格式文件。PE病毒是所有病毒中数量极多、破坏极大、技巧性最强的一类病毒。PE病毒一般具有重定位、截获API函数地址、搜索感染目标文件、内存文件映射、实施感染等功能。

1)重定位

编写正常的程序时是不需要关心变量的位置的,因为源程序在编译时,变量(常量)在内存中的位置都被计算好了。程序装入内存时,系统不会为它重定位。编程时需要用到变量(常量)时直接用变量名访问,编译后通过偏移地址访问。病毒程序也要用到变量,当病毒感染HOST程序后,由于其依附到不同HOST程序中的位置也不尽相同,病毒随着HOST装入内存后,病毒中的各个变量(常量)在内存中的位置也会发生变化。这样,病毒对变量的引用不再准确,势必导致病毒无法正常执行。这样,病毒就非常有必要对病毒代码中的所有变量(常量)进行重新定位。2)获取API函数的地址

Win32下的系统功能不是通过中断实现,而是通过调用动态链接库中的API函数实现的。PE病毒也需要调用API函数实现某些功能,但是普通的PE程序里面只有一个导入函数节,记录了代码节所用到的API函数在DLL中的真实地址。这样,调用API函数时就可以通过该导入函数节找到相应API的真正执行地址。但是,对于PE病毒来说,它只有代码节,并不存在导入函数节,所以病毒无法像普通PE程序那样直接调用相关的API函数,而应该先找出这些APi函数在相应DLL中的地址。3)搜索感染目标文件

通常使用API函数来实现搜索感染目标文件的目的,如FindFirstFile、FindNextFile、FindCode等。

4)内存文件映射

内存文件映射提供一组独立的函数,使得应用程序能够通过内存指针像访问内存一样对磁盘上的文件进行访问。这组内存映射文件函数将磁盘上的文件全部或部分映射到进程虚拟地址空间的某个位置,以后对文件内容的访问就如同在该地址区域内直接对内存访问一样简单。这样,对文件中数据的操作便是直接对内存进行操作,大大提高了访问的速度,对病毒减少对资源的占用是非常重要的。5)实施感染

PE病毒常见的感染及其他文件的方法是在文件中添加一个新节,然后往该新节中添加病毒代码和病毒执行后返回HOST程序代码,并修改文件头中代码开始执行位置指向新添加的病毒节的代码入口,以便程序运行后先执行病毒代码。6.7计 算 机 蠕 虫

6.7.1计算机蠕虫的概念

1.计算机蠕虫的定义

恶意代码包括计算机病毒、计算机蠕虫和特洛伊木马等。在上一节中,已经介绍了计算机病毒的知识,现在我们关注另一种恶意代码—计算机蠕虫。从字面意思可以看出,蠕虫可以像蝇蛆一样在网上到处蠕动。计算机蠕虫会时刻寻找更多的计算机并伺机对其感染,那些被感染的机器又会作为自动发射缓冲器进一步感染其他机器,在短时间内造成大面积网络阻塞。计算机蠕虫利用网络、电子邮件以及U盘、移动硬盘等移动存储设备进行复制和传播。比如2006年以来危害极大的“熊猫烧香”就是蠕虫的一种。因为蠕虫使用多种方式进行传播,所以蠕虫程序的传播速度是非常大的。计算机病毒主要攻击的是文件系统,在其传染的过程中,计算机使用者是传染的触发者,是传染的关键环节,使用者的计算机知识水平的高低常常决定了病毒所能造成的破坏程度。而蠕虫主要利用计算机系统漏洞(vulnerability)进行传染,搜索到网络中存在漏洞的计算机后主动进行攻击,在传染的过程中,与计算机操作者是否进行操作无关,从而与使用者的计算机知识水平无关。另外,蠕虫的定义中强调了自身副本的完整性和独立性,这也是区分蠕虫和病毒的重要因素。可以通过简单的观察攻击程序是否存在载体来区分蠕虫与病毒;目前很多破坏性很强的病毒利用了部分网络功能,例如以信件作为病毒的载体,或感染Windows系统的网络邻居共享中的文件。通过分析可以知道,Windows系统的网络邻居共享本质上是本地文件系统的一种扩展,对网络邻居共享文件的攻击不能等同于对计算机系统的攻击。而利用信件作为宿主的病毒同样不具备独立运行的能力。不能简单地把利用了部分网络功能的病毒统统称为蠕虫或蠕虫病毒,因为它们不具备上面提到的蠕虫的基本特征。通过以上的分析和总结,本节重新给出的计算机蠕虫完整定义:“计算机蠕虫是无须计算机使用者干预即可运行的独立程序,它通过不停的获得网络中存在漏洞的计算机上的部分或全部控制权来进行传播。”(ComputerwormisaprogramwhichcanexecutesindependentlywithoutinterventionofcomputerusersandpropagatesbycompromisingvulnerablecomputerspartiallyorfullyontheInternet.)2.计算机蠕虫的发展历史

“蠕虫”最早出自一本1975出版的名为《ShockwaveRider》的科幻小说。1980年,XeroxPARC的研究人员编写了最早的蠕虫,用来尝试进行分布式计算(DistributedComputation)而不是进行恶意的破坏。整个程序由几个段(Segment)组成,这些段分布在网络中的不同计算机上,它们能够判断出计算机是否空闲,并向处于空闲状态的计算机迁移。当某个段被破坏掉时,其它段能重新复制出这个段。研究人员编写蠕虫的目的是为了辅助科学实验。蠕虫被用做恶意攻击的历史可以追溯到1988年11月2日爆发的Morris蠕虫。美国康乃尔大学学生罗伯特·莫里斯(RobertMorris)正是利用UNIX操作系统寄发电子邮件的公用程序中的一个缺陷,把他首创的人工生命“蠕虫”病毒放进Internet网络,闯下了弥天大祸。一夜之间,这条“蠕虫”闪电般地自我复制,并向着整个Internet网络迅速蔓延,使美国6000余台基于UNIX的小型电脑和工作站受到感染和攻击,网络上几乎所有的机器都被迫停机,直接经济损失在9000万美元以上,莫里斯本人也因此受到了法律的制裁。1998年5月,ADM蠕虫被发现,它只感染Linux系统,由于程序自身的限制,它的传染效率较低。ADM蠕虫是通过域名解析服务程序BIND中的反向查询(inversequery)溢出漏洞进行传播的。

1999年9月,ADMMillennium蠕虫爆发,由于该蠕虫将其所有文件的时间戳设置为2000年1月1日,所以人们称其为“Millennium”蠕虫。由于它在很多方面类似于1998年的ADM蠕虫,所以被认为是ADM蠕虫的仿制品。Millennium蠕虫只感染Linux系统,它入侵系统后,会修补所有它利用的系统漏洞,以此来防止重复感染。它通过imap4、qpopper、bind、rpc.mountd4种系统服务中存在的漏洞进行传播。2000年5月4日,求爱信(LOVELETTER)蠕虫爆发,这是一个用VBScript语言写成的蠕虫程序,它可以通过多种方式进行传播,包括E-mail、Windows文件共享、IRC、USENET新闻组等。根据CERT的统计,截至2000年5月8日,仅5天的时间,就有近500000台机器被感染。

2001年1月,Ramen蠕虫在Linux系统下发现,它的名字取自一种面条。它在15分钟内可以扫描13万个地址,早期的版本只修改被入侵计算机Web服务下的index.html文件,在利用系统漏洞入侵后会为系统修补好漏洞。但后期的版本中被加入了隐藏其踪迹的工具包(Rootkit),并在系统中留下陷门。虽然它是蠕虫而非病毒,但仍被媒体称为“Linux系统下的首例病毒”。Ramen蠕虫通过wuftpd、rpc.statd、LPRng三种系统服务中存在的漏洞进行

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论