Browse code

use cached metadata in icon parser, add icon unit tests

aCaB authored on 2010/07/30 22:54:15
Showing 9 changed files
... ...
@@ -1,3 +1,9 @@
1
+Fri Jul 30 15:51:06 CEST 2010 (acab)
2
+------------------------------------
3
+ * libclamav, unit_tests: use cached PE metadata when matching icons (better fix for 
4
+	      bb#2064, partially reverts d932a6d)
5
+	      add some unit tests for ign2, ldb, idb
6
+
1 7
 Fri Jul 30 15:15:35 CEST 2010 (tk)
2 8
 ----------------------------------
3 9
  * freshclam: fix parsing of extended log entries
... ...
@@ -50,6 +50,10 @@ struct cli_exe_info {
50 50
     uint32_t ep;
51 51
     /** Number of sections*/
52 52
     uint16_t nsections;
53
+    /** Resrources RVA - PE ONLY */
54
+    uint32_t res_addr;
55
+    /** Address size - PE ONLY */
56
+    uint32_t hdr_size;
53 57
     /** Hashset for versioninfo matching */
54 58
     struct cli_hashset *vinfo;
55 59
 };
... ...
@@ -429,16 +429,25 @@ int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
429 429
     return CL_VIRUS;
430 430
 }
431 431
 
432
-static int matchicon(cli_ctx *ctx, const char *grp1, const char *grp2)
432
+static int matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
433 433
 {
434 434
 	icon_groupset iconset;
435 435
 
436
+    if(!ctx ||
437
+       !ctx->engine ||
438
+       !ctx->engine->iconcheck ||
439
+       !ctx->engine->iconcheck->group_counts[0] ||
440
+       !ctx->engine->iconcheck->group_counts[1] ||
441
+       !exeinfo->res_addr
442
+    ) return CL_CLEAN;
443
+
436 444
     cli_icongroupset_init(&iconset);
437 445
     cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
438 446
     cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
439
-    return cli_match_icon(&iconset, ctx);
447
+    return cli_scanicon(&iconset, exeinfo->res_addr, ctx, exeinfo->section, exeinfo->nsections, exeinfo->hdr_size);
440 448
 }
441 449
 
450
+
442 451
 int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres)
443 452
 {
444 453
     int ret = CL_EMEM, empty;
... ...
@@ -483,7 +492,7 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac
483 483
 	    if(root->ac_lsigtable[i]->tdb.icongrp1 || root->ac_lsigtable[i]->tdb.icongrp2) {
484 484
 		if(!target_info || target_info->status != 1)
485 485
 		    continue;
486
-		if(matchicon(ctx, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
486
+		if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
487 487
 		    if(ctx->virname)
488 488
 			*ctx->virname = root->ac_lsigtable[i]->virname;
489 489
 		    return CL_VIRUS;
... ...
@@ -58,7 +58,6 @@
58 58
 #include "disasm.h"
59 59
 #include "special.h"
60 60
 #include "ishield.h"
61
-#include "pe_icons.h"
62 61
 
63 62
 #define DCONF ctx->dconf->pe
64 63
 
... ...
@@ -501,7 +500,7 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc
501 501
     fmap_unneed_ptr(map, oentry, entries*8);
502 502
 }
503 503
 
504
-int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
504
+int cli_scanpe(cli_ctx *ctx)
505 505
 {
506 506
 	uint16_t e_magic; /* DOS signature ("MZ") */
507 507
 	uint16_t nsections;
... ...
@@ -1002,7 +1001,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
1002 1002
 
1003 1003
 	    /* check MD5 section sigs */
1004 1004
 	    md5_sect = ctx->engine->md5_mdb;
1005
-	    if((DCONF & PE_CONF_MD5SECT) && md5_sect && !iconset) {
1005
+	    if((DCONF & PE_CONF_MD5SECT) && md5_sect) {
1006 1006
 		found = 0;
1007 1007
 		for(j = 0; j < md5_sect->soff_len && md5_sect->soff[j] <= exe_sections[i].rsz; j++) {
1008 1008
 		    if(md5_sect->soff[j] == exe_sections[i].rsz) {
... ...
@@ -1078,15 +1077,6 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
1078 1078
 
1079 1079
     cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
1080 1080
 
1081
-    if(iconset){
1082
-	if(!dll && dirs[2].Size && cli_scanicon(iconset, EC32(dirs[2].VirtualAddress), ctx, exe_sections, nsections, hdr_size) == CL_VIRUS) {
1083
-	    free(exe_sections);
1084
-	    return CL_VIRUS;
1085
-	}
1086
-	free(exe_sections);
1087
-	return CL_CLEAN;
1088
-    }
1089
-
1090 1081
     if(pe_plus) { /* Do not continue for PE32+ files */
1091 1082
 	free(exe_sections);
1092 1083
 	return CL_CLEAN;
... ...
@@ -2383,7 +2373,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
2383 2383
     valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
2384 2384
     falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
2385 2385
 
2386
-    hdr_size = PESALIGN(hdr_size, valign);
2386
+    peinfo->hdr_size = hdr_size = PESALIGN(hdr_size, valign);
2387 2387
 
2388 2388
     peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
2389 2389
 
... ...
@@ -2447,6 +2437,11 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
2447 2447
 	return -1;
2448 2448
     }
2449 2449
 
2450
+    if(EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size)
2451
+	peinfo->res_addr = 0;
2452
+    else
2453
+	peinfo->res_addr = EC32(dirs[2].VirtualAddress);
2454
+
2450 2455
     while(dirs[2].Size && peinfo->vinfo) {
2451 2456
 	struct vinfo_list vlist;
2452 2457
 	uint8_t *vptr, *baseptr;
... ...
@@ -152,7 +152,7 @@ struct cli_pe_hook_data {
152 152
   uint32_t hdr_size;/**< internally needed by rawaddr */
153 153
 };
154 154
 
155
-int cli_scanpe(cli_ctx *ctx, icon_groupset *set);
155
+int cli_scanpe(cli_ctx *ctx);
156 156
 
157 157
 int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo);
158 158
 
... ...
@@ -1503,20 +1503,6 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
1503 1503
     return CL_SUCCESS;
1504 1504
 }
1505 1505
 
1506
-
1507
-int cli_match_icon(icon_groupset *set, cli_ctx *ctx) {
1508
-    if(!ctx || !ctx->engine || !ctx->engine->iconcheck || !ctx->engine->iconcheck->group_counts[0] || !ctx->engine->iconcheck->group_counts[1])
1509
-	return CL_CLEAN;
1510
-    else {
1511
-	unsigned int ctx_opts = ctx->options;
1512
-	int ret;
1513
-	ctx->options &= ~CL_SCAN_BLOCKBROKEN;
1514
-	ret = cli_scanpe(ctx, set);
1515
-	ctx->options = ctx_opts;
1516
-	return ret;
1517
-    }
1518
-}
1519
-
1520 1506
 void cli_icongroupset_add(const char *groupname, icon_groupset *set, unsigned int type, cli_ctx *ctx) {
1521 1507
     struct icon_matcher *matcher;
1522 1508
     unsigned int i, j;
... ...
@@ -23,7 +23,6 @@
23 23
 #include "pe.h"
24 24
 
25 25
 int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size);
26
-int cli_match_icon(icon_groupset *set, cli_ctx *ctx);
27 26
 
28 27
 void cli_icongroupset_add(const char *groupname, icon_groupset *set, unsigned int type, cli_ctx *ctx);
29 28
 static inline void cli_icongroupset_init(icon_groupset *set) {
... ...
@@ -2356,7 +2356,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
2356 2356
 	 */
2357 2357
 	case CL_TYPE_MSEXE:
2358 2358
 	    if(SCAN_PE && ctx->dconf->pe)
2359
-		ret = cli_scanpe(ctx, NULL);
2359
+		ret = cli_scanpe(ctx);
2360 2360
 	    break;
2361 2361
 	default:
2362 2362
 	    break;
... ...
@@ -171,6 +171,29 @@ EOF
171 171
 
172 172
     grep "phish-test-ssl: Heuristics.Phishing.Email.SSL-Spoof FOUND" clamscan3.log >/dev/null || die "phish-test1 failed";
173 173
     grep "phish-test-cloak: Heuristics.Phishing.Email.Cloaked.Null FOUND" clamscan3.log >/dev/null || die "phish-test2 failed";
174
+
175
+    cat <<EOF >test-db/test.ign2
176
+ClamAV-Test-File
177
+EOF
178
+    cat <<EOF >test-db/test.idb
179
+EA0X-32x32x8:ea0x-grp1:ea0x-grp2:2046f030a42a07153f4120a0031600007000005e1617ef0000d21100cb090674150f880313970b0e7716116d01136216022500002f0a173700081a004a0e
180
+IScab-16x16x8:iscab-grp1:iscab-grp2:107b3000168306015c20a0105b07060be0a0b11c050bea0706cb0a0bbb060b6f00017c06018301068109086b03046705081b000a270a002a000039002b17
181
+EOF
182
+    cat <<EOF >test-db/test.ldb
183
+ClamAV-Test-Icon-EA0X;Engine:52-1000,Target:1,IconGroup1:ea0x-grp1,IconGroup2:*;(0);0:4d5a
184
+ClamAV-Test-Icon-IScab;Engine:52-1000,Target:1,IconGroup2:iscab-grp2;(0);0:4d5a
185
+EOF
186
+    if test_run 1 $CLAMSCAN --quiet -dtest-db $TESTFILES --log=clamscan4.log; then
187
+	scan_failed clamscan4.log "clamscan didn't detect icons correctly"
188
+    fi
189
+    grep "clam.ea05.exe: ClamAV-Test-Icon-EA0X.UNOFFICIAL FOUND" clamscan4.log || die "icon-test1 failed"
190
+    grep "clam.ea06.exe: ClamAV-Test-Icon-EA0X.UNOFFICIAL FOUND" clamscan4.log || die "icon-test2 failed"
191
+    grep "clam_IScab_ext.exe: ClamAV-Test-Icon-IScab.UNOFFICIAL FOUND" clamscan4.log || die "icon-test3 failed"
192
+    grep "clam_IScab_int.exe: ClamAV-Test-Icon-IScab.UNOFFICIAL FOUND" clamscan4.log || die "icon-test4 failed"
193
+    NINFECTED=`grep "Infected files" clamscan4.log | cut -f2 -d: | sed -e 's/ //g'`
194
+    if test "x$NINFECTED" -ne x4; then
195
+	scan_failed clamscan4.log "clamscan has detected spurious icons or whitlisting was not applier properly"
196
+    fi
174 197
     test_end $1
175 198
 }
176 199