zoukankan      html  css  js  c++  java
  • ClamAV学习【9】——cvd文件解析及cli_untgz函数浏览

    这个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()
    ");
    
    	//dup复制文件描述符
        if((fdd = dup(fd)) == -1) {
    	cli_errmsg("cli_untgz: Can't duplicate descriptor %d
    ", fd);
    	return -1;
        }
    
    	//打开文件
        if((infile = gzdopen(fdd, "rb")) == NULL) {
    	cli_errmsg("cli_untgz: Can't gzdopen() descriptor %d, errno = %d
    ", 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
    ");
    	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
    ");
    	    free(path);
    	    gzclose(infile);
    	    return -1;
    	}
    
    	//上一种病毒库已经读完
    	//进行下一种病毒库文件头信息处理
    	//既是文件名、大小等
    	if(!in_block) {
    		//解压完病毒库
    	    if (block[0] == '')  /* We're done */
    		break;
    
    		//前99bytes中是文件名属性
    	    strncpy(name, block, 100);
    	    name[100] = '';
    
    		//该斜号分割不允许
    		//在錡indows下应该也需要更改,不过不影响
    		//name只能是文件名
    	    if(strchr(name, '/')) {
    		cli_errmsg("cli_untgz: Slash separators are not allowed in CVD
    ");
    		free(path);
    	        gzclose(infile);
    		return -1;
    	    }
    
    		//给路径变量赋值
    		//设置为$tempdir$/newvirusfilename
    	    snprintf(path, pathlen, "%s/%s", destdir, name);
    	    cli_dbgmsg("cli_untgz: Unpacking %s
    ", path);
    
    		//156位置文件标志
    	    type = block[156];
    
    		//判断类型
    	    switch(type) {
    		case '0':
    		case '':
    		    break;
    		case '5':
    		    cli_errmsg("cli_untgz: Directories are not supported in CVD
    ");
    		    free(path);
    	            gzclose(infile);
    		    return -1;
    		default:
    		    cli_errmsg("cli_untgz: Unknown type flag '%c'
    ", 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
    ", path);
    		    free(path);
    	            gzclose(infile);
    		    return -1;
    		}
    		outfile = NULL;
    	    }
    
    		//输出文件指针指向当前病毒库文件
    	    if(!(outfile = fopen(path, "wb"))) {
    		cli_errmsg("cli_untgz: Cannot create file %s
    ", path);
    		free(path);
    	        gzclose(infile);
    		return -1;
    	    }
    
    		//124后的为病毒签名数量
    	    strncpy(osize, block + 124, 12);
    	    osize[12] = '';
    
    		//读取数量,用于写是否结束判断标志
    	    if((sscanf(osize, "%o", &size)) == 0) {
    		cli_errmsg("cli_untgz: Invalid size in header
    ");
    		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)
    ", 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;
    }
    

    原文:http://blog.csdn.net/betabin/article/details/7456873

  • 相关阅读:
    Codeforces 1082 毛毛虫图构造&最大权闭合子图
    BZOJ 1003 最短路dp
    BZOJ 1002 生成树计数&高精度
    BZOJ 1001 平面图转对偶图
    BZOJ 世界树
    一般图极大团个数,最大团顶点数
    第十五届四川省省赛 SCU
    第十五届四川省省赛 SCU
    第十五届四川省省赛 SCU
    BZOJ4671异或图
  • 原文地址:https://www.cnblogs.com/sunylat/p/6393462.html
Copyright © 2011-2022 走看看