Browse code

add W32.Polipos.A detection

git-svn: trunk@1941

Tomasz Kojm authored on 2006/05/02 03:32:13
Showing 2 changed files
... ...
@@ -1,3 +1,8 @@
1
+Mon May  1 20:30:10 CEST 2006 (tk)
2
+----------------------------------
3
+  * libclamav/pe.c: add W32.Polipos.A detection
4
+		    Thanks to aCaB for virus analysis and detection improvements
5
+
1 6
 Mon May  1 19:54:57 CEST 2006 (tk)
2 7
 ----------------------------------
3 8
   * freshclam/manager.c: fix possible buffer overflow
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2004 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  With additions from aCaB <acab@clamav.net>
5 5
  *
... ...
@@ -61,6 +61,11 @@
61 61
 
62 62
 extern short cli_leavetemps_flag;
63 63
 
64
+struct offset_list {
65
+    uint32_t offset;
66
+    struct offset_list *next;
67
+};
68
+
64 69
 static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos, unsigned int *err)
65 70
 {
66 71
 	int i, found = 0;
... ...
@@ -74,7 +79,6 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint
74 74
     }
75 75
 
76 76
     if(!found) {
77
-	cli_dbgmsg("Can't calculate raw address from RVA 0x%x\n", rva);
78 77
 	*err = 1;
79 78
 	return 0;
80 79
     }
... ...
@@ -143,7 +147,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
143 143
 	uint16_t nsections;
144 144
 	uint32_t e_lfanew; /* address of new exe header */
145 145
 	uint32_t ep; /* entry point (raw) */
146
-	uint32_t tmp;
146
+	uint8_t polipos = 0;
147 147
 	time_t timestamp;
148 148
 	struct pe_image_file_hdr file_hdr;
149 149
 	struct pe_image_optional_hdr32 optional_hdr32;
... ...
@@ -151,11 +155,13 @@ int cli_scanpe(int desc, cli_ctx *ctx)
151 151
 	struct pe_image_section_hdr *section_hdr;
152 152
 	struct stat sb;
153 153
 	char sname[9], buff[4096], *tempfile;
154
+	unsigned char *ubuff;
155
+	ssize_t bytes;
154 156
 	unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0;
155 157
 	unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0;
156 158
 	int (*upxfn)(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL;
157 159
 	char *src = NULL, *dest = NULL;
158
-	int ndesc, ret;
160
+	int ndesc, ret = CL_CLEAN;
159 161
 	size_t fsize;
160 162
 
161 163
 
... ...
@@ -536,6 +542,14 @@ int cli_scanpe(int desc, cli_ctx *ctx)
536 536
 		max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
537 537
 	}
538 538
 
539
+	if(SCAN_ALGO && !strlen(sname)) {
540
+	    if(EC32(section_hdr[i].VirtualSize) > 40000 && EC32(section_hdr[i].VirtualSize) < 70000) {
541
+		if(EC32(section_hdr[i].Characteristics) == 0xe0000060) {
542
+		    polipos = i;
543
+		}
544
+	    }
545
+	}
546
+
539 547
     }
540 548
 
541 549
     if(pe_plus)
... ...
@@ -609,6 +623,98 @@ int cli_scanpe(int desc, cli_ctx *ctx)
609 609
 	}
610 610
     }
611 611
 
612
+    /* W32.Polipos.A */
613
+   if(polipos && !dll && !pe_plus && nsections > 2 && nsections < 13 && e_lfanew <= 0x800 && (EC16(optional_hdr32.Subsystem) == 2 || EC16(optional_hdr32.Subsystem) == 3) && EC16(file_hdr.Machine) == 0x14c && optional_hdr32.SizeOfStackReserve >= 0x80000) {
614
+		uint32_t remaining = EC32(section_hdr[0].SizeOfRawData);
615
+		uint32_t chunk = sizeof(buff);
616
+		uint32_t val, shift, raddr, curroff, total = 0;
617
+		const char *jpt;
618
+		struct offset_list *offlist = NULL, *offnode;
619
+
620
+
621
+	cli_dbgmsg("Detected W32.Polipos.A characteristics\n");
622
+
623
+	if(remaining < chunk)
624
+	    chunk = remaining;
625
+
626
+	lseek(desc, EC32(section_hdr[0].PointerToRawData), SEEK_SET);
627
+	while((bytes = cli_readn(desc, buff, chunk)) > 0) {
628
+	    shift = 0;
629
+	    while(bytes - 5 > shift) {
630
+		jpt = buff + shift;
631
+		if(*jpt!='\xe9' && *jpt!='\xe8') {
632
+		    shift++;
633
+		    continue;
634
+		}
635
+		val = cli_readint32(jpt + 1);
636
+		val += 5 + EC32(section_hdr[0].VirtualAddress) + total + shift;
637
+		raddr = cli_rawaddr(val, section_hdr, nsections, &err);
638
+
639
+		if(!err && (raddr >= EC32(section_hdr[polipos].PointerToRawData) && raddr < EC32(section_hdr[polipos].PointerToRawData) + EC32(section_hdr[polipos].SizeOfRawData)) && (!offlist || (raddr != offlist->offset))) {
640
+		    offnode = (struct offset_list *) cli_malloc(sizeof(struct offset_list));
641
+		    if(!offnode) {
642
+			free(section_hdr);
643
+			while(offlist) {
644
+			    offnode = offlist;
645
+			    offlist = offlist->next;
646
+			    free(offnode);
647
+			}
648
+			return CL_EMEM;
649
+		    }
650
+		    offnode->offset = raddr;
651
+		    offnode->next = offlist;
652
+		    offlist = offnode;
653
+		}
654
+
655
+		shift++;
656
+	    }
657
+
658
+	    if(remaining < chunk) {
659
+		chunk = remaining;
660
+	    } else {
661
+		remaining -= bytes;
662
+		if(remaining < chunk) {
663
+		    chunk = remaining;
664
+		}
665
+	    }
666
+
667
+	    if(!remaining)
668
+		break;
669
+
670
+	    total += bytes;
671
+	}
672
+
673
+	offnode = offlist;
674
+	while(offnode) {
675
+	    cli_dbgmsg("Polipos: Checking offset 0x%x (%u)", offnode->offset, offnode->offset);
676
+	    lseek(desc, offnode->offset, SEEK_SET);
677
+	    if(cli_readn(desc, buff, 9) == 9) {
678
+		ubuff = (unsigned char *) buff;
679
+		if(ubuff[0] == 0x55 && ubuff[1] == 0x8b && ubuff[2] == 0xec &&
680
+		   ((ubuff[3] == 0x83 && ubuff[4] == 0xec && ubuff[6] == 0x60) ||  ubuff[3] == 0x60 ||
681
+		     (ubuff[3] == 0x81 && ubuff[4] == 0xec && ubuff[7] == 0x00 && ubuff[8] == 0x00))) {
682
+		    ret = CL_VIRUS;
683
+		    *ctx->virname = "W32.Polipos.A";
684
+		    break;
685
+		}
686
+	    }
687
+
688
+	    offnode = offnode->next;
689
+	}
690
+
691
+	while(offlist) {
692
+	    offnode = offlist;
693
+	    offlist = offlist->next;
694
+	    free(offnode);
695
+	}
696
+
697
+	if(ret == CL_VIRUS) {
698
+	    free(section_hdr);
699
+	    return CL_VIRUS;
700
+	}
701
+    }
702
+
703
+
612 704
     if(broken) {
613 705
 	free(section_hdr);
614 706
 	return CL_CLEAN;