_ _ (_) | | __ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_ \ \ / /\ \/ /| || | | || '_ ` _ \ | '_ \ | '_ \ / _ \| __| \ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_ \_/ /_/\_\| | \__,_||_| |_| |_|| .__/(_)|_| |_| \___| \__| _/ | | | |__/ |_| /---------------------------------------------------------------------------------------\ |>...................[ Clam AV引擎分析v0.71版 ]...................<| |>......................[ by nEINEI/vxjump.net ]......................<| |>......................[ 2008-03-22 ]......................<| \>...................... [ neineit@gmail.com ] ......................From ", "Received", "Message-Id: "等文件格式识别方面采用顺序匹配方式,结构如下: struct cli_magic_s { int offset; // 待匹配数据在文件处的偏移 const char *magic; // 待匹配数据 size_t length; // 待匹配数据长度 const char *descr; // 针对类型的描述 cli_file_t type; // 对应文件的格式 }; 目前只对文件头部前26个字节数据进行验证。在格式分析完成后调用对应的扫描分析。 [0x05] 扫描分析函数 1 cli_scanpe 分析: 该版会对PE格式的文件做前置的合法性校验,非法情况返回-1,不进行处理。 但在合法性校验完成后,并未继续扫描,作者写上 /* to be continued ... */ 应该想在下一版本中完善这块。 2 cli_scanrar 分析: 先将rar包裹内文件用链表链接起来,根据分析类型来做下一步处理,主要区分以下情况, 1 包裹加密 2 包内文件大小,超过引擎最大扫描文件大小设定值, 3 包裹内含文件数量,超过引擎最大包裹内文件数量设定值 4 是否是目录 当这几种情况都判断完后,继续调用cli_magic_scandesc 扫描,此时为递归处理。 3 cli_scanzip 分析: 与上面的判断情况类似,但增加了对文件压缩比的判断 。 4 cli_scanbzip分析: 类似同上 5 cli_scangzip分析: 类似同上 6 cli_scanmscomp分析: 将该文件解压到临时文件,然后调用cli_magic_scandesc 扫描。 7 cli_scanmail 调用前一版本的mail检测函数。 8 cli_scanole2 先调用cli_ole2_extract进行解析,而后用cli_vba_scandir 进行扫描,在该函数中进行针对解压后的数据buffer扫描和 生成到临时目录的目录扫描。Ole2 检测流程: 此版对ole2 的文件识别是基于8字节的数据匹配,在识别完成后, 1)先读取ole2的文件头。 2)转换文件头各个字段数据的高低位顺序。 3)然后进行文件头各个字段的校验 4)调用ole2_walk_property_tree 函数递归解出数据到一指定目录。在识别过程中主要区分Root Entry , File ,Directory 三种方式,分别处理。 对于 Root Entry 主要会验证 检测层数,文件个数等。 对于 File 则调用回调函数,将数据写到指定文件当中。 对应 Directory 则创建目录,继续递归调用。 5)该版本支持能检测office的产品有 vba_version_t vba_version[] = { { { 0x5e, 0x00, 0x00, 0x01 }, "Office 97", 5, FALSE}, { { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1", 5, FALSE }, { { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?", 6, FALSE }, { { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?", 6, FALSE }, { { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE }, { { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE }, { { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2", 6, FALSE }, { { 0x73, 0x00, 0x00, 0x01 }, "Office XP", 6, FALSE }, { { 0x76, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE }, { { 0x79, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE }, { { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98", 5, TRUE }, { { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001", 5, TRUE }, { { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X", 6, TRUE }, }; 该版本中,最后一个字段 FALSE ,和 TRUE 对程序解析无任何影响,区别是对数据做高低位转换。目前不区分对 FALSE,TRUE 对转换的影响。 在将0le2 文件解码到指定文件目录后,会调用cli_vba_scandir 进行数据的扫描,在该函数中首先会将文件解析成vba_project_tag格式的数据 typedef struct vba_project_tag { int count; // 解析后形成文件的个数 char **name; // 对应的文件名 uint32_t *offset; // 待扫描数据的偏移,指在被解出来的数据中的偏移 uint32_t *length; /* for Word 6 macros */ unsigned char *key; /* for Word 6 macros */ char *dir; } vba_project_t; 在该函数中 对 vba_decompress 来解出来的数据进行buffer扫描,calm av 将buffer扫描封装到最底层,相应的上层 扫描调用接口有很多,如cli_scandesc, cli_scandir , cli_scanfile 等等,最终调用的就是 cli_scanbuffer。 结构体中key 是针对解密宏时用到的,解密的方法为异或。 [0x06] 总结 1 CVD格式的描述说明 CVD 格式文件包含一个cl_cvd结构的文件头,及用gz压缩的数据。 解压后为文本格式*.db 文件,或*.db2 格式的文件。 2 如何检测OLE2格式和WORD宏 该版对OLE2 的检测是通过8在字节的数据 "\320\317\021\340\241\261\032\341" 进行识别的。 针对word 宏的检测是在解开OLE2文件后,有一个对ms office 进行的产品识别结构,在该函数中识别具体的产品。 3 如何检测加密的包裹 new flags: CL_OLE2, CL_ENCRYPTED 加密包裹主要是通过 DETECT_ENCRYPTED 与一个特定的文件标志做“&&操作”运算 来决定的,对于 1 RAR包: 通过 if( DETECT_ENCRYPTED && (rarlist->item.Flags & 4)) 来判断。 其中 item.Flags 是通过 GetHeaderWord 函数获得的,该将指定的unsinged short int数据做高低位转换。传入的数据为RAR包头部数据。 2 ZIP包: 通过 if(DETECT_ENCRYPTED && (zdirent.d_flags & 1 )) 来判断。 其中zdirent结构为开源的解zip库中定义的结构。 3 绕过类型的格式识别整理:ignore popular file types (media, graphics) 目前针对检测忽略的文件类型有MPGE ,RIFF , GIF , PNG,JPEG,BMP,MP3,PDF,PSOTSCRIPT,WMA,WMV,ASF,RM. 参考文献: [1] clam av 0.71 src. thanks killer,一起讨论研究引擎设计及提出若干问题。