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... | ... |
@@ -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 |
+ |