scan meta-data in RAR files

git-svn: trunk@1400
This commit is contained in:
Tomasz Kojm 2005-03-18 01:27:45 +00:00
parent e77215736b
commit a62ae54fc1
6 changed files with 107 additions and 37 deletions

View file

@ -1,3 +1,7 @@
Fri Mar 18 02:24:05 CET 2005 (tk)
---------------------------------
* libclamav: scan meta-data in RAR files
Wed Mar 16 21:55:44 CET 2005 (tk)
---------------------------------
* libclamav/pe.c: fix section handling in petite block

View file

@ -121,10 +121,10 @@ struct cli_md5_node {
struct cli_md5_node *next;
};
struct cli_zip_node {
int compr, csize, size, encrypted, crc32, fileno, maxdepth;
struct cli_meta_node {
int method, csize, size, encrypted, crc32, fileno, maxdepth;
char *filename, *virname;
struct cli_zip_node *next;
struct cli_meta_node *next;
};
struct cl_node {
@ -143,7 +143,11 @@ struct cl_node {
struct cli_md5_node **md5_hlist;
/* Zip metadata */
struct cli_zip_node *zip_mlist;
struct cli_meta_node *zip_mlist;
/* RAR metadata */
struct cli_meta_node *rar_mlist;
};
struct cl_limits {

View file

@ -390,7 +390,7 @@ void cl_free(struct cl_node *root)
{
int i;
struct cli_md5_node *md5pt, *md5h;
struct cli_zip_node *zippt, *ziph;
struct cli_meta_node *metapt, *metah;
if(!root) {
cli_errmsg("cl_free: root == NULL\n");
@ -432,14 +432,24 @@ void cl_free(struct cl_node *root)
free(root->md5_hlist);
}
zippt = root->zip_mlist;
while(zippt) {
ziph = zippt;
zippt = zippt->next;
free(ziph->virname);
if(ziph->filename)
free(ziph->filename);
free(ziph);
metapt = root->zip_mlist;
while(metapt) {
metah = metapt;
metapt = metapt->next;
free(metah->virname);
if(metah->filename)
free(metah->filename);
free(metah);
}
metapt = root->rar_mlist;
while(metapt) {
metah = metapt;
metapt = metapt->next;
free(metah->virname);
if(metah->filename)
free(metah->filename);
free(metah);
}
free(root);

View file

@ -705,11 +705,11 @@ static int cli_loadhdb(FILE *fd, struct cl_node **root, unsigned int *signo, uns
return 0;
}
static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
static int cli_loadmd(FILE *fd, struct cl_node **root, unsigned int *signo, int type)
{
char buffer[FILEBUFF], *pt;
int line = 0, comments = 0, ret = 0;
struct cli_zip_node *new;
struct cli_meta_node *new;
if(!*root) {
@ -728,7 +728,7 @@ static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
cli_chomp(buffer);
new = (struct cli_zip_node *) cli_calloc(1, sizeof(struct cli_zip_node));
new = (struct cli_meta_node *) cli_calloc(1, sizeof(struct cli_meta_node));
if(!new) {
ret = CL_EMEM;
break;
@ -817,9 +817,9 @@ static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
break;
} else {
if(!strcmp(pt, "*"))
new->compr = -1;
new->method = -1;
else
new->compr = atoi(pt);
new->method = atoi(pt);
free(pt);
}
@ -851,8 +851,13 @@ static int cli_loadzmd(FILE *fd, struct cl_node **root, unsigned int *signo)
free(pt);
}
new->next = (*root)->zip_mlist;
(*root)->zip_mlist = new;
if(type == 1) {
new->next = (*root)->zip_mlist;
(*root)->zip_mlist = new;
} else {
new->next = (*root)->rar_mlist;
(*root)->rar_mlist = new;
}
}
if(!line) {
@ -907,7 +912,10 @@ int cl_loaddb(const char *filename, struct cl_node **root, unsigned int *signo)
ret = cli_loadndb(fd, root, signo);
} else if(cli_strbcasestr(filename, ".zmd")) {
ret = cli_loadzmd(fd, root, signo);
ret = cli_loadmd(fd, root, signo, 1);
} else if(cli_strbcasestr(filename, ".rmd")) {
ret = cli_loadmd(fd, root, signo, 2);
} else {
cli_dbgmsg("cl_loaddb: unknown extension - assuming old database format\n");
@ -958,9 +966,10 @@ int cl_loaddbdir(const char *dirname, struct cl_node **root, unsigned int *signo
cli_strbcasestr(dent->d_name, ".db2") ||
cli_strbcasestr(dent->d_name, ".db3") ||
cli_strbcasestr(dent->d_name, ".hdb") ||
cli_strbcasestr(dent->d_name, ".fp") ||
cli_strbcasestr(dent->d_name, ".fp") ||
cli_strbcasestr(dent->d_name, ".ndb") ||
cli_strbcasestr(dent->d_name, ".zmd") ||
cli_strbcasestr(dent->d_name, ".rmd") ||
cli_strbcasestr(dent->d_name, ".cvd"))) {
dbfile = (char *) cli_calloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));
@ -1040,6 +1049,7 @@ int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
cli_strbcasestr(dent->d_name, ".fp") ||
cli_strbcasestr(dent->d_name, ".ndb") ||
cli_strbcasestr(dent->d_name, ".zmd") ||
cli_strbcasestr(dent->d_name, ".rmd") ||
cli_strbcasestr(dent->d_name, ".cvd"))) {
dbstat->no++;
@ -1110,6 +1120,7 @@ int cl_statchkdir(const struct cl_stat *dbstat)
cli_strbcasestr(dent->d_name, ".fp") ||
cli_strbcasestr(dent->d_name, ".ndb") ||
cli_strbcasestr(dent->d_name, ".zmd") ||
cli_strbcasestr(dent->d_name, ".rmd") ||
cli_strbcasestr(dent->d_name, ".cvd"))) {
fname = cli_calloc(strlen(dbstat->dir) + strlen(dent->d_name) + 2, sizeof(char));

View file

@ -120,23 +120,23 @@ static void cli_unlock_mutex(void *mtx)
static int cli_scanrar(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, int *arec, int *mrec)
{
FILE *tmp = NULL;
int files = 0, fd, ret = CL_CLEAN, afiles;
int files = 0, fd, ret = CL_CLEAN, afiles, encrypted;
ArchiveList_struct *rarlist = NULL;
ArchiveList_struct *rarlist_head = NULL;
char *rar_data_ptr;
unsigned long rar_data_size;
struct cli_meta_node *mdata;
cli_dbgmsg("in scanrar()\n");
#ifdef CL_THREAD_SAFE
pthread_cleanup_push(cli_unlock_mutex, &cli_scanrar_mutex);
pthread_mutex_lock(&cli_scanrar_mutex);
cli_scanrar_inuse = 1;
#endif
if(! (afiles = urarlib_list(desc, (ArchiveList_struct *) &rarlist))) {
if(!(afiles = urarlib_list(desc, (ArchiveList_struct *) &rarlist))) {
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_scanrar_mutex);
cli_scanrar_inuse = 0;
@ -149,8 +149,52 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
rarlist_head = rarlist;
while(rarlist) {
files++;
encrypted = rarlist->item.Flags & 0x04;
cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", rarlist->item.Name, rarlist->item.FileCRC, encrypted, rarlist->item.PackSize, rarlist->item.UnpSize, rarlist->item.Method, rarlist->item.PackSize ? (rarlist->item.UnpSize / rarlist->item.PackSize) : 0, limits ? limits->maxratio : -1);
/* Scan metadata */
mdata = root->rar_mlist;
if(mdata) do {
if(mdata->encrypted != encrypted)
continue;
if(mdata->crc32 && mdata->crc32 != rarlist->item.FileCRC)
continue;
if(mdata->csize > 0 && mdata->csize != rarlist->item.PackSize)
continue;
if(mdata->size >= 0 && mdata->size != rarlist->item.UnpSize)
continue;
if(mdata->method >= 0 && mdata->method != rarlist->item.Method)
continue;
if(mdata->fileno && mdata->fileno != files)
continue;
if(mdata->maxdepth && *arec > mdata->maxdepth)
continue;
/* TODO add support for regex */
/*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
if(mdata->filename && strcmp(rarlist->item.Name, mdata->filename))
continue;
break; /* matched */
} while((mdata = mdata->next));
if(mdata) {
*virname = mdata->virname;
ret = CL_VIRUS;
break;
}
if(DETECT_ENCRYPTED && (rarlist->item.Flags & 0x04)) {
files++;
cli_dbgmsg("RAR: Encrypted files found in archive.\n");
lseek(desc, 0, SEEK_SET);
ret = cli_scandesc(desc, virname, scanned, root, 0, 0);
@ -166,7 +210,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
if((rarlist->item.Flags & 0x03) != 0) {
cli_dbgmsg("RAR: Skipping %s (splitted)\n", rarlist->item.Name);
rarlist = rarlist->next;
files++;
continue;
}
@ -184,7 +227,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
if(limits->maxfilesize && (rarlist->item.UnpSize > (unsigned int) limits->maxfilesize)) {
cli_dbgmsg("RAR: %s: Size exceeded (%u, max: %lu)\n", rarlist->item.Name, (unsigned int) rarlist->item.UnpSize, limits->maxfilesize);
rarlist = rarlist->next;
files++;
if(BLOCKMAX) {
*virname = "RAR.ExceededFileSize";
ret = CL_VIRUS;
@ -206,7 +248,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
if(rarlist->item.FileAttr & RAR_FENTRY_ATTR_DIRECTORY) {
rarlist = rarlist->next;
files++;
continue;
}
@ -273,7 +314,6 @@ static int cli_scanrar(int desc, const char **virname, long int *scanned, const
fclose(tmp);
tmp = NULL;
rarlist = rarlist->next;
files++;
}
urarlib_freelist(rarlist_head);
@ -298,7 +338,7 @@ static int cli_scanzip(int desc, const char **virname, long int *scanned, const
char *buff;
int fd, bytes, files = 0, ret = CL_CLEAN, encrypted;
struct stat source;
struct cli_zip_node *mdata;
struct cli_meta_node *mdata;
zzip_error_t err;
@ -331,7 +371,7 @@ static int cli_scanzip(int desc, const char **virname, long int *scanned, const
encrypted = zdirent.d_flags;
cli_dbgmsg("Zip: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, ratio: %d (max: %d)\n", zdirent.d_name, zdirent.d_crc32, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, limits ? limits->maxratio : -1);
cli_dbgmsg("Zip: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", zdirent.d_name, zdirent.d_crc32, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_compr, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, limits ? limits->maxratio : -1);
if(!zdirent.st_size) {
if(zdirent.d_crc32) {
@ -358,7 +398,7 @@ static int cli_scanzip(int desc, const char **virname, long int *scanned, const
if(mdata->size >= 0 && mdata->size != zdirent.st_size)
continue;
if(mdata->compr >= 0 && mdata->compr != zdirent.d_compr)
if(mdata->method >= 0 && mdata->method != zdirent.d_compr)
continue;
if(mdata->fileno && mdata->fileno != files)

View file

@ -251,7 +251,7 @@ int build(struct optstruct *opt)
exit(1);
}
if(stat("main.db", &foo) == -1 && stat("daily.db", &foo) == -1 && stat("main.hdb", &foo) == -1 && stat("daily.hdb", &foo) == -1 && stat("main.ndb", &foo) == -1 && stat("daily.ndb", &foo) == -1 && stat("main.zmd", &foo) == -1 && stat("daily.zmd", &foo) == -1) {
if(stat("main.db", &foo) == -1 && stat("daily.db", &foo) == -1 && stat("main.hdb", &foo) == -1 && stat("daily.hdb", &foo) == -1 && stat("main.ndb", &foo) == -1 && stat("daily.ndb", &foo) == -1 && stat("main.zmd", &foo) == -1 && stat("main.rmd", &foo) == -1 && stat("daily.zmd", &foo) == -1 && stat("daily.rmd", &foo) == -1) {
mprintf("Virus database not found in current working directory.\n");
exit(1);
}
@ -271,7 +271,7 @@ int build(struct optstruct *opt)
mprintf("WARNING: There are no signatures in the database(s).\n");
} else {
mprintf("Signatures: %d\n", no);
realno = countlines("main.db") + countlines("daily.db") + countlines("main.hdb") + countlines("daily.hdb") + countlines("main.ndb") + countlines("daily.ndb") + countlines("main.zmd") + countlines("daily.zmd");
realno = countlines("main.db") + countlines("daily.db") + countlines("main.hdb") + countlines("daily.hdb") + countlines("main.ndb") + countlines("daily.ndb") + countlines("main.zmd") + countlines("daily.zmd") + countlines("main.rmd") + countlines("daily.rmd");
if(realno != no) {
mprintf("!Signatures in database: %d. Loaded: %d.\n", realno, no);
mprintf("Please check the current directory and remove unnecessary databases\n");
@ -288,7 +288,7 @@ int build(struct optstruct *opt)
exit(1);
case 0:
{
char *args[] = { "tar", "-cvf", NULL, "COPYING", "main.db", "daily.db", "Notes", "viruses.db3", "main.hdb", "daily.hdb", "main.ndb", "daily.ndb", "main.zmd", "daily.zmd", "main.fp", "daily.fp", NULL };
char *args[] = { "tar", "-cvf", NULL, "COPYING", "main.db", "daily.db", "Notes", "viruses.db3", "main.hdb", "daily.hdb", "main.ndb", "daily.ndb", "main.zmd", "daily.zmd", "main.rmd", "daily.rmd", "main.fp", "daily.fp", NULL };
args[2] = tarfile;
execv("/bin/tar", args);
mprintf("!Can't execute tar\n");
@ -705,7 +705,7 @@ int listdb(const char *filename)
free(start);
}
} else if(cli_strbcasestr(filename, ".ndb") || cli_strbcasestr(filename, ".zmd")) {
} else if(cli_strbcasestr(filename, ".ndb") || cli_strbcasestr(filename, ".zmd") || cli_strbcasestr(filename, ".rmd")) {
while(fgets(buffer, FILEBUFF, fd)) {
line++;
@ -755,6 +755,7 @@ int listdir(const char *dirname)
cli_strbcasestr(dent->d_name, ".hdb") ||
cli_strbcasestr(dent->d_name, ".ndb") ||
cli_strbcasestr(dent->d_name, ".zmd") ||
cli_strbcasestr(dent->d_name, ".rmd") ||
cli_strbcasestr(dent->d_name, ".cvd"))) {
dbfile = (char *) mcalloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));