ClamAV学习【9】——cvd文件解析及cli_untgz函数浏览

来源:互联网 发布:spss数据分析报告范文 编辑:程序博客网 时间:2024/05/16 14:01

这个cli_untgz函数,是用来解压CVD文件的。

那么,就刚先搞清楚CVD文件的功能作用。下了源码,我们会发现,没有前面提到的*.mdb或者*.hbd等病毒签名文件。原因就是,那些文件都是由CVD文件解压生成的,是的,CVD是个病毒签名压缩文件。(下面是daily.cvd解压后的)


CVD文件,前512个bytes是一个特殊的头文件,在前面也提到过了(http://blog.csdn.net/betabin/article/details/7448447)。记录引擎病毒库的简单信息。然后后面的内容,曾经多次用UE打开,发现是乱码。所以,是个压缩文件。压缩类型,根据cli_untgz函数里面使用的gzread读取函数,可以猜到是使用zlib压缩库压缩的。然后根据函数内容,接着可以判断出,原信息是一个接着一个病毒库文件存储的。既是每个新的病毒库开始的前512bytes中,存储着名字及病毒签名数量。接着就是病毒签名信息。通过签名的病毒签名数量,可以判断正在读取的病毒签名是否读取完。

还是贴代码注释比较好理解:

//解压CVD文件到临时目录中int cli_untgz(int fd, const char *destdir){char *path, osize[13], name[101], type;char block[TAR_BLOCKSIZE];int nbytes, nread, nwritten, in_block = 0, fdd;unsigned int size, pathlen = strlen(destdir) + 100 + 5;FILE *outfile = NULL;struct stat foo;gzFile *infile;//提示    cli_dbgmsg("in cli_untgz()\n");//dup复制文件描述符    if((fdd = dup(fd)) == -1) {cli_errmsg("cli_untgz: Can't duplicate descriptor %d\n", fd);return -1;    }//打开文件    if((infile = gzdopen(fdd, "rb")) == NULL) {cli_errmsg("cli_untgz: Can't gzdopen() descriptor %d, errno = %d\n", fdd, errno);if(fstat(fdd, &foo) == 0)    close(fdd);return -1;    }//路径变量分配内存    path = (char *) cli_calloc(sizeof(char), pathlen);    if(!path) {cli_errmsg("cli_untgz: Can't allocate memory for path\n");gzclose(infile);return -1;    }//开始循环读取cvd文件内容    while(1) {//每次读取512个bytes部分nread = gzread(infile, block, TAR_BLOCKSIZE);//上一种病毒库已经读完//且读不到下一种病毒库头信息时//结束if(!in_block && !nread)    break;if(nread != TAR_BLOCKSIZE) {    cli_errmsg("cli_untgz: Incomplete block read\n");    free(path);    gzclose(infile);    return -1;}//上一种病毒库已经读完//进行下一种病毒库文件头信息处理//既是文件名、大小等if(!in_block) {//解压完病毒库    if (block[0] == '\0')  /* We're done */break;//前99bytes中是文件名属性    strncpy(name, block, 100);    name[100] = '\0';//该斜号分割不允许//在錡indows下应该也需要更改,不过不影响//name只能是文件名    if(strchr(name, '/')) {cli_errmsg("cli_untgz: Slash separators are not allowed in CVD\n");free(path);        gzclose(infile);return -1;    }//给路径变量赋值//设置为$tempdir$/newvirusfilename    snprintf(path, pathlen, "%s/%s", destdir, name);    cli_dbgmsg("cli_untgz: Unpacking %s\n", path);//156位置文件标志    type = block[156];//判断类型    switch(type) {case '0':case '\0':    break;case '5':    cli_errmsg("cli_untgz: Directories are not supported in CVD\n");    free(path);            gzclose(infile);    return -1;default:    cli_errmsg("cli_untgz: Unknown type flag '%c'\n", type);    free(path);            gzclose(infile);    return -1;    }//设置in_block参数//表示接下来开始写内容    in_block = 1;//关闭上一个病毒库文件指针    if(outfile) {if(fclose(outfile)) {    cli_errmsg("cli_untgz: Cannot close file %s\n", path);    free(path);            gzclose(infile);    return -1;}outfile = NULL;    }//输出文件指针指向当前病毒库文件    if(!(outfile = fopen(path, "wb"))) {cli_errmsg("cli_untgz: Cannot create file %s\n", path);free(path);        gzclose(infile);return -1;    }//124后的为病毒签名数量    strncpy(osize, block + 124, 12);    osize[12] = '\0';//读取数量,用于写是否结束判断标志    if((sscanf(osize, "%o", &size)) == 0) {cli_errmsg("cli_untgz: Invalid size in header\n");free(path);        gzclose(infile);fclose(outfile);return -1;    }} else { /* write or continue writing file contents *///写入path病毒文件nbytes = size > TAR_BLOCKSIZE ? TAR_BLOCKSIZE : size;    nwritten = fwrite(block, 1, nbytes, outfile);    if(nwritten != nbytes) {cli_errmsg("cli_untgz: Wrote %d instead of %d (%s)\n", nwritten, nbytes, path);free(path);        gzclose(infile);return -1;    }//减去已经写了的病毒签名数//判断是否结束    size -= nbytes;    if(size == 0)in_block = 0;}    }    if(outfile)fclose(outfile);    gzclose(infile);    free(path);    return 0;}


原创粉丝点击