扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国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
while(iter!=m_listVRecords.end())
{
PVRECORD pVRec = *iter;
ASSERT(pVRec);
if(pVRec)
{
bool bVirus = true;
for(unsigned int i=0; i
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领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者