Browse code

add support for FSG 1.33

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@750 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2004/08/14 19:56:23
Showing 5 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Aug 14 12:50:07 CEST 2004 (tk)
2
+----------------------------------
3
+  * libclamav: add support for FSG 1.33 (aCaB)
4
+
1 5
 Fri Aug 13 11:22:02 BST 2004 (njh)
2 6
 ----------------------------------
3 7
   * clamav-milter:	Single thread through the tcpwrappers code, thanks to
... ...
@@ -23,6 +23,7 @@
23 23
 ** 02/08/2k4 - Done coding
24 24
 ** 03/08/2k4 - Cleaning and securing
25 25
 ** 04/08/2k4 - Done porting
26
+** 07/08/2k4 - Started adding support for 1.33
26 27
 */
27 28
 
28 29
 /*
... ...
@@ -47,6 +48,20 @@
47 47
 #include "rebuildpe.h"
48 48
 #include "others.h"
49 49
 
50
+#if WORDS_BIGENDIAN == 0
51
+#define EC16(v)	(v)
52
+#define EC32(v) (v)
53
+#else
54
+static inline uint16_t EC16(uint16_t v)
55
+{
56
+    return ((v >> 8) + (v << 8));
57
+}
58
+
59
+static inline uint32_t EC32(uint32_t v)
60
+{
61
+    return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
62
+}
63
+#endif
50 64
 
51 65
 static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
52 66
 {
... ...
@@ -65,7 +80,7 @@ static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
65 65
   return (olddl>>7)&1;
66 66
 }
67 67
 
68
-int unfsg(char *source, char *dest, int ssize, int dsize) {
68
+static int unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc, char **enddst) {
69 69
   uint8_t mydl=0x80;
70 70
   uint32_t backbytes, backsize, oldback;
71 71
   char *csrc = source, *cdst = dest;
... ...
@@ -186,5 +201,75 @@ int unfsg(char *source, char *dest, int ssize, int dsize) {
186 186
       lostbit=1;
187 187
     }
188 188
   }
189
+
190
+  *endsrc = csrc;
191
+  *enddst = cdst;
189 192
   return 0;
190 193
 }
194
+
195
+int unfsg_200(char *source, char *dest, int ssize, int dsize) {
196
+  char *fake;
197
+
198
+  return unfsg(source, dest, ssize, dsize, &fake, &fake);
199
+}
200
+
201
+int unfsg_133(char *source, char *dest, int ssize, int dsize, struct SECTION *sections, int sectcount, uint32_t base, uint32_t ep, int file) {
202
+  char *tsrc=source, *tdst=dest;
203
+  int i, upd=1, offs=0, lastsz=dsize;
204
+
205
+  for (i = 0 ; i <= sectcount ; i++) {
206
+    char *startd=tdst;
207
+    if ( unfsg(tsrc, tdst, tsrc - source + ssize, tdst - dest + dsize, &tsrc, &tdst) == -1 )
208
+      return -1;
209
+
210
+    /* RVA has been filled already in pe.c */
211
+    sections[i].raw=offs;
212
+    sections[i].rsz=tdst-startd;
213
+    /*    cli_dbgmsg("Unpacked section %d @%x size %x Vsize =%x \n", i, offs, tdst-startd, dsize - (startd - dest)); */
214
+    offs+=tdst-startd;
215
+  }
216
+
217
+  /* Sort out the sections */
218
+  while ( upd ) {
219
+    upd = 0;
220
+    for (i = 0; i < sectcount  ; i++) {
221
+      uint32_t trva,trsz,traw;
222
+      
223
+      if ( sections[i].rva < sections[i+1].rva )
224
+	continue;
225
+      trva = sections[i].rva;
226
+      traw = sections[i].raw;
227
+      trsz = sections[i].rsz;
228
+      sections[i].rva = sections[i+1].rva;
229
+      sections[i].rsz = sections[i+1].rsz;
230
+      sections[i].raw = sections[i+1].raw;
231
+      sections[i+1].rva = trva;
232
+      sections[i+1].raw = traw;
233
+      sections[i+1].rsz = trsz;
234
+      upd = 1;
235
+    }
236
+  }
237
+
238
+  /* Cure Vsizes and debugspam */
239
+  for (i = 0; i <= sectcount ; i++) {
240
+    if ( i != sectcount ) {
241
+      sections[i].vsz = sections[i+1].rva - sections[i].rva;
242
+      lastsz-= sections[i+1].rva - sections[i].rva;
243
+    }
244
+    else 
245
+      sections[i].vsz = lastsz;
246
+
247
+    cli_dbgmsg("FSG: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:% x\n", i, sections[i].rva, sections[i].vsz, sections[i].raw, sections[i].rsz);
248
+  }
249
+
250
+  if ( (tsrc = rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0)) ) {
251
+    write(file, tsrc, 0x148+0x80+0x28*(sectcount+1)+offs);
252
+    free(tsrc);
253
+  } else {
254
+    free(tsrc);
255
+    cli_dbgmsg("FSG: Rebuilding failed\n");
256
+    return 0;
257
+  }
258
+
259
+  return 1;
260
+}
... ...
@@ -20,9 +20,12 @@
20 20
 #define __FSG_H
21 21
 
22 22
 #include "cltypes.h"
23
-#include "pe.h"
23
+#include "rebuildpe.h"
24 24
 
25
-int unfsg(char *, char *, int, int);
25
+int unfsg_200(char *, char *, int, int);
26
+int unfsg_133(char *, char *, int , int, struct SECTION *, int, uint32_t, uint32_t, int);
26 27
 
27 28
 #endif
28 29
 
30
+
31
+
... ...
@@ -1,6 +1,8 @@
1 1
 /*
2 2
  *  Copyright (C) 2004 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4
+ *  With additions from aCaB <acab@clamav.net>
5
+ *
4 6
  *  This program is free software; you can redistribute it and/or modify
5 7
  *  it under the terms of the GNU General Public License as published by
6 8
  *  the Free Software Foundation; either version 2 of the License, or
... ...
@@ -37,6 +39,7 @@
37 37
 #include "petite.h"
38 38
 #include "fsg.h"
39 39
 #include "scanners.h"
40
+#include "rebuildpe.h"
40 41
 
41 42
 #define IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
42 43
 #define IMAGE_DOS_SIGNATURE_OLD	    0x4d5a          /* ZM */
... ...
@@ -420,15 +423,15 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
420 420
 	    return CL_EIO;
421 421
 	}
422 422
 
423
-	if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
423
+        if(read(desc, buff, 168) != 168) {
424 424
 	    cli_dbgmsg("UPX/FSG: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
425 425
             free(section_hdr);
426 426
 	    return CL_EIO;
427 427
 	}
428 428
 
429
-	if(buff[0]=='\x87' && buff [1]=='\x25') {
429
+	if(buff[0] == '\x87' && buff[1] == '\x25') {
430 430
 
431
-	    /* FSG support - thanks to aCaB ! */
431
+	    /* FSG v2.0 support - thanks to aCaB ! */
432 432
 
433 433
 	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
434 434
 	    dsize = EC32(section_hdr[i].VirtualSize);
... ...
@@ -516,7 +519,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
516 516
 		    return CL_EMEM;
517 517
 		}
518 518
 
519
-		if(unfsg(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize, dsize) == -1) {
519
+		if(unfsg_200(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize) == -1) {
520 520
 		    cli_dbgmsg("FSG: Unpacking failed\n");
521 521
 		    free(src);
522 522
 		    free(dest);
... ...
@@ -529,6 +532,197 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
529 529
 	    }
530 530
 	}
531 531
 
532
+ 	if(found && buff[0] == '\xbe' && cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase) < min) {
533
+
534
+	    /* FSG support - v. 1.33 (thx trog for the many samples) */
535
+
536
+	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
537
+	    dsize = EC32(section_hdr[i].VirtualSize);
538
+
539
+	    while(found) {
540
+		    int gp, t, sectcnt = 0;
541
+		    char *support;
542
+		    uint32_t newesi, newedi, newebx, oldep;
543
+		    struct SECTION *sections;
544
+
545
+
546
+		if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
547
+		    cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize, limits->maxfilesize);
548
+		    free(section_hdr);
549
+		    return CL_CLEAN;
550
+		}
551
+
552
+		if(ssize <= 0x19 || dsize <= ssize) {
553
+		    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
554
+		    free(section_hdr);
555
+		    return CL_CLEAN;
556
+		}
557
+
558
+		if((gp = cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase)) >= EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
559
+		    cli_dbgmsg("FSG: Support data out of padding area (newedi: %d, vaddr: %d)\n", newedi, EC32(section_hdr[i].VirtualAddress));
560
+		    break;
561
+		}
562
+
563
+		if(limits && limits->maxfilesize && gp > limits->maxfilesize) {
564
+		    cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, limits->maxfilesize);
565
+		    free(section_hdr);
566
+		    return CL_CLEAN;
567
+		}
568
+
569
+		if((support = (char *) cli_malloc(gp)) == NULL) {
570
+		    free(section_hdr);
571
+		    return CL_EMEM;
572
+		}
573
+
574
+		lseek(desc, gp, SEEK_SET);
575
+		gp = EC32(section_hdr[i + 1].PointerToRawData) - gp;
576
+
577
+		if(read(desc, support, gp) != gp) {
578
+		    cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
579
+		    free(section_hdr);
580
+		    free(support);
581
+		    return CL_EIO;
582
+		}
583
+
584
+		newebx = cli_readint32(support) - EC32(optional_hdr.ImageBase); /* Unused */
585
+		newedi = cli_readint32(support + 4) - EC32(optional_hdr.ImageBase); /* 1st dest */
586
+		newesi = cli_readint32(support + 8) - EC32(optional_hdr.ImageBase); /* Source */
587
+
588
+		if(newesi < EC32(section_hdr[i + 1].VirtualAddress || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData))) {
589
+		    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
590
+		    free(support);
591
+		    break;
592
+		}
593
+
594
+		if(newedi != EC32(section_hdr[i].VirtualAddress)) {
595
+		    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
596
+		    free(support);
597
+		    break;
598
+		}
599
+
600
+		/* Counting original sections */
601
+		for(t = 12; t < gp - 4; t += 4) {
602
+			uint32_t rva = cli_readint32(support+t);
603
+
604
+		    if(!rva)
605
+			break;
606
+
607
+		    rva -= EC32(optional_hdr.ImageBase)+1;
608
+		    sectcnt++;
609
+
610
+		    if(rva % 0x1000)
611
+			/* FIXME: really need to bother? */
612
+			cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt);
613
+
614
+		    if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
615
+			cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
616
+			break;
617
+		    }
618
+		}
619
+
620
+		if(!sectcnt || t >= gp - 4 || cli_readint32(support + t)) {
621
+		    free(support);
622
+		    break;
623
+		}
624
+
625
+		if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) {
626
+		    free(section_hdr);
627
+		    free(support);
628
+		    return CL_EMEM;
629
+		}
630
+
631
+		sections[0].rva = newedi;
632
+		for(t = 1; t <= sectcnt; t++)
633
+		    sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr.ImageBase);
634
+
635
+		free(support);
636
+
637
+		if((src = (char *) cli_malloc(ssize)) == NULL) {
638
+		    free(section_hdr);
639
+		    free(sections);
640
+		    return CL_EMEM;
641
+		}
642
+
643
+		lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
644
+		if(read(desc, src, ssize) != ssize) {
645
+		    cli_dbgmsg("Can't read raw data of section %d\n", i);
646
+		    free(section_hdr);
647
+		    free(sections);
648
+		    free(src);
649
+		    return CL_EIO;
650
+		}
651
+
652
+		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
653
+		    free(section_hdr);
654
+		    free(src);
655
+		    free(sections);
656
+		    return CL_EMEM;
657
+		}
658
+
659
+		oldep = EC32(optional_hdr.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163);
660
+		cli_dbgmsg("FSG: found old EP @%x\n", oldep);
661
+
662
+		tempfile = cli_gentemp(NULL);
663
+		if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
664
+		    cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
665
+		    free(tempfile);
666
+		    free(section_hdr);
667
+		    free(src);
668
+		    free(dest);
669
+		    free(sections);
670
+		    return CL_EIO;
671
+		}
672
+
673
+		switch(unfsg_133(src + newesi - EC32(section_hdr[i + 1].VirtualAddress), dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, sections, sectcnt, EC32(optional_hdr.ImageBase), oldep, ndesc)) {
674
+		    case 1: /* Everything OK */
675
+			cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
676
+			free(src);
677
+			free(dest);
678
+			free(sections);
679
+			fsync(ndesc);
680
+			lseek(ndesc, 0, SEEK_SET);
681
+
682
+			if(cli_magic_scandesc(ndesc, virname, scanned, root, limits, options, arec, mrec) == CL_VIRUS) {
683
+			    free(section_hdr);
684
+			    close(ndesc);
685
+			    if(!cli_leavetemps_flag)
686
+				unlink(tempfile);
687
+			    free(tempfile);
688
+			    return CL_VIRUS;
689
+			}
690
+
691
+			close(ndesc);
692
+			if(!cli_leavetemps_flag)
693
+			    unlink(tempfile);
694
+			free(tempfile);
695
+			free(section_hdr);
696
+			return CL_CLEAN;
697
+
698
+		    case 0: /* We've got an unpacked buffer, no exe though */
699
+			cli_dbgmsg("FSG: FSG: Successfully decompressed\n");
700
+			close(ndesc);
701
+			unlink(tempfile);
702
+			free(tempfile);
703
+			free(sections);
704
+			found = 0;
705
+			upx_success = 1;
706
+			break; /* Go and scan the buffer! */
707
+
708
+		    default: /* Everything gone wrong */
709
+			cli_dbgmsg("FSG: Unpacking failed\n");
710
+			close(ndesc);
711
+			unlink(tempfile); // It's empty anyway
712
+			free(tempfile);
713
+			free(src);
714
+			free(dest);
715
+			free(sections);
716
+			break;
717
+		}
718
+
719
+		break; /* were done with 1.33 */
720
+	    }
721
+	}
722
+
532 723
 	if(found) {
533 724
 
534 725
 	    /* UPX support */
... ...
@@ -709,6 +903,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
709 709
 
710 710
     lseek(desc, ep, SEEK_SET);
711 711
     if(read(desc, buff, 200) != 200) {
712
+	cli_dbgmsg("Can't read 200 bytes\n");
712 713
 	free(section_hdr);
713 714
 	return CL_EIO;
714 715
     }
... ...
@@ -20,6 +20,7 @@
20 20
 ** rebuildpe.c
21 21
 ** 
22 22
 ** 28/07/2k4 - Moved out of petitep.c
23
+** 08/08/2k4 - Fixed typo for sects characteristics
23 24
 **
24 25
 */
25 26
 
... ...
@@ -161,7 +162,7 @@ char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base
161 161
       cli_writeint32(curpe+24, 0);
162 162
       cli_writeint32(curpe+28, 0);
163 163
       cli_writeint32(curpe+32, 0);
164
-      cli_writeint32(curpe+24, 0xffffffff);
164
+      cli_writeint32(curpe+0x24, 0xffffffff);
165 165
       curpe+=40;
166 166
     }
167 167
     memcpy(curpe, buffer, datasize);
... ...
@@ -169,3 +170,5 @@ char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base
169 169
 
170 170
   return pefile;
171 171
 }
172
+
173
+