git-svn: trunk@2310
Tomasz Kojm authored on 2006/09/27 09:36:11... | ... |
@@ -1,3 +1,9 @@ |
1 |
+Wed Sep 27 02:34:00 CEST 2006 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: add support for PE section based MD5 signatures (stored in .mdb) |
|
4 |
+ Requested by Christoph |
|
5 |
+ * sigtool: handle .mdb databases |
|
6 |
+ |
|
1 | 7 |
Tue Sep 26 17:42:17 BST 2006 (njh) |
2 | 8 |
---------------------------------- |
3 | 9 |
* libclamav/mbox.c: Experimental curl removal: fix proxy handling and |
... | ... |
@@ -49,6 +49,7 @@ |
49 | 49 |
#include "rebuildpe.h" |
50 | 50 |
#include "str.h" |
51 | 51 |
#include "execs.h" |
52 |
+#include "md5.h" |
|
52 | 53 |
|
53 | 54 |
#ifndef O_BINARY |
54 | 55 |
#define O_BINARY 0 |
... | ... |
@@ -173,6 +174,49 @@ static int cli_ddump(int desc, int offset, int size, const char *file) |
173 | 173 |
} |
174 | 174 |
*/ |
175 | 175 |
|
176 |
+static unsigned char *cli_md5sect(int fd, uint32_t offset, uint32_t size) |
|
177 |
+{ |
|
178 |
+ size_t bread, sum = 0; |
|
179 |
+ off_t pos; |
|
180 |
+ char buff[FILEBUFF]; |
|
181 |
+ unsigned char *digest; |
|
182 |
+ MD5_CTX md5ctx; |
|
183 |
+ |
|
184 |
+ |
|
185 |
+ if((pos = lseek(fd, 0, SEEK_CUR)) == -1) { |
|
186 |
+ cli_dbgmsg("cli_md5sect: Invalid descriptor %d\n", fd); |
|
187 |
+ return NULL; |
|
188 |
+ } |
|
189 |
+ |
|
190 |
+ if(lseek(fd, offset, SEEK_SET) == -1) { |
|
191 |
+ cli_dbgmsg("cli_md5sect: lseek() failed\n"); |
|
192 |
+ lseek(fd, pos, SEEK_SET); |
|
193 |
+ return NULL; |
|
194 |
+ } |
|
195 |
+ |
|
196 |
+ digest = cli_calloc(16, sizeof(char)); |
|
197 |
+ if(!digest) { |
|
198 |
+ cli_errmsg("cli_md5sect: Can't allocate memory for digest\n"); |
|
199 |
+ return NULL; |
|
200 |
+ } |
|
201 |
+ |
|
202 |
+ MD5_Init(&md5ctx); |
|
203 |
+ |
|
204 |
+ while((bread = cli_readn(fd, buff, FILEBUFF)) > 0) { |
|
205 |
+ if(sum + bread >= size) { |
|
206 |
+ MD5_Update(&md5ctx, buff, size - sum); |
|
207 |
+ break; |
|
208 |
+ } else { |
|
209 |
+ MD5_Update(&md5ctx, buff, bread); |
|
210 |
+ sum += bread; |
|
211 |
+ } |
|
212 |
+ } |
|
213 |
+ |
|
214 |
+ MD5_Final(digest, &md5ctx); |
|
215 |
+ lseek(fd, pos, SEEK_SET); |
|
216 |
+ return digest; |
|
217 |
+} |
|
218 |
+ |
|
176 | 219 |
int cli_scanpe(int desc, cli_ctx *ctx) |
177 | 220 |
{ |
178 | 221 |
uint16_t e_magic; /* DOS signature ("MZ") */ |
... | ... |
@@ -185,9 +229,10 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
185 | 185 |
struct pe_image_optional_hdr32 optional_hdr32; |
186 | 186 |
struct pe_image_optional_hdr64 optional_hdr64; |
187 | 187 |
struct pe_image_section_hdr *section_hdr; |
188 |
+ struct cli_md5_node *md5_sect; |
|
188 | 189 |
struct stat sb; |
189 | 190 |
char sname[9], buff[4096], *tempfile; |
190 |
- unsigned char *ubuff; |
|
191 |
+ unsigned char *ubuff, *md5_dig; |
|
191 | 192 |
ssize_t bytes; |
192 | 193 |
unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0; |
193 | 194 |
unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0; |
... | ... |
@@ -561,6 +606,31 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
561 | 561 |
return CL_VIRUS; |
562 | 562 |
} |
563 | 563 |
broken = 1; |
564 |
+ |
|
565 |
+ } else { |
|
566 |
+ /* check MD5 section sigs */ |
|
567 |
+ md5_sect = ctx->engine->md5_sect; |
|
568 |
+ while(md5_sect && md5_sect->size < EC32(section_hdr[i].SizeOfRawData)) |
|
569 |
+ md5_sect = md5_sect->next; |
|
570 |
+ |
|
571 |
+ if(md5_sect && md5_sect->size == EC32(section_hdr[i].SizeOfRawData)) { |
|
572 |
+ md5_dig = cli_md5sect(desc, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData)); |
|
573 |
+ if(!md5_dig) { |
|
574 |
+ cli_errmsg("PE: Can't calculate MD5 for section %d\n", i); |
|
575 |
+ } else { |
|
576 |
+ while(md5_sect && md5_sect->size == EC32(section_hdr[i].SizeOfRawData)) { |
|
577 |
+ if(!strcmp(md5_dig, md5_sect->md5)) { |
|
578 |
+ if(ctx->virname) |
|
579 |
+ *ctx->virname = md5_sect->virname; |
|
580 |
+ free(md5_dig); |
|
581 |
+ free(section_hdr); |
|
582 |
+ return CL_VIRUS; |
|
583 |
+ } |
|
584 |
+ md5_sect = md5_sect->next; |
|
585 |
+ } |
|
586 |
+ free(md5_dig); |
|
587 |
+ } |
|
588 |
+ } |
|
564 | 589 |
} |
565 | 590 |
|
566 | 591 |
if(!i) { |
... | ... |
@@ -584,6 +654,8 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
584 | 584 |
|
585 | 585 |
} |
586 | 586 |
|
587 |
+ |
|
588 |
+ |
|
587 | 589 |
if(pe_plus) |
588 | 590 |
ep = EC32(optional_hdr64.AddressOfEntryPoint); |
589 | 591 |
else |
... | ... |
@@ -739,11 +739,11 @@ static int cli_loadndb(FILE *fd, struct cl_engine **engine, unsigned int *signo, |
739 | 739 |
return CL_SUCCESS; |
740 | 740 |
} |
741 | 741 |
|
742 |
-static int cli_loadhdb(FILE *fd, struct cl_engine **engine, unsigned int *signo, unsigned short fp, unsigned int options) |
|
742 |
+static int cli_loadhdb(FILE *fd, struct cl_engine **engine, unsigned int *signo, unsigned short mode, unsigned int options) |
|
743 | 743 |
{ |
744 | 744 |
char buffer[FILEBUFF], *pt; |
745 | 745 |
int line = 0, ret = 0; |
746 |
- struct cli_md5_node *new; |
|
746 |
+ struct cli_md5_node *new, *mpt, *last; |
|
747 | 747 |
|
748 | 748 |
|
749 | 749 |
if((ret = cli_initengine(engine, options))) { |
... | ... |
@@ -761,7 +761,8 @@ static int cli_loadhdb(FILE *fd, struct cl_engine **engine, unsigned int *signo, |
761 | 761 |
break; |
762 | 762 |
} |
763 | 763 |
|
764 |
- new->fp = fp; |
|
764 |
+ if(mode == 1) /* fp */ |
|
765 |
+ new->fp = 1; |
|
765 | 766 |
|
766 | 767 |
if(!(pt = cli_strtok(buffer, 0, ":"))) { |
767 | 768 |
free(new); |
... | ... |
@@ -796,17 +797,38 @@ static int cli_loadhdb(FILE *fd, struct cl_engine **engine, unsigned int *signo, |
796 | 796 |
|
797 | 797 |
new->viralias = cli_strtok(buffer, 3, ":"); /* aliases are optional */ |
798 | 798 |
|
799 |
- if(!(*engine)->md5_hlist) { |
|
800 |
- cli_dbgmsg("Initializing md5 list structure\n"); |
|
801 |
- (*engine)->md5_hlist = (struct cli_md5_node **) cli_calloc(256, sizeof(struct cli_md5_node *)); |
|
799 |
+ if(mode == 2) { /* section MD5 */ |
|
800 |
+ if(!(*engine)->md5_sect) { |
|
801 |
+ (*engine)->md5_sect = new; |
|
802 |
+ } else { |
|
803 |
+ if(new->size < (*engine)->md5_sect->size) { |
|
804 |
+ new->next = (*engine)->md5_sect; |
|
805 |
+ (*engine)->md5_sect = new; |
|
806 |
+ } else { |
|
807 |
+ mpt = (*engine)->md5_sect; |
|
808 |
+ while(mpt) { |
|
809 |
+ last = mpt; |
|
810 |
+ if((mpt->size < new->size) && (!mpt->next || new->size < mpt->next->size)) |
|
811 |
+ break; |
|
812 |
+ mpt = mpt->next; |
|
813 |
+ } |
|
814 |
+ new->next = last->next; |
|
815 |
+ last->next = new; |
|
816 |
+ } |
|
817 |
+ } |
|
818 |
+ } else { |
|
802 | 819 |
if(!(*engine)->md5_hlist) { |
803 |
- ret = CL_EMEM; |
|
804 |
- break; |
|
820 |
+ cli_dbgmsg("Initializing md5 list structure\n"); |
|
821 |
+ (*engine)->md5_hlist = (struct cli_md5_node **) cli_calloc(256, sizeof(struct cli_md5_node *)); |
|
822 |
+ if(!(*engine)->md5_hlist) { |
|
823 |
+ ret = CL_EMEM; |
|
824 |
+ break; |
|
825 |
+ } |
|
805 | 826 |
} |
806 |
- } |
|
807 | 827 |
|
808 |
- new->next = (*engine)->md5_hlist[new->md5[0] & 0xff]; |
|
809 |
- (*engine)->md5_hlist[new->md5[0] & 0xff] = new; |
|
828 |
+ new->next = (*engine)->md5_hlist[new->md5[0] & 0xff]; |
|
829 |
+ (*engine)->md5_hlist[new->md5[0] & 0xff] = new; |
|
830 |
+ } |
|
810 | 831 |
} |
811 | 832 |
|
812 | 833 |
if(!line) { |
... | ... |
@@ -1065,6 +1087,9 @@ static int cli_load(const char *filename, struct cl_engine **engine, unsigned in |
1065 | 1065 |
} else if(cli_strbcasestr(filename, ".fp")) { |
1066 | 1066 |
ret = cli_loadhdb(fd, engine, signo, 1, options); |
1067 | 1067 |
|
1068 |
+ } else if(cli_strbcasestr(filename, ".mdb")) { |
|
1069 |
+ ret = cli_loadhdb(fd, engine, signo, 2, options); |
|
1070 |
+ |
|
1068 | 1071 |
} else if(cli_strbcasestr(filename, ".ndb")) { |
1069 | 1072 |
if(options & CL_DB_HWACCEL) |
1070 | 1073 |
skipped = 1; |
... | ... |
@@ -1163,6 +1188,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine **engine, unsigne |
1163 | 1163 |
cli_strbcasestr(dent->d_name, ".db3") || |
1164 | 1164 |
cli_strbcasestr(dent->d_name, ".hdb") || |
1165 | 1165 |
cli_strbcasestr(dent->d_name, ".fp") || |
1166 |
+ cli_strbcasestr(dent->d_name, ".mdb") || |
|
1166 | 1167 |
cli_strbcasestr(dent->d_name, ".ndb") || |
1167 | 1168 |
cli_strbcasestr(dent->d_name, ".sdb") || |
1168 | 1169 |
cli_strbcasestr(dent->d_name, ".zmd") || |
... | ... |
@@ -1283,6 +1309,7 @@ int cl_statinidir(const char *dirname, struct cl_stat *dbstat) |
1283 | 1283 |
cli_strbcasestr(dent->d_name, ".db3") || |
1284 | 1284 |
cli_strbcasestr(dent->d_name, ".hdb") || |
1285 | 1285 |
cli_strbcasestr(dent->d_name, ".fp") || |
1286 |
+ cli_strbcasestr(dent->d_name, ".mdb") || |
|
1286 | 1287 |
cli_strbcasestr(dent->d_name, ".ndb") || |
1287 | 1288 |
cli_strbcasestr(dent->d_name, ".sdb") || |
1288 | 1289 |
cli_strbcasestr(dent->d_name, ".zmd") || |
... | ... |
@@ -1361,6 +1388,7 @@ int cl_statchkdir(const struct cl_stat *dbstat) |
1361 | 1361 |
cli_strbcasestr(dent->d_name, ".db3") || |
1362 | 1362 |
cli_strbcasestr(dent->d_name, ".hdb") || |
1363 | 1363 |
cli_strbcasestr(dent->d_name, ".fp") || |
1364 |
+ cli_strbcasestr(dent->d_name, ".mdb") || |
|
1364 | 1365 |
cli_strbcasestr(dent->d_name, ".ndb") || |
1365 | 1366 |
cli_strbcasestr(dent->d_name, ".sdb") || |
1366 | 1367 |
cli_strbcasestr(dent->d_name, ".zmd") || |
... | ... |
@@ -270,7 +270,7 @@ static int writeinfo(const char *db, const char *header) |
270 | 270 |
int i; |
271 | 271 |
struct stat sb; |
272 | 272 |
char file[32], *md5; |
273 |
- char *extlist[] = { "db", "fp", "hdb", "ndb", "rmd", "zmd", "sdb", NULL }; |
|
273 |
+ char *extlist[] = { "db", "fp", "hdb", "mdb", "ndb", "rmd", "zmd", "sdb", NULL }; |
|
274 | 274 |
|
275 | 275 |
|
276 | 276 |
snprintf(file, sizeof(file), "%s.info", db); |
... | ... |
@@ -345,6 +345,7 @@ static int build(struct optstruct *opt) |
345 | 345 |
|
346 | 346 |
if(stat("main.db", &foo) == -1 && stat("daily.db", &foo) == -1 && |
347 | 347 |
stat("main.hdb", &foo) == -1 && stat("daily.hdb", &foo) == -1 && |
348 |
+ stat("main.mdb", &foo) == -1 && stat("daily.mdb", &foo) == -1 && |
|
348 | 349 |
stat("main.ndb", &foo) == -1 && stat("daily.ndb", &foo) == -1 && |
349 | 350 |
stat("main.sdb", &foo) == -1 && stat("daily.sdb", &foo) == -1 && |
350 | 351 |
stat("main.zmd", &foo) == -1 && stat("daily.zmd", &foo) == -1 && |
... | ... |
@@ -366,6 +367,7 @@ static int build(struct optstruct *opt) |
366 | 366 |
} else { |
367 | 367 |
lines = countlines("main.db") + countlines("daily.db") + |
368 | 368 |
countlines("main.hdb") + countlines("daily.hdb") + |
369 |
+ countlines("main.mdb") + countlines("daily.mdb") + |
|
369 | 370 |
countlines("main.ndb") + countlines("daily.ndb") + |
370 | 371 |
countlines("main.sdb") + countlines("daily.sdb") + |
371 | 372 |
countlines("main.zmd") + countlines("daily.zmd") + |
... | ... |
@@ -481,7 +483,8 @@ static int build(struct optstruct *opt) |
481 | 481 |
"main.ndb", "daily.ndb", "main.sdb", |
482 | 482 |
"daily.sdb", "main.zmd", "daily.zmd", |
483 | 483 |
"main.rmd", "daily.rmd", "main.fp", |
484 |
- "daily.fp", "daily.info", "main.info", |
|
484 |
+ "daily.fp", "main.mdb", "daily.mdb", |
|
485 |
+ "daily.info", "main.info", |
|
485 | 486 |
#ifdef CL_EXPERIMENTAL |
486 | 487 |
/* TODO: add support for main.[wp]db */ |
487 | 488 |
"daily.wdb","daily.pdb", |
... | ... |
@@ -817,6 +820,7 @@ static int listdir(const char *dirname) |
817 | 817 |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && |
818 | 818 |
(cli_strbcasestr(dent->d_name, ".db") || |
819 | 819 |
cli_strbcasestr(dent->d_name, ".hdb") || |
820 |
+ cli_strbcasestr(dent->d_name, ".mdb") || |
|
820 | 821 |
cli_strbcasestr(dent->d_name, ".ndb") || |
821 | 822 |
cli_strbcasestr(dent->d_name, ".sdb") || |
822 | 823 |
cli_strbcasestr(dent->d_name, ".zmd") || |
... | ... |
@@ -944,7 +948,7 @@ static int listdb(const char *filename) |
944 | 944 |
mprintf("%s\n", start); |
945 | 945 |
} |
946 | 946 |
|
947 |
- } else if(cli_strbcasestr(filename, ".hdb")) { /* hash database */ |
|
947 |
+ } else if(cli_strbcasestr(filename, ".hdb") || cli_strbcasestr(filename, ".mdb")) { /* hash database */ |
|
948 | 948 |
|
949 | 949 |
while(fgets(buffer, FILEBUFF, fd)) { |
950 | 950 |
line++; |