Virus 版 (精华区)
发信人: Kernel (--->哈尔滨), 信区: Virus
标 题: 杀毒软件的引擎.1(zz)
发信站: BBS 哈工大紫丁香站 (Tue Jul 27 09:57:18 2004)
杀毒软件的引擎(重新编辑)
为防止误解,特作如下声明:
1.鉴于个人能力有限,文中大量借用了业已在病毒界获得公认的两篇文章:先进杀毒引
擎的设计原理 ,流行杀毒软件的引擎设计 。
2.为便于理解,为中很多词语未使用严格的工业研发用语。比如杀毒引擎的前端正式名
称为‘基于初步预扫描的(文件)对象汇入工程部分“。很多工业用语听起来很拗口,自
己变通了一下,感兴趣者可查阅L.Felly:系统的安全与防护 中的有关章节。
3.我认为现今在全球流行的几款杀毒软件在技术上并不存在谁的技术远远领先的问题,
没有必要过与赞扬那一款杀毒软件,自己用着高兴就好。
4.到现在为止,我已经用过几乎所有的杀毒软件(论坛上提到的)
5. 我个人非常不喜欢设计病毒,私下写过的几个纯粹是写着玩,大部分时候是MM生气
的时候写个玩笑程序让她高兴用的
6.很长时间不在专业病毒论坛上走动了。我认为如果因为喜欢程序设计看一下病毒的
代码是可以的,当出于其他目的的时候,还是收手吧。
7.鉴于个人能力原因,有一部分是MM写的,MM很漂亮,也很娇气,但对我基本上言听
计从,必经一起走过了十几年了。原帖子中有一部分是错误的,已经由她修改过。
8.文中有一部分内容来自一个朋友提供的杀毒软件公司的开发文档,我已经大幅改动
过。
正文部分
文章比较长,加之本人写作水平有限和某些技术文档需要核实,只能写一段发一段,
还望大家原谅。有误之处,敬请指出,谢谢!(各段数值标出,每次均对该文件进行编辑.
1.什么是杀毒软件引擎,与病毒库的关系?
首先必须指出杀毒软件的引擎与其病毒库并没有什么直接的关系。杀毒引擎的任务和
功能非常简单,就是对于给定的文件或者程序进程判断其是否是合法程序(对应于杀毒软
件厂商自己定义的正常和非异常程序规范而言。正常的程序规范是指在程序所在系统平台
上操所系统本身洗净有定义的或者业界已经公认的程序行为过程,比如操作系统正常运行
就必须要求应用程序与系统核心进行进程响应并与交换相关数据。非异常程序活动是指可
能存在非法程序操作结果但能够以较高的置信度确定其非非法程序活动规范的。一般情况
下,相关文件的复制,移动,删除等都奔包括在该界定范围内)。
我们知道病毒的最终目的有些是与合法活动很类似的,在这种情况下,要求软件厂商
必须自己有一个行为规范界定规则,在一个给定的范围和置信度下,判断相关操作是否为
合法。在这方面,各个厂商的界定是有区别的,一般而言非美国厂商界定是非常严格的,
只有有很高的置信水平的程序行为,他们才判别为非病毒操作。记得前一阵论坛上有人给
了四段简单的代码,很多杀毒软件将其判为病毒或有病毒性质的文件行为,实际上看那几
段代码可以知道,其结果并不足以视之为病毒。美国厂商一般判断比较复杂,这主要由于
美国市场上的杀毒软件引擎来源比较复杂,比如诺顿,有足够的技术资料确信它的杀毒软
件引擎是自成体系的,而mcafee则存在一定的外界技术引进(收购所罗门)。
用简单的话说,杀毒引擎就是一套判断特定程序行为是否为病毒程序(包括可疑的)
的技术机制。一个完整的技术引擎遵守如下的行为过程:
1.非自身程序行为的程序行为捕获。包括来自于内存的程序运行,来自于给定文
件的行为虚拟判断,来自于网络的动态的信息等等。一般情况下,我们称之为引擎前端。
捕捉的方法非常多,除诺顿以外的杀毒软件采用的都是行为规范代码化的方法。诺顿由于
与微软有这远远高于其它厂商合作关系,其实现过程比较独特,另有叙述。
2.基于引擎机制的规则判断。这个环节代表了杀毒引擎的质量水平,一个好的杀
毒引擎应该能在这个环节发现很多或者称之为相当规模的病毒行为,存而避免进入下一个
判断环节。传统的反病毒软件引擎使用的是基于特征码的静态扫描技术,即在文件中寻找
特定十六进制串,如果找到,就可判定文件感染了某种病毒。但这种方法在当今病毒技术
迅猛发展的形势下已经起不到很好的作用了。为了更好的发现病毒,相继开发了所谓的虚
拟机,实时监控等相关技术。这个环节被叫做杀毒软件引擎工作的核心层。
3.引擎与病毒库的交互作用。这个过程往往被认为是收尾阶段,相对于前两个环
节,这个阶段速度是非常慢的,杀毒引擎与要将非自身程序行为过程转化为杀毒软件自身
可识别的行为标识符(包括静态代码等),然后与病毒库中所存贮的行为信息进行对应,
并作出相应处理。当然必须承认,当前的杀毒软件对大量病毒的识别都是在这个阶段完成
的。因此一个足够庞大的病毒库往往能够弥补杀毒软件引擎的不足之处。但是必须意识到
,如果在核心层阶段就可以结束并清除病毒程序,那么杀毒软件的工作速度将会大幅提升
。“很可惜的是,当前我们没有足够聪明的杀毒引擎来完成这个过程”,这就是为什么有
病毒库的原因。
诺顿是微软最高级的安全方面核心合作厂商,因此它的杀毒软件在某些方面工作比
较特殊。比如在杀毒软件的安装,使用和功能实现方面,大部分厂商采用的是中间件技术
,在系统底层与非自身应用程序之间作为中间件存在并实现其功能;另有一些厂商使用的
是应用程序或者嵌入技术,相对而言这种方法安全性较低;诺顿和 mcafee实现方式比较相
似,诺顿采用了基于系统最底层的系统核心驱动,这种实现方式是最安全的或者说最高级
的实现方式,当然这需要微软的系统源代码级的支持(要花许多money),业界公认,这是
最稳定的实现方法,但从目前而言,只诺顿一家。Mcafee实现方式与诺顿很接近,一般称
之为软件驱动。相当于在系统中存在一个虚拟“硬件”,来实现杀毒软件功能。这些实现
方式关系着杀毒引擎对程序行为进行捕捉的方式。
我们使用的intel系的处理器有两个 ring层,对应两个层,微软的操作系统将系
统中的所有行为分为如下几个层:
1.最底层:系统核心层,这个层的所有行为都由操作系统已经内置的指令来
实现,所有外界因素(即使你是系统管理员)均不能影响该层的行为。诺顿的核心层既工
作在这个层上。
2.硬件虚拟层,一般称之为HAL。为了实现硬件无关性,微软设计了该层。所
有的外部工作硬件(相对于系统核心而言)都进入HAL,并被HAL处理为核心层可以相应的
指令。我们所使用的硬件的驱动程序既工作在该层上。当外界硬件存在指令请求时,驱动
程序作出相关处理后传给核心层。如果无与之对应的驱动相应,那么将按照默认硬件进行
处理。好像安全模式下硬件的工作就被置于默认硬件模式。Mcafee被认为工作与该层上。
3.用户层(分为两个子层,不详细叙述,感兴趣的可以查阅《windows xp入门
到精通》(有中文版),第二部分四节有叙述)。我们所知的大部分杀毒软件既工作与该
层上。一个完整的程序行为请求是如下流程:位于3户层上的应用程序产生指令行为请求,
被传递至2HAL进行处理,最后进入1最底层后进入CPU的指令处理循环,然后反向将软件可
识别的处理结果经1-2-3再响应给应用程序。对于诺顿而言,其整个工作过程如下:3-2
-1,完成;mcafee:3-2-1-1-2,完成:其余:3-2-1-1-2-3,完成;这个环节代表了杀毒
软件引擎的前端行为规范的获得。只从这个过程而言,诺顿和mcafee是比较先进的。(具
体的系统与CPU的ring()的对应,记不清楚了。 WinNT时代,微软的NT系统被设计有与四个
ring()层相对应,RISC系列的处理器有四个ring。因此现在的大部分杀毒软件是不能工作
与NT上的。具体的CISC和RISC的ring()数我记得可能有误,反正是一个2ring(),一个4rin
g().)。
尽管比较先进的工作方式给诺顿和mcafee带来了较高的系统稳定性(HAL层很少出现
问题,最底层出问题的几率接近于零),较快的响应速度(减少了环节),但同时也带来
了一些问题:1.资源占用比较厉害。在mcafee上体现的不是很明显,在诺顿上表现非常明
显。因为对于越底层的行为,硬件资源分配越多。最好资源的是什么?当然是操作系统。
应为它最最底层。2.卸载问题。卸载底层的组件出问题的概率是相对比较高的,因此诺顿
的卸载比较慢,偶尔还出问题。
有人质疑由于微软操作系统的不稳定性是否会拖累诺顿,想开发人士询问后得知,
微软操作系统的内核层设计是非常优秀的,很多时候操作系统的不稳定性来源于以下几个
方面:
1.应用程序设计不合理,许多程序设计者根本就未读过微软的32位程序设计指
南,所设 计的程序并不严格符合微软规范。我们看到很多软件多年前设计还能运行于最
新的xp平台,原因很简单:这个软件在设计时完全遵循了微软的程序设计规范。
2. 驱动程序的编写有问题,与HAL层有冲突。
因此认为微软的操作系统将会影响诺顿的稳定性是不合理的。
注:刚才问了一下偶MM,她告诉我应该是CISC有四个ring(),RISC有两个ring().对应于
系统的最低层而言,工作在ring0()上。应用程序工作在ring3()上 。偶的记忆力比较差,
文中可能有部分技术错误,请原谅。
业界有人认为,先进杀毒软件的引擎设计已经日趋复杂,类如诺顿这一类的厂商其
产品的引擎应该已经覆盖了操作系统的各个层级,以提高防护能力。在一篇文档中有程序
员提出有足够的信息认为诺顿,mcafee,趋势的产品自己修改了标准的系统相关协议,比
如TCP/IP等,以达到所谓的完整防护的目的。NOD32的一篇官方文档(说实话,我没有看到
过)指出有必要全面更新(说白了就是修改)系统的诸多协议,以达到最快的速度和杀毒
效果。
要讨论怎样反病毒,就必须从病毒技术本身的讨论开始。正是所谓“知己知彼,百战不殆
”。很难想象一个毫无病毒写作经验的人会成为杀毒高手。目前国内一些著名反病毒软件
公司的研发队伍中不乏病毒写作高手。只不过他们将同样的技术用到了正道上,以‘毒’
攻‘毒’。当今的病毒与DOS和WIN3.x时代下的从技术角度上看有很多不同。最大的转变是
:引导区病毒减少了,而脚本型病毒开始泛滥。原因是在当今的操作系统下直接改写磁盘
的引导区会有一定的难度(DOS则没有保护,允许调用INT13直接写盘),而且引导区的改
动很容易被发现,并且微软在设计操作系统时加强了对引导区的程序行为管理,写一个完
美的引导区病毒难度很大,所以很少有人再写了;而脚本病毒以其传播效率高且容易编写
而深得病毒作者的青睐。但是最最落后的杀毒引擎也就是只基于静态代码的杀毒引擎都能
干掉该种病毒(病毒库搞好就行)。
要讨论的技术主要来自于二进制外壳型病毒(感染文件的病毒),并且这些技术大
都和操作系统底层机制或386以上CPU 的保护模式相关,值得研究。DOS下的外壳型病毒主
要感染 16位的COM或EXE文件,由于DOS没有(文件和引导区)保护,它们能够轻松地进行
驻留,减少可用内存(通过修改MCB链),修改系统代码,拦截系统服务或中断。而到了W
IN9X和WINNT/2000时代,搞个运行其上的32位WINDOWS病毒变得难了点。由于存在页面保护
,你不可能修改系统的代码页(如果你强到连操作系统代码都能改,偶无话可说)。由于
I/O许可位图中的规定,你也不能进行直接端口访问(29A的一个美女[听说叫 Mercy.Chan
]可以通过汇编方法直接访问端口的目的,但是没有见过给出事例代码。知道得给介绍一下
她的程序代码)WINDOWS中你不可能象在 DOS中那样通过截获INT21H来拦截所有文件操作。
总之,你以一个用户态权限运行,你的行为将受到操作系统严格的控制,不可能再象DOS下
那样为所欲为了(在xp中,这种权限管理极为严格,大致分成了4-8个等级)。 WIND
OWS下采用的可执行文件格式和DOS下的 EXE截然不同(普通程序采用PE格式,驱动程序采
用LE),所以病毒的感染文件的难度增大了(PE和LE比较复杂,中间分了若干个节,如果
感染错了,将导致文件不能继续执行)。当今病毒的新技术太多,随便介绍几个。
1.系统核心态病毒
386及以上的CPU实现了4个特权级模式(WINDOWS只用到了其中两个),其中特权级
0(Ring0)是留给操作系统代码,设备驱动程序代码使用的,它们工作于系统核心态;而
特权极3(Ring3)则给普通的用户程序使用(我想知道一个问题,ring1,2是干什么的?)
,它们工作在用户态。运行于处理器核心态的代码不受任何的限制,可以自由地访问任何
有效地址,进行直接端口访问。而运行于用户态的代码则要受到处理器的诸多检查,它们
只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对
任务状态段(TSS)中I/O许可位图(I/O Permission Bitmap)中规定的可访问端口进行直
接访问(此时处理器状态和控制标志寄存器EFLAGS中的IOPL通常为0,指明当前可以进行直
接I/O的最低特权级别是Ring0)。以上的讨论只限于保护模式操作系统,象DOS这种实模式
操作系统则没有这些概念,其中的所有代码都可被看作运行在核心态。既然运行在核心态
有如此之多的优势,那么病毒当然没有理由不想得到Ring0。处理器模式从Ring3向Ring0的
切换发生在控制权转移时,有以下两种情况:访问调用门的长转移指令CALL,访问中断门
或陷阱门的INT指令。具体的转移细节由于涉及复杂的保护检查和堆栈切换,不再赘述,请
参阅相关资料。现代的操作系统通常使用中断门来提供系统服务,通过执行一条陷入指令来
完成模式切换,在INTEL X86上这条指令是INT,如在WIN9X下是INT30(保护模式回调),
在LINUX下是INT80,在WINNT/2000下是INT2E。用户模式的服务程序(如系统DLL)通过执
行一个INTXX来请求系统服务,然后处理器模式将切换到核心态,工作于核心态的相应的系
统代码将服务于此次请求并将结果传给用户程序。
在即将发布的xp-sp2中采用所谓增强的内存页面保护将会更为严格的控制用户权限
,据说在访问内存地址时得到的将是经过系统映射处理的对应内存范围,在内存实地址与
用户层之间,搞了一个类似于转换协议的东西,害的很多软件都不能运行,应为他们总是
试图按照原有的HAL层访问规则进行工作。
2.驻留病毒
驻留病毒是指那些在内存中寻找合适的页面并将病毒自身拷贝到其中且在系统运行
期间能够始终保持病毒代码的存在。驻留病毒比那些直接感染(Direct- action)型病毒
更具隐蔽性,它通常要截获某些系统操作来达到感染传播的目的。进入了核心态的病毒可
以利用系统服务来达到此目的,如CIH病毒通过调用一个由VMM导出的服务VMMCALL _PageA
llocate在大于0xC0000000的地址上分配一块页面空间。而处于用户态的程序要想在程序退
出后仍驻留代码的部分于内存中似乎是不可能的,因为无论用户程序分配何种内存都将作
为进程占用资源的一部分,一旦进程结束,所占资源将立即被释放。所以我们要做的是分
配一块进程退出后仍可保持的内存。
病毒写作小组29A的成员GriYo 运用的一个技术很有创意:他通过CreateFileMappingA 和
MapViewOfFile创建了一个区域对象并映射它的一个视口到自己的地址空间中去,并把病毒
体搬到那里,由于文件映射所在的虚拟地址处于共享区域(能够被所有进程看到,即所有
进程用于映射共享区内虚拟地址的页表项全都指向相同的物理页面),所以下一步他通过
向Explorer.exe中注入一段代码(利用WriteProcessMemory来向其它进程的地址空间写入
数据),而这段代码会从Explorer.exe的地址空间中再次申请打开这个文件映射。如此一
来,即便病毒退出,但由于Explorer.exe还对映射页面保持引用,所以一份病毒体代码就
一直保持在可以影响所有进程的内存页面中直至Explorer.exe退出(我直接试过该种方法
,在xp下注意要写一个空循环语句,以免被踢出处理队列)。
另外还可以通过修改系统动态连接模块(DLL)来进行驻留。WIN9X下系统DLL(如Kernel3
2.dll 映射至BFF70000)处于系统共享区域(2G-3G),如果在其代码段空隙中写入一小段
病毒代码则可以影响其它所有进程。但Kernel32.dll 的代码段在用户态是只能读不能写的
。所以必须先通过特殊手段修改其页保护属性;而在WINNT/2000/xp系统DLL所在页面被映
射到进程的私有空间(如 Kernel32.dll 映射至77ED0000)中,并具有写时拷贝属性,即
没有进程试图写入该页面时,所有进程共享这个页面;而当一个进程试图写入该页面时,
系统的页面错误处理代码将收到处理器的异常,并检查到该异常并非访问违例,同时分配
给引发异常的进程一个新页面,并拷贝原页面内容于其上且更新进程的页表以指向新分配
的页。这种共享内存的优化给病毒的写作带来了一定的麻烦,病毒不能象在WIN9X下那样仅
修改Kernel32.dll一处代码便可一劳永逸。它需要利用 WriteProcessMemory来向每个进程
映射Kernel32.dll的地址写入病毒代码,这样每个进程都会得到病毒体的一个副本,这在
病毒界被称为多进程驻留或每进程驻留(Muti-Process Residence or Per-Process Resi
dence )。
文中列举方法在xp-sp1下略作修改即可使用 ,大部分为在代码段内加入空循环 。
在sp2下,很多时候报如下类型的错误不可访问的内存地址段.........。
在原来的帖子中我援引了另一篇文档中的例子,但经MM告知那些挂钩-捆绑等方法在如今的
设计中并不是很受欢迎,原因在于新的操作系统许多函数规则是不可预知的,也就是所谓
的”黑箱“设计使得设计人员更加偏爱系统级别的线程捆绑或者更加直接的接管权限控制
的方法,采用最复杂的线程捆绑技术甚至可以使杀毒软件和防火墙得不到足够的信息来区
分一个程序是否合法。更高级别的抢夺权限控制甚至可以结束所有杀毒软件的进程,包括
卡巴斯基所采用的受保护的内存线程技术。
尽管微软隐藏了很多系统函数,但是经过很多高手的努力,许多隐藏的系统函数已经
被找出,并且微软也有意识的减少隐藏函数的数量。在前段时间网上泄漏的2000的部分代
码中,其中关于磁盘文件读写的部分(大小为700M的那个压缩包里标号为115BH的那个文件
其中的第三节子代码)其中有很多进程是微软的开发文档中是没有给出介绍的,不知道以
后会不会有人利用这些东西写病毒。对病毒稍微有些常识的人都知道,普通病毒是通过将
自身附加到宿主尾部(如此一来,宿主的大小就会增加),并修改程序入口点来使病毒得
到击活。但现在不少病毒通过使用特殊的感染技巧能够使宿主大小及宿主文件头上的入口
点保持不变。附加了病毒代码却使被感染文件大小不变听起来让人不可思议,其实它是利
用了PE文件格式的特点:PE文件的每个节之间留有按簇大小对齐后的空洞,病毒体如果足
够小则可以将自身分成几份并分别插入到每个节最后的空隙中,这样就不必额外增加一个
节,因而文件大小保持不变。著名的CIH病毒正是运用这一技术的典型范例(它的大小只有
1K左右)。
病毒在不修改文件头入口点的前提下要想获得控制权并非易事:入口点不变意味着程序是
从原程序的入口代码处开始执行的,病毒必须要将原程序代码中的一处修改为导向病毒入
口的跳转指令。原理就是这样,但其中还存在很多可讨论的地方,如在原程序代码的何处
插入这条跳转指令。一些查毒工具扫描可执行文件头部的入口点域,如果发现它指向的地
方不正常,即不在代码节而在资源节或重定位节中,则有理由怀疑文件感染了某种病毒。
所以刚才讨论那种病毒界称之为EPO(入口点模糊)的技术可以很好的对付这样的扫描,同
时它还是反虚拟执行的重要手段。
另外值得一提的是现在不少病毒已经支持对压缩文件的感染。如Win32.crypto病毒就
可以感染ZIP,ARJ,RAR,ACE,CAB 等诸多类型的压缩文件。这些病毒的代码中含有对特
定压缩文件类型解压并压缩的代码段,可以先把压缩文件中的内容解压出来,然后对合适
的文件进行感染,最后再将感染后文件压缩回去并同时修改压缩文件头部的校验和。目前
不少反病毒软件都支持查多种格式的压缩文件,但对有些染毒的压缩文件无法杀除。原因
我想可能是怕由于某种缘故,如解压或压缩有误,校验和计算不对等,使得清除后压缩文
件格式被破坏。病毒却不用对用户的文件损坏负责,所以不存在这种担心。
个人看来,目前的杀毒软件在对待加壳病毒的时候表现比较差的为瑞星,怀疑瑞星的
杀毒引擎对加壳的东西放映不灵敏,因此瑞星自己加壳了很多病毒放到病毒库里,我曾使
用一些很少用的加壳方式对某些普通病毒加壳,结果瑞星没查出来,有待改进。
以上关于病毒的相关文字均来源于 某病毒论坛的文章 ,我个人作了少量修改 。再往
下为引擎部分的实现 。
--
※ 来源:·哈工大紫丁香 http://bbs.hit.edu.cn·[FROM: 218.108.197.181]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.229毫秒