软件开发培训班 >> 网络技术 >> 网络安全
杀毒软件技术的亲密接触 |
||||||||||||
|
病毒的分类 1994年2月18日,我国正式颁布实施了《中华人民共和国计算机信息系统安全保护条例》,在《条例》第二十八条中明确指出:“计算机病毒,是指编制或者在计算机程序中插入的破坏计算机功能或者毁坏数据,影响计算机使用,并能自我复制的一组计算机指令或者程序代码。”这是我国对于计算机病毒的正式定义,但是在实际中,所有会对用户的计算机安全产生威胁的,都被划入了广义的病毒范畴。 病毒大致分为以下几类:传统病毒,宏病毒,恶意脚本,木马、黑客、蠕虫、破坏性程序。 1.传统病毒:能够感染的程序。通过改变文件或者其他东西进行传播,通常有感染可执行文件的文件型病毒和感染引导扇区的引导型病毒; 2.宏病毒(Macro):利用Word、Excel等的宏脚本功能进行传播的病毒; 3.恶意脚本(Script)、:做破坏的脚本程序。包括HTML脚本、批处理脚本、VB、JS脚本等; 4.木马(Trojan)程序:当病毒程序被激活或启动后用户无法终止其运行。广义上说,所有的网络服务程序都是木马,判定是否是木马病毒的标准不好确定,通常的标准是:在用户不知情的情况下安装,隐藏在后台,服务器端一般没有界面无法配置; 5.黑客(Hack) 程序:利用网络来攻击其他计算机的网络工具,被运行或激活后就象其他正常程序一样有界面;黑客程序是用来攻击/破坏别人的计算机,对使用者本身的机器没有损害; 6.蠕虫(Worm)程序:蠕虫病毒是一种可以利用操作系统的漏洞、电子邮件、P2P软件等自动传播自身的病毒; 7.破坏性程序(Harm):病毒启动后,破坏用户计算机系统,如删除文件,格式化硬盘等。常见的是bat文件,也有一些是可执行文件,有一部分和恶意网页结合使用。 病毒与引擎的变迁 特征码是什么呢?比如说,“如果在第1034字节处是下面的内容:0xec , 0x99, 0x80,0x99,就表示是大麻病毒。”这就是特征码,一串表明病毒自身特征的十六进制的字串。特征码一般都选得很长,有时可达数十字节,一般也会选取多个,以保证正确判断。杀毒软件通过利用特征串,可以非常容易的查出病毒。 广谱特征 为了对付这种情况,首先特征码的获取不可能再是简单的取出一段代码来,而是分段的,中间可以包含任意的内容(也就是增加了一些不参加比较的“掩码字节”,在出现“掩码字节”的地方,出现什么内容都不参加比较)。这就是曾经提出的广谱特征码的概念。这个技术在一段时间内,对于处理某些变形的病毒提供了一种方法,但是也使误报率大大增加,所以采用广谱特征码的技术目前已不能有效的对新病毒进行查杀,并且还可能把正规程序当作病毒误报给用户。 启发式扫描 这种启发式扫描比起静态的特征码扫描要先进的多,可以达到一定的未知病毒处理能力,但还是会有不准确的时候。特别是因为无法确定一定是病毒,而不可能做未知病毒杀毒。 行为判定 引擎技术对比 简单总结一下各种引擎技术的优缺点:
解压缩与去壳 压缩是普通用户日常经常使用的减小文件体积的方法,常见的工具软件有WinZip、WinRAR等。病毒有时候会隐藏在压缩包内部,如果一个杀毒软件没有解压缩的能力就不可能查杀压缩包内的病毒。同时,如果杀毒软件不具备相应格式的压缩能力,在查杀病毒后就不能复原压缩包,导致压缩包破坏。可见,杀毒软件要想做到对病毒的全面捕获与查杀,脱壳解压能力也是至关重要的。 利用特征码技术的静态杀毒引擎 通常选择特征码是按照以下思路。 1.获取一个病毒程序的长度,根据长度可以将文件分为几份,份数根据样本长度而定,可以是3'5份,也可以更多。分成几段获取特征码的方法可以很大程度上避免采用单一特征码误报病毒现象的发生,也可以避免特征码过于集中造成的误报。 2.每份中选取通常为16或32个字节长的特征串。 在选取时,应该采取如下的原则: 1.如果选出来的信息是通用信息,即很多文件该位置都是一样的信息,那么舍弃,调整偏移量后重新选取。 2.如果选取出来的信息是全零的字节。那么也要调整偏移后重新选取。 当然调整的偏移量多少可以人为事先规定,也可以自动随机调节。最后,将选取出来的几段特征码及它们的偏移量存入病毒库,标示出病毒的名称即可。为了方便选取特征码,通常根据以上的思路编写出特征码提取程序,自动提取特征码并作为病毒记录存入病毒库。 关键数据结构 首先介绍程序中的两个重要结构VSIGNATURE和VRECORD。一个VSIGNATURE是一个特征,很多个特征组成了一条病毒记录,也就是一个VRECORD。 typedef struct tagVSIGNATURE { BAV_SIGN_TYPE eType; DWORD dwOffset; DWORD dwSize; BYTE Signature[MAX_SIGNATURE_LEN]; }VSIGNATURE,*PVSIGNATURE; typedef struct tagVRECORD { int nSize; DWORD dwVirusID; DWORD dwSignCount; PVSIGNATURE pVSing[8]; DWORD dwTreatCount; PVTREATMENT pVTreat[8]; }VRECORD,*PVRECORD; VSIGNATURE结构是用于存放单一特征码的,其中的eType成员变量是一个枚举结构,用来定义特征码的类型,这里演示工程里目前我们只定义了一种简单文件特征。dwOffset成员存储该特征码的偏移量。dwSize成员存储特征码的长度。字节型的Signature数组成员存放特征码串,最大长度由 MAX_SIGNATURE_LEN宏控制,目前为32字节。 VRECORD结构用于存放病毒库中每个病毒记录的内容。其中nSize用于控制结构的版本,目前我们不用过多关心。dwVirusID成员指定病毒的ID编号。dwSignCount成员存放特征码(VSIGNATURE)的段数,也就是对于该病毒取了多少段特征码。pVSing数组成员存放每段特征码的内容,这里用数组是为了演示方便,以后我们会改为可变长度的数据结构。dwTreatCount成员存放处理该病毒的方法数量。pVTreat数组成员存放处理该病毒的每种方法的内容。这两个成员要到我们增加杀毒方法的时候才会用到。 为了演示程序的简单,这一版的病毒库没有从文件加载,而是直接在CVirusDB::Load()中编码进去的。比如第一个eicar测试病毒的第一条特征是这样的: { BS_PHY_FILE, 0, 32, 0x58, 0x35, 0x 0x50, 0x5B, 0x34, 0x 0x34, 0x28, 0x50, 0x5E, 0x29, 0x37, 0x43, 0x43, 0x29, 0x37, 0x7D, 0x24, 0x45, 0x49, 0x43, 0x41, } 它表明这是一个简单文件特征,特征起始地址0,特征长度32,后面32个字节是具体特征值。 库与引擎类 引擎(CEngine)负责被扫描对象的遍历,病毒数据库对象(CVirusDB)负责在自己管理的库中搜索。对应到目前版本的代码上,引擎遍历目录,将找到的文件生成被扫描对象(CScanObj)交给当前病毒库对象的Search()方法。 CEngine类中DFS()函数是负责文件系统深度优先搜索的函数,其中以下一段就是产生一个对象,然后传递给CVirusDB::Search()方法来查毒: { m_cScanResults.dwObjCount++; CFileObject cScanObj; cScanObj.m_eObjType = BO_PHY_FILE; cScanObj.m_strObjName = lpszPathName; if( !cScanObj.Open() ) { // TODO: show error here. return; } DWORD dwVID = m_pcVDB->Search(&cScanObj); if( dwVID ) { PSCAN_RECORD pScanRecord = new SCAN_RECORD; if(pScanRecord) { CFileObject* pScanObj = new CFileObject(cScanObj); pScanRecord->dwVirusID = dwVID; pScanRecord->eResult = BR_WITH_VIRUS; pScanRecord->pScanObject= pScanObj; pScanRecord->pNext = m_cScanResults.pScanRecords; m_cScanResults.pScanRecords = pScanRecord; m_cScanResults.dwRecCount++; } } cScanObj.Close(); } CVirusDB类中的Search函数是用于在病毒库中匹配特征的成员函数,内容如下: DWORD CVirusDB::Search(CScanObject* pScanObj) { list while(iter!=m_listVRecords.end()) { PVRECORD pVRec = *iter; ASSERT(pVRec); if(pVRec) { bool bVirus = true; for(unsigned int i=0; i { bVirus &= pScanObj->Compare(pVRec->pVSing[i]->dwOffset, pVRec->pVSing[i]->dwSize, pVRec->pVSing[i]->Signature); if(!bVirus) break; } // match all signatures if(bVirus) { return pVRec->dwVirusID; } } else { // error return 0xFFFFFFFF; } iter++; } // no match record in VirusDB return 0; } While循环是遍历本病毒库中所有的记录。在For循环中,根据指向VRECORD结构的指针pVRec中dwSignCount的内容可知特征码的数量。然后循环用pScanObj->Compare()函数比较每段特征码与文件中指定偏移处的内容是否一致,如果全部一致,则说明该文件是病毒。 本次主要为大家介绍了根据特征码查病毒的方法,源代码可以在网站http://bav.netsv.org下载。在真实的环境中,查毒引擎的设计要比这个例子复杂上很多,利用了诸如脱壳,解压,虚拟机等等技术,这些我们将在日后的文章中逐渐介绍。 |