`
wsql
  • 浏览: 11753499 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

特征码技术的静态杀毒引擎(20050822AA39)

 
阅读更多

time:2005-08-22

kaspersky club 21楼会议室


利用特征码技术的静态杀毒引擎
特征码的选取
在进入程序的详细讲解之前,先来讲一下对于病毒程序的特征码通常是如何选取出来的,以及特征码的结构是什么样子的。

通常选择特征码是按照以下思路。

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, 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个字节是具体特征值。

库与引擎类
清楚了这两个结构,接下来我们看一下具体的扫描代码。特征串的匹配其实就是memcmp,没有什么特别的,关键讲解一下引擎、库与被扫描对象之间的基本关系和分工。

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics