科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网网络频道杀毒软件技术之静态查毒引擎的实现

杀毒软件技术之静态查毒引擎的实现

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

了躲避杀毒软件的查杀,电脑病毒开始进化。病毒为了躲避杀毒软件的查杀,逐渐演变为变形的形式,每感染一次,就对自身变一次形,通过对自身的变形来躲避查杀。

作者:中国IT实验室 2007年8月30日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共2页)

  VSIGNATURE结构是用于存放单一特征码的,其中的eType 成员变量是一个枚举结构,用来定义特征码的类型,这里演示工程里目前我们只定义了一种简单文件特征。dwOffset 成员存储该特征码的偏移量。dwSize 成员存储特征码的长度。字节型的Signature数组成员存放特征

码串,最大长度由 MAX_SIGNATURE_LEN 宏控制,目前为32 字节。

  VRECORD 结构用于存放病毒库中每个病毒记录的内容。其中nSize用于控制结构的版本,目前我们不用过多关心。dwVirusID成员指定病毒的ID 编号。dwSignCount成员存放特征码(VSIGNATURE)的段数,也就是对于该病毒取了多少段特征码。pVSing 数组成员存放每段特征码

的内容,这里用数组是为了演示方便,以后我们会改为可变长度的数据结构。dwTreatCount成员存放处理该病毒的方法数量。pVTreat数组成员存放处理该病毒的每种方法的内容。这两个成员要到我们增加杀毒方法的时候才会用到。

  下面来看一个具体的例子,eicar测试病毒的第一条特征是这样的:

{

BS_PHY_FILE, 0, 32,

0x58, 0x35, 0x4F, 0x21, 0x50, 0x25, 0x40, 0x41,

0x50, 0x5B, 0x34, 0x5C, 0x50, 0x5A, 0x58, 0x35,

0x34, 0x28, 0x50, 0x5E, 0x29, 0x37, 0x43, 0x43,

0x29, 0x37, 0x7D, 0x24, 0x45, 0x49, 0x43, 0x41,

}

  它表明这是一个简单文件特征,特征起始地址0,特征长度32,后面32 个字节是具体特征值。

  库与引擎类

  清楚了病毒库的构成后,接下来我们看一下具体的扫描方法。关键要把引擎、库与被扫描对象之间的基本关系和分工搞清楚。

  引擎(CEngine)负责被扫描对象的遍历,对应到目前版本的代码上,引擎遍历目录,将找到的文件生成被扫描对象(CScanObj)交给当前病毒库对象的Search()方法。而病毒数据库对象(CVirusDB)则负责在自己管理的库中搜索。为了演示程序的简单,这一版的病毒库没有从文件中加载,而是直接在CVirusDB::Load()中编码进去的。从整体上来看,搜索过程经历了下面3 个阶段:

  1. CEngine遍历目录,生成被扫描对象并把该对象传递到病毒数据库中m_pcVDB->Search(&cScanObj)

  2. 病毒数据库搜索自身的记录CVirusDB::Search(),并调用被扫描对象CFileObject 的Compare()方法进行匹配;

  3. 被扫描对象返回匹配结果,病毒库对象(CVirusDB)根据结果来决定是否是病毒,并返回病毒ID。

  下面就来仔细看看以上提到的每一个关键部分:

  首先是引擎的目录遍历。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::iterator iter = m_listVRecords.begin();

while(iter!=m_listVRecords.end())

{

PVRECORD pVRec = *iter;

ASSERT(pVRec);

if(pVRec)

{

bool bVirus = true;

for(unsigned int i=0; idwSignCount;

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()函数比较每段特征码与文件中指定偏移处的内容是否一致,如果全部一致,则说明该文件是病毒。

  最后,被扫描对象进行特征串的匹配其实就是memcmp,这一步没有什么特别的。

  本次主要为大家介绍了根据特征码查病毒的方法,源代码可以在网站http://bav.netsv.org 下载。在真实的环境中,查毒引擎的设计要比这个例子复杂上很多,一般都有多个库,还利用了诸如脱壳,解压,虚拟机等等技术,这些我们将在日后的文章中逐渐介绍。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章