Browse code

add support for matching single bytes anchored to sub-signatures; bump f-level

git-svn: trunk@3588

Tomasz Kojm authored on 2008/02/06 21:26:16
Showing 4 changed files
... ...
@@ -1,3 +1,9 @@
1
+Wed Feb  6 13:12:24 CET 2008 (tk)
2
+---------------------------------
3
+  * libclamav/matcher-ac.[ch]: add support for matching single bytes anchored
4
+			       to sub-signatures (see bb#776 for details)
5
+  * libclamav/others.h: bump f-level
6
+
1 7
 Wed Feb  6 14:07:45 EET 2008 (edwin)
2 8
 ------------------------------------
3 9
   * libclamav/regex_list.c: fix -pedantic warning.
... ...
@@ -1,4 +1,7 @@
1 1
 /*
2
+ *  Copyright (C) 2007 - 2008 Sourcefire, Inc.
3
+ *  Author: Tomasz Kojm <tkojm@clamav.net>
4
+ *
2 5
  *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm@clamav.net>
3 6
  *
4 7
  *  This program is free software; you can redistribute it and/or modify
... ...
@@ -341,11 +344,7 @@ void cli_ac_free(struct cli_matcher *root)
341 341
 
342 342
     for(i = 0; i < root->ac_patterns; i++) {
343 343
 	patt = root->ac_pattable[i];
344
-
345
-	if(patt->prefix)
346
-	    free(patt->prefix);
347
-	else
348
-	    free(patt->pattern);
344
+	patt->prefix ? free(patt->prefix) : free(patt->pattern);
349 345
 	free(patt->virname);
350 346
 	if(patt->offset)
351 347
 	    free(patt->offset);
... ...
@@ -383,19 +382,19 @@ void cli_ac_free(struct cli_matcher *root)
383 383
     switch(wc = p & CLI_MATCH_WILDCARD) {				\
384 384
 	case CLI_MATCH_CHAR:						\
385 385
 	    if((unsigned char) p != b)					\
386
-		return 0;						\
386
+		match = 0;						\
387 387
 	    break;							\
388 388
 									\
389 389
 	case CLI_MATCH_IGNORE:						\
390 390
 	    break;							\
391 391
 									\
392 392
 	case CLI_MATCH_ALTERNATIVE:					\
393
-	    found = 0;							\
393
+	    match = 0;							\
394 394
 	    alt = pattern->alttable[altcnt];				\
395 395
 	    if(alt->chmode) {						\
396 396
 		for(j = 0; j < alt->num; j++) {				\
397 397
 		    if(alt->str[j] == b) {				\
398
-			found = 1;					\
398
+			match = 1;					\
399 399
 			break;						\
400 400
 		    }							\
401 401
 		}							\
... ...
@@ -403,7 +402,7 @@ void cli_ac_free(struct cli_matcher *root)
403 403
 		while(alt) {						\
404 404
 		    if(bp + alt->len <= length) {			\
405 405
 			if(!memcmp(&buffer[bp], alt->str, alt->len)) {	\
406
-			    found = 1;					\
406
+			    match = 1;					\
407 407
 			    bp += alt->len - 1;				\
408 408
 			    break;					\
409 409
 			}						\
... ...
@@ -411,31 +410,28 @@ void cli_ac_free(struct cli_matcher *root)
411 411
 		    alt = alt->next;					\
412 412
 		}							\
413 413
 	    }								\
414
-	    if(!found)							\
415
-		return 0;						\
416 414
 	    altcnt++;							\
417 415
 	    break;							\
418 416
 									\
419 417
 	case CLI_MATCH_NIBBLE_HIGH:					\
420 418
 	    if((unsigned char) (p & 0x00f0) != (b & 0xf0))		\
421
-		return 0;						\
419
+		match = 0;						\
422 420
 	    break;							\
423 421
 									\
424 422
 	case CLI_MATCH_NIBBLE_LOW:					\
425 423
 	    if((unsigned char) (p & 0x000f) != (b & 0x0f))		\
426
-		return 0;						\
424
+		match = 0;						\
427 425
 	    break;							\
428 426
 									\
429 427
 	default:							\
430 428
 	    cli_errmsg("ac_findmatch: Unknown wildcard 0x%x\n", wc);	\
431
-	    return 0;							\
429
+	    match = 0;							\
432 430
     }
433 431
 
434 432
 inline static int ac_findmatch(const unsigned char *buffer, uint32_t offset, uint32_t length, const struct cli_ac_patt *pattern, uint32_t *end)
435 433
 {
436
-	uint32_t bp;
434
+	uint32_t bp, match;
437 435
 	uint16_t wc, i, j, altcnt = pattern->alt_pattern;
438
-	uint8_t found;
439 436
 	struct cli_ac_alt *alt;
440 437
 
441 438
 
... ...
@@ -444,22 +440,61 @@ inline static int ac_findmatch(const unsigned char *buffer, uint32_t offset, uin
444 444
 
445 445
     bp = offset + pattern->depth;
446 446
 
447
+    match = 1;
447 448
     for(i = pattern->depth; i < pattern->length && bp < length; i++) {
448 449
 	AC_MATCH_CHAR(pattern->pattern[i],buffer[bp]);
450
+	if(!match)
451
+	    return 0;
449 452
 	bp++;
450 453
     }
451 454
     *end = bp;
452 455
 
456
+    if(!(pattern->ch[1] & CLI_MATCH_IGNORE)) {
457
+	bp += pattern->ch_mindist[1];
458
+	for(i = pattern->ch_mindist[1]; i <= pattern->ch_maxdist[1]; i++) {
459
+	    if(bp >= length)
460
+		return 0;
461
+	    match = 1;
462
+	    AC_MATCH_CHAR(pattern->ch[1],buffer[bp]);
463
+	    if(match)
464
+		break;
465
+	    bp++;
466
+	}
467
+	if(!match)
468
+	    return 0;
469
+    }
470
+
453 471
     if(pattern->prefix) {
454 472
 	altcnt = 0;
455 473
 	bp = offset - pattern->prefix_length;
456
-
474
+	match = 1;
457 475
 	for(i = 0; i < pattern->prefix_length; i++) {
458 476
 	    AC_MATCH_CHAR(pattern->prefix[i],buffer[bp]);
477
+	    if(!match)
478
+		return 0;
459 479
 	    bp++;
460 480
 	}
461 481
     }
462 482
 
483
+    if(!(pattern->ch[0] & CLI_MATCH_IGNORE)) {
484
+	bp = offset - pattern->prefix_length;
485
+	if(pattern->ch_mindist[0] + 1 > bp)
486
+	    return 0;
487
+	bp -= pattern->ch_mindist[0] + 1;
488
+	for(i = pattern->ch_mindist[0]; i <= pattern->ch_maxdist[0]; i++) {
489
+	    match = 1;
490
+	    AC_MATCH_CHAR(pattern->ch[0],buffer[bp]);
491
+	    if(match)
492
+		break;
493
+	    if(!bp)
494
+		return 0;
495
+	    else
496
+		bp--;
497
+	}
498
+	if(!match)
499
+	    return 0;
500
+    }
501
+
463 502
     return 1;
464 503
 }
465 504
 
... ...
@@ -707,8 +742,8 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
707 707
 int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target)
708 708
 {
709 709
 	struct cli_ac_patt *new;
710
-	char *pt, *hex = NULL;
711
-	uint16_t i, j, ppos = 0, pend;
710
+	char *pt, *pt2, *hex = NULL, *hexcpy = NULL;
711
+	uint16_t i, j, ppos = 0, pend, *dec;
712 712
 	uint8_t wprefix = 0, zprefix = 1, namelen, plen = 0;
713 713
 	struct cli_ac_alt *newalt, *altpt, **newtable;
714 714
 	int ret, error = CL_SUCCESS;
... ...
@@ -727,11 +762,94 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
727 727
     new->mindist = mindist;
728 728
     new->maxdist = maxdist;
729 729
     new->target = target;
730
+    new->ch[0] |= CLI_MATCH_IGNORE;
731
+    new->ch[1] |= CLI_MATCH_IGNORE;
732
+
733
+    if(strchr(hexsig, '[')) {
734
+	if(!(hexcpy = cli_strdup(hexsig))) {
735
+	    free(new);
736
+	    return CL_EMEM;
737
+	}
738
+
739
+	hex = hexcpy;
740
+	for(i = 0; i < 2; i++) {
741
+		unsigned int n1, n2;
742
+
743
+	    if(!(pt = strchr(hex, '[')))
744
+		break;
745
+	    *pt++ = 0;
746
+
747
+	    if(!(pt2 = strchr(pt, ']'))) {
748
+		cli_dbgmsg("cli_ac_addsig: missing closing square bracket\n");
749
+		error = CL_EMALFDB;
750
+		break;
751
+	    }
752
+	    *pt2++ = 0;
753
+
754
+            if(sscanf(pt, "%u-%u", &n1, &n2) != 2) {
755
+		cli_dbgmsg("cli_ac_addsig: incorrect range inside square brackets\n");
756
+		error = CL_EMALFDB;
757
+		break;
758
+	    }
759
+
760
+	    if((n1 > n2) || (n2 > AC_CH_MAXDIST)) {
761
+		cli_dbgmsg("cli_ac_addsig: incorrect range inside square brackets\n");
762
+		error = CL_EMALFDB;
763
+		break;
764
+	    }
765
+
766
+	    if(strlen(hex) == 2) {
767
+		if(i) {
768
+		    error = CL_EMALFDB;
769
+		    break;
770
+		}
771
+		dec = cli_hex2ui(hex);
772
+		if(!dec) {
773
+		    error = CL_EMALFDB;
774
+		    break;
775
+		}
776
+		new->ch[i] = *dec;
777
+		free(dec);
778
+		new->ch_mindist[i] = n1;
779
+		new->ch_maxdist[i] = n2;
780
+		hex = pt2;
781
+	    } else if(strlen(pt2) == 2) {
782
+		i = 1;
783
+		dec = cli_hex2ui(pt2);
784
+		if(!dec) {
785
+		    error = CL_EMALFDB;
786
+		    break;
787
+		}
788
+		new->ch[i] = *dec;
789
+		free(dec);
790
+		new->ch_mindist[i] = n1;
791
+		new->ch_maxdist[i] = n2;
792
+	    } else {
793
+		error = CL_EMALFDB;
794
+		break;
795
+	    }
796
+	}
797
+
798
+	if(error) {
799
+	    free(hexcpy);
800
+	    free(new);
801
+	    return error;
802
+	}
803
+
804
+	hex = cli_strdup(hex);
805
+	free(hexcpy);
806
+	if(!hex) {
807
+	    free(new);
808
+	    return CL_EMEM;
809
+	}
810
+    }
730 811
 
731 812
     if(strchr(hexsig, '(')) {
732
-	    char *hexcpy, *hexnew, *start, *h, *c;
813
+	    char *hexnew, *start, *h, *c;
733 814
 
734
-	if(!(hexcpy = cli_strdup(hexsig))) {
815
+	if(hex) {
816
+	    hexcpy = hex;
817
+	} else if(!(hexcpy = cli_strdup(hexsig))) {
735 818
 	    free(new);
736 819
 	    return CL_EMEM;
737 820
 	}
... ...
@@ -860,17 +978,15 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
860 860
 	}
861 861
     }
862 862
 
863
-    if((new->pattern = cli_hex2ui(new->alt ? hex : hexsig)) == NULL) {
864
-	if(new->alt) {
865
-	    free(hex);
863
+    if((new->pattern = cli_hex2ui(hex ? hex : hexsig)) == NULL) {
864
+	if(new->alt)
866 865
 	    ac_free_alt(new);
867
-	}
866
+	free(hex);
868 867
 	free(new);
869 868
 	return CL_EMALFDB;
870 869
     }
871
-    new->length = strlen(new->alt ? hex : hexsig) / 2;
872
-    if(new->alt)
873
-	free(hex);
870
+    new->length = strlen(hex ? hex : hexsig) / 2;
871
+    free(hex);
874 872
 
875 873
     for(i = 0; i < root->ac_maxdepth && i < new->length; i++) {
876 874
 	if(new->pattern[i] & CLI_MATCH_WILDCARD) {
... ...
@@ -928,20 +1044,14 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
928 928
 
929 929
     if(!namelen) {
930 930
 	cli_errmsg("cli_ac_addsig: No virus name\n");
931
-	if(new->prefix)
932
-	    free(new->prefix);
933
-	else
934
-	    free(new->pattern);
931
+	new->prefix ? free(new->prefix) : free(new->pattern);
935 932
 	ac_free_alt(new);
936 933
 	free(new);
937 934
 	return CL_EMALFDB;
938 935
     }
939 936
 
940 937
     if((new->virname = cli_calloc(namelen + 1, sizeof(char))) == NULL) {
941
-	if(new->prefix)
942
-	    free(new->prefix);
943
-	else
944
-	    free(new->pattern);
938
+	new->prefix ? free(new->prefix) : free(new->pattern);
945 939
 	ac_free_alt(new);
946 940
 	free(new);
947 941
 	return CL_EMEM;
... ...
@@ -951,10 +1061,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
951 951
     if(offset) {
952 952
 	new->offset = cli_strdup(offset);
953 953
 	if(!new->offset) {
954
-	    if(new->prefix)
955
-		free(new->prefix);
956
-	    else
957
-		free(new->pattern);
954
+	    new->prefix ? free(new->prefix) : free(new->pattern);
958 955
 	    ac_free_alt(new);
959 956
 	    free(new->virname);
960 957
 	    free(new);
... ...
@@ -963,10 +1070,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
963 963
     }
964 964
 
965 965
     if((ret = cli_ac_addpatt(root, new))) {
966
-	if(new->prefix)
967
-	    free(new->prefix);
968
-	else
969
-	    free(new->pattern);
966
+	new->prefix ? free(new->prefix) : free(new->pattern);
970 967
 	free(new->virname);
971 968
 	ac_free_alt(new);
972 969
 	if(new->offset)
... ...
@@ -1,4 +1,7 @@
1 1
 /*
2
+ *  Copyright (C) 2007 - 2008 Sourcefire, Inc.
3
+ *  Author: Tomasz Kojm <tkojm@clamav.net>
4
+ *
2 5
  *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm@clamav.net>
3 6
  *
4 7
  *  This program is free software; you can redistribute it and/or modify
... ...
@@ -27,6 +30,7 @@
27 27
 #define AC_DEFAULT_MIN_DEPTH 2
28 28
 #define AC_DEFAULT_MAX_DEPTH 3
29 29
 #define AC_DEFAULT_TRACKLEN 8
30
+#define AC_CH_MAXDIST 32
30 31
 extern uint8_t cli_ac_mindepth, cli_ac_maxdepth;
31 32
 
32 33
 struct cli_ac_data {
... ...
@@ -46,6 +50,9 @@ struct cli_ac_patt {
46 46
     uint32_t mindist, maxdist;
47 47
     uint32_t sigid;
48 48
     char *virname, *offset;
49
+    uint16_t ch[2];
50
+    uint16_t ch_mindist[2];
51
+    uint16_t ch_maxdist[2];
49 52
     uint16_t parts, partno, alt, alt_pattern;
50 53
     struct cli_ac_alt **alttable;
51 54
     struct cli_ac_patt *next, *next_same;
... ...
@@ -88,7 +88,7 @@ static pthread_mutex_t cli_ctime_mutex = PTHREAD_MUTEX_INITIALIZER;
88 88
 #define       P_tmpdir        "C:\\WINDOWS\\TEMP"
89 89
 #endif
90 90
 
91
-#define CL_FLEVEL 25 /* don't touch it */
91
+#define CL_FLEVEL 27 /* don't touch it */
92 92
 
93 93
 uint8_t cli_debug_flag = 0, cli_leavetemps_flag = 0;
94 94