git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@725 77e5149b-7576-45b1-b177-96237e5ba77b
Tomasz Kojm authored on 2004/08/05 10:15:59... | ... |
@@ -79,7 +79,7 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \ |
79 | 79 |
blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo table.lo \ |
80 | 80 |
text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \ |
81 | 81 |
cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \ |
82 |
- chmunpack.lo rebuildpe.lo petite.lo |
|
82 |
+ chmunpack.lo rebuildpe.lo petite.lo fsg.lo |
|
83 | 83 |
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS) |
84 | 84 |
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) |
85 | 85 |
depcomp = $(SHELL) $(top_srcdir)/depcomp |
... | ... |
@@ -87,8 +87,8 @@ am__depfiles_maybe = depfiles |
87 | 87 |
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/blob.Plo ./$(DEPDIR)/cabd.Plo \ |
88 | 88 |
@AMDEP_TRUE@ ./$(DEPDIR)/chmunpack.Plo ./$(DEPDIR)/cvd.Plo \ |
89 | 89 |
@AMDEP_TRUE@ ./$(DEPDIR)/dsig.Plo ./$(DEPDIR)/filetypes.Plo \ |
90 |
-@AMDEP_TRUE@ ./$(DEPDIR)/htmlnorm.Plo ./$(DEPDIR)/lzxd.Plo \ |
|
91 |
-@AMDEP_TRUE@ ./$(DEPDIR)/matcher-ac.Plo \ |
|
90 |
+@AMDEP_TRUE@ ./$(DEPDIR)/fsg.Plo ./$(DEPDIR)/htmlnorm.Plo \ |
|
91 |
+@AMDEP_TRUE@ ./$(DEPDIR)/lzxd.Plo ./$(DEPDIR)/matcher-ac.Plo \ |
|
92 | 92 |
@AMDEP_TRUE@ ./$(DEPDIR)/matcher-bm.Plo ./$(DEPDIR)/matcher.Plo \ |
93 | 93 |
@AMDEP_TRUE@ ./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \ |
94 | 94 |
@AMDEP_TRUE@ ./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \ |
... | ... |
@@ -319,7 +319,9 @@ libclamav_la_SOURCES = \ |
319 | 319 |
rebuildpe.c \ |
320 | 320 |
rebuildpe.h \ |
321 | 321 |
petite.c \ |
322 |
- petite.h |
|
322 |
+ petite.h \ |
|
323 |
+ fsg.c \ |
|
324 |
+ fsg.h |
|
323 | 325 |
|
324 | 326 |
lib_LTLIBRARIES = libclamav.la |
325 | 327 |
all: all-am |
... | ... |
@@ -397,6 +399,7 @@ distclean-compile: |
397 | 397 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvd.Plo@am__quote@ |
398 | 398 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsig.Plo@am__quote@ |
399 | 399 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@ |
400 |
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsg.Plo@am__quote@ |
|
400 | 401 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htmlnorm.Plo@am__quote@ |
401 | 402 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzxd.Plo@am__quote@ |
402 | 403 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matcher-ac.Plo@am__quote@ |
403 | 404 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,190 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2004 aCaB <acab@clamav.net> |
|
2 |
+ * |
|
3 |
+ * This program is free software; you can redistribute it and/or modify |
|
4 |
+ * it under the terms of the GNU General Public License as published by |
|
5 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
6 |
+ * (at your option) any later version. |
|
7 |
+ * |
|
8 |
+ * This program is distributed in the hope that it will be useful, |
|
9 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 |
+ * GNU General Public License for more details. |
|
12 |
+ * |
|
13 |
+ * You should have received a copy of the GNU General Public License |
|
14 |
+ * along with this program; if not, write to the Free Software |
|
15 |
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
16 |
+ */ |
|
17 |
+ |
|
18 |
+/* |
|
19 |
+** defsg.c |
|
20 |
+** |
|
21 |
+** 02/08/2k4 - Dumped and reversed |
|
22 |
+** 02/08/2k4 - Done coding |
|
23 |
+** 03/08/2k4 - Cleaning and securing |
|
24 |
+** 04/08/2k4 - Done porting |
|
25 |
+*/ |
|
26 |
+ |
|
27 |
+/* |
|
28 |
+** Unpacks an FSG compressed section. |
|
29 |
+** |
|
30 |
+** Czesc bart, good asm, nice piece of code ;) |
|
31 |
+*/ |
|
32 |
+ |
|
33 |
+#if HAVE_CONFIG_H |
|
34 |
+#include "clamav-config.h" |
|
35 |
+#endif |
|
36 |
+ |
|
37 |
+#include <stdio.h> |
|
38 |
+#include <stdlib.h> |
|
39 |
+#include <sys/types.h> |
|
40 |
+#include <sys/stat.h> |
|
41 |
+#include <unistd.h> |
|
42 |
+#include <string.h> |
|
43 |
+ |
|
44 |
+#include "cltypes.h" |
|
45 |
+#include "pe.h" |
|
46 |
+#include "rebuildpe.h" |
|
47 |
+#include "others.h" |
|
48 |
+ |
|
49 |
+ |
|
50 |
+static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize) |
|
51 |
+{ |
|
52 |
+ unsigned char mydl = *mydlptr; |
|
53 |
+ unsigned char olddl = mydl; |
|
54 |
+ |
|
55 |
+ mydl*=2; |
|
56 |
+ if ( !(olddl & 0x7f)) { |
|
57 |
+ if ( *scur < buffer || *scur >= buffer+buffersize-1 ) |
|
58 |
+ return -1; |
|
59 |
+ olddl = **scur; |
|
60 |
+ mydl = olddl*2+1; |
|
61 |
+ *scur=*scur + 1; |
|
62 |
+ } |
|
63 |
+ *mydlptr = mydl; |
|
64 |
+ return (olddl>>7)&1; |
|
65 |
+} |
|
66 |
+ |
|
67 |
+int unfsg(char *source, char *dest, int ssize, int dsize) { |
|
68 |
+ uint8_t mydl=0x80; |
|
69 |
+ uint32_t backbytes, backsize, oldback; |
|
70 |
+ char *csrc = source, *cdst = dest; |
|
71 |
+ int oob, lostbit = 1; |
|
72 |
+ |
|
73 |
+ /* I assume buffers size is >0 - No checking! */ |
|
74 |
+ *cdst++=*csrc++; |
|
75 |
+ |
|
76 |
+ while ( 1 ) { |
|
77 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize))) { |
|
78 |
+ if (oob == -1) |
|
79 |
+ return -1; |
|
80 |
+ /* 164 */ |
|
81 |
+ backsize = 0; |
|
82 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize))) { |
|
83 |
+ if (oob == -1) |
|
84 |
+ return -1; |
|
85 |
+ /* 16a */ |
|
86 |
+ backbytes = 0; |
|
87 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize))) { |
|
88 |
+ if (oob == -1) |
|
89 |
+ return -1; |
|
90 |
+ /* 170 */ |
|
91 |
+ lostbit = 1; |
|
92 |
+ backsize++; |
|
93 |
+ backbytes = 0x10; |
|
94 |
+ while ( backbytes < 0x100 ) { |
|
95 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
96 |
+ return -1; |
|
97 |
+ backbytes = backbytes*2+oob; |
|
98 |
+ } |
|
99 |
+ backbytes &= 0xff; |
|
100 |
+ if ( ! backbytes ) { |
|
101 |
+ if (cdst >= dest+dsize) |
|
102 |
+ return -1; |
|
103 |
+ *cdst++=0x00; |
|
104 |
+ continue; |
|
105 |
+ } else { |
|
106 |
+ /* repne movsb - FIXME dont remove for now */ |
|
107 |
+ } |
|
108 |
+ } else { |
|
109 |
+ /* 18f */ |
|
110 |
+ if (csrc >= source+ssize) |
|
111 |
+ return -1; |
|
112 |
+ backbytes = *(unsigned char*)csrc; |
|
113 |
+ backsize = backsize * 2 + (backbytes & 1); |
|
114 |
+ backbytes = (backbytes & 0xff)>>1; |
|
115 |
+ csrc++; |
|
116 |
+ if (! backbytes) |
|
117 |
+ break; |
|
118 |
+ backsize+=2; |
|
119 |
+ oldback = backbytes; |
|
120 |
+ lostbit = 0; |
|
121 |
+ } |
|
122 |
+ } else { |
|
123 |
+ /* 180 */ |
|
124 |
+ backsize = 1; |
|
125 |
+ do { |
|
126 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
127 |
+ return -1; |
|
128 |
+ backsize = backsize*2+oob; |
|
129 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
130 |
+ return -1; |
|
131 |
+ } while (oob); |
|
132 |
+ |
|
133 |
+ backsize = backsize - 1 - lostbit; |
|
134 |
+ if (! backsize) { |
|
135 |
+ /* 18a */ |
|
136 |
+ backsize = 1; |
|
137 |
+ do { |
|
138 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
139 |
+ return -1; |
|
140 |
+ backsize = backsize*2+oob; |
|
141 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
142 |
+ return -1; |
|
143 |
+ } while (oob); |
|
144 |
+ |
|
145 |
+ backbytes = oldback; |
|
146 |
+ } else { |
|
147 |
+ /* 198 */ |
|
148 |
+ if (csrc >= source+ssize) |
|
149 |
+ return -1; |
|
150 |
+ backbytes = *(unsigned char*)csrc; |
|
151 |
+ backbytes += (backsize-1)<<8; |
|
152 |
+ backsize = 1; |
|
153 |
+ csrc++; |
|
154 |
+ do { |
|
155 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
156 |
+ return -1; |
|
157 |
+ backsize = backsize*2+oob; |
|
158 |
+ if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) |
|
159 |
+ return -1; |
|
160 |
+ } while (oob); |
|
161 |
+ |
|
162 |
+ if (backbytes >= 0x7d00) |
|
163 |
+ backsize++; |
|
164 |
+ if (backbytes >= 0x500) |
|
165 |
+ backsize++; |
|
166 |
+ if (backbytes <= 0x7f) |
|
167 |
+ backsize += 2; |
|
168 |
+ |
|
169 |
+ oldback = backbytes; |
|
170 |
+ } |
|
171 |
+ lostbit = 0; |
|
172 |
+ } |
|
173 |
+ if (cdst-backbytes < dest || cdst+backsize >= dest+dsize) |
|
174 |
+ return -1; |
|
175 |
+ while(backsize--) { |
|
176 |
+ *cdst=*(cdst-backbytes); |
|
177 |
+ cdst++; |
|
178 |
+ } |
|
179 |
+ |
|
180 |
+ } else { |
|
181 |
+ /* 15d */ |
|
182 |
+ if (cdst < dest || cdst >= dest+dsize || csrc < source || csrc >= source+ssize) |
|
183 |
+ return -1; |
|
184 |
+ *cdst++=*csrc++; |
|
185 |
+ lostbit=1; |
|
186 |
+ } |
|
187 |
+ } |
|
188 |
+ return 0; |
|
189 |
+} |
0 | 190 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,28 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2004 aCaB <acab@clamav.net> |
|
2 |
+ * |
|
3 |
+ * This program is free software; you can redistribute it and/or modify |
|
4 |
+ * it under the terms of the GNU General Public License as published by |
|
5 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
6 |
+ * (at your option) any later version. |
|
7 |
+ * |
|
8 |
+ * This program is distributed in the hope that it will be useful, |
|
9 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 |
+ * GNU General Public License for more details. |
|
12 |
+ * |
|
13 |
+ * You should have received a copy of the GNU General Public License |
|
14 |
+ * along with this program; if not, write to the Free Software |
|
15 |
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
16 |
+ */ |
|
17 |
+ |
|
18 |
+#ifndef __FSG_H |
|
19 |
+#define __FSG_H |
|
20 |
+ |
|
21 |
+#include "cltypes.h" |
|
22 |
+#include "pe.h" |
|
23 |
+ |
|
24 |
+int unfsg(char *, char *, int, int); |
|
25 |
+ |
|
26 |
+#endif |
|
27 |
+ |
... | ... |
@@ -35,6 +35,7 @@ |
35 | 35 |
#include "pe.h" |
36 | 36 |
#include "upx.h" |
37 | 37 |
#include "petite.h" |
38 |
+#include "fsg.h" |
|
38 | 39 |
#include "scanners.h" |
39 | 40 |
|
40 | 41 |
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */ |
... | ... |
@@ -168,7 +169,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
168 | 168 |
struct pe_image_section_hdr *section_hdr; |
169 | 169 |
struct stat sb; |
170 | 170 |
char sname[9], buff[256], *tempfile; |
171 |
- int i, found, upx_success = 0, broken = 0, min = 0, max = 0; |
|
171 |
+ int i, found, upx_success = 0, min = 0, max = 0; |
|
172 | 172 |
int (*upxfn)(char *, int , char *, int) = NULL; |
173 | 173 |
char *src, *dest; |
174 | 174 |
int ssize, dsize, ndesc; |
... | ... |
@@ -385,7 +386,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
385 | 385 |
|
386 | 386 |
} |
387 | 387 |
|
388 |
- if((ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) { |
|
388 |
+ if((ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && (ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) { |
|
389 | 389 |
cli_dbgmsg("Possibly broken PE file\n"); |
390 | 390 |
free(section_hdr); |
391 | 391 |
if(DETECT_BROKEN) { |
... | ... |
@@ -398,151 +399,277 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
398 | 398 |
|
399 | 399 |
cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep); |
400 | 400 |
|
401 |
- /* UPX support */ |
|
401 |
+ /* UPX & FSG support */ |
|
402 | 402 |
|
403 | 403 |
/* try to find the first section with physical size == 0 */ |
404 | 404 |
found = 0; |
405 | 405 |
for(i = 0; i < nsections - 1; i++) { |
406 |
- if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i+1].SizeOfRawData && section_hdr[i+1].VirtualSize) { |
|
406 |
+ if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i + 1].SizeOfRawData && section_hdr[i + 1].VirtualSize) { |
|
407 | 407 |
found = 1; |
408 |
- cli_dbgmsg("UPX: empty section found - assuming UPX compression\n"); |
|
408 |
+ cli_dbgmsg("UPX/FSG: empty section found - assuming compression\n"); |
|
409 | 409 |
break; |
410 | 410 |
} |
411 | 411 |
} |
412 | 412 |
|
413 | 413 |
if(found) { |
414 |
- strncpy(sname, section_hdr[i].Name, 8); |
|
415 |
- sname[8] = 0; |
|
416 |
- cli_dbgmsg("UPX: Section %d name: %s\n", i, sname); |
|
417 |
- strncpy(sname, section_hdr[i + 1].Name, 8); |
|
418 |
- sname[8] = 0; |
|
419 |
- cli_dbgmsg("UPX: Section %d name: %s\n", i + 1, sname); |
|
420 |
- |
|
421 |
- if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4)) |
|
422 |
- cli_dbgmsg("UPX: Possibly hacked UPX section headers\n"); |
|
423 |
- |
|
424 |
- /* we assume (i + 1) is UPX1 */ |
|
425 |
- ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
426 |
- dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize); |
|
427 | 414 |
|
428 |
- if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) { |
|
429 |
- cli_dbgmsg("UPX: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize); |
|
415 |
+ /* Check EP for UPX vs. FSG */ |
|
416 |
+ if(lseek(desc, ep, SEEK_SET) == -1) { |
|
417 |
+ cli_dbgmsg("UPX/FSG: lseek() failed\n"); |
|
430 | 418 |
free(section_hdr); |
431 |
- return CL_CLEAN; |
|
419 |
+ return CL_EIO; |
|
432 | 420 |
} |
433 | 421 |
|
434 |
- if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */ |
|
435 |
- cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
436 |
- free(section_hdr); |
|
437 |
- return CL_CLEAN; |
|
422 |
+ if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */ |
|
423 |
+ cli_dbgmsg("UPX/FSG: Can't read 126 bytes at 0x%x (%d)\n", ep, ep); |
|
424 |
+ free(section_hdr); |
|
425 |
+ return CL_EIO; |
|
438 | 426 |
} |
439 | 427 |
|
440 |
- /* FIXME: use file operations in case of big files */ |
|
441 |
- if((src = (char *) cli_malloc(ssize)) == NULL) { |
|
442 |
- free(section_hdr); |
|
443 |
- return CL_EMEM; |
|
444 |
- } |
|
428 |
+ if(buff[0]=='\x87' || buff [1]=='\x25') { |
|
445 | 429 |
|
446 |
- if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
|
447 |
- free(section_hdr); |
|
448 |
- free(src); |
|
449 |
- return CL_EMEM; |
|
450 |
- } |
|
430 |
+ /* FSG support - thanks to aCaB ! */ |
|
451 | 431 |
|
452 |
- lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
453 |
- if(read(desc, src, ssize) != ssize) { |
|
454 |
- cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
455 |
- free(section_hdr); |
|
456 |
- free(src); |
|
457 |
- free(dest); |
|
458 |
- return CL_EIO; |
|
459 |
- } |
|
432 |
+ ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
433 |
+ dsize = EC32(section_hdr[i].VirtualSize); |
|
460 | 434 |
|
461 |
- /* try to detect UPX code */ |
|
435 |
+ while(found) { |
|
436 |
+ uint32_t newesi, newedi, newebx, newedx; |
|
462 | 437 |
|
463 |
- if(lseek(desc, ep, SEEK_SET) == -1) { |
|
464 |
- cli_dbgmsg("lseek() failed\n"); |
|
465 |
- free(section_hdr); |
|
466 |
- free(src); |
|
467 |
- free(dest); |
|
468 |
- return CL_EIO; |
|
469 |
- } |
|
438 |
+ if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) { |
|
439 |
+ cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize); |
|
440 |
+ free(section_hdr); |
|
441 |
+ return CL_CLEAN; |
|
442 |
+ } |
|
470 | 443 |
|
471 |
- if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */ |
|
472 |
- cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep); |
|
473 |
- free(section_hdr); |
|
474 |
- free(src); |
|
475 |
- free(dest); |
|
476 |
- return CL_EIO; |
|
477 |
- } else { |
|
478 |
- if(cli_memstr(UPX_NRV2B, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, buff + 0x69 + 8, 13)) { |
|
479 |
- cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n"); |
|
480 |
- upxfn = upx_inflate2b; |
|
481 |
- } else if(cli_memstr(UPX_NRV2D, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, buff + 0x69 + 8, 13)) { |
|
482 |
- cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n"); |
|
483 |
- upxfn = upx_inflate2d; |
|
484 |
- } else if(cli_memstr(UPX_NRV2E, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, buff + 0x69 + 8, 13)) { |
|
485 |
- cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n"); |
|
486 |
- upxfn = upx_inflate2e; |
|
444 |
+ if(ssize <= 0x19 || dsize <= ssize) { |
|
445 |
+ cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
446 |
+ free(section_hdr); |
|
447 |
+ return CL_CLEAN; |
|
448 |
+ } |
|
449 |
+ |
|
450 |
+ if((newedx = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase)) < EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) { |
|
451 |
+ cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx); |
|
452 |
+ break; |
|
453 |
+ } |
|
454 |
+ |
|
455 |
+ if((src = (char *) cli_malloc(ssize)) == NULL) { |
|
456 |
+ free(section_hdr); |
|
457 |
+ return CL_EMEM; |
|
458 |
+ } |
|
459 |
+ |
|
460 |
+ lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
461 |
+ if(read(desc, src, ssize) != ssize) { |
|
462 |
+ cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
463 |
+ free(section_hdr); |
|
464 |
+ free(src); |
|
465 |
+ return CL_EIO; |
|
466 |
+ } |
|
467 |
+ |
|
468 |
+ if((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src || dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) { |
|
469 |
+ cli_dbgmsg("FSG: New ESP out of bounds\n"); |
|
470 |
+ free(src); |
|
471 |
+ break; |
|
472 |
+ } |
|
473 |
+ |
|
474 |
+ if((newedx = cli_readint32(dest) - EC32(optional_hdr.ImageBase)) <= EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) { |
|
475 |
+ cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx); |
|
476 |
+ free(src); |
|
477 |
+ break; |
|
478 |
+ } |
|
479 |
+ |
|
480 |
+ if((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src || dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 32) { |
|
481 |
+ cli_dbgmsg("FSG: New stack out of bounds\n"); |
|
482 |
+ free(src); |
|
483 |
+ break; |
|
484 |
+ } |
|
485 |
+ |
|
486 |
+ newedi = cli_readint32(dest) - EC32(optional_hdr.ImageBase); |
|
487 |
+ newesi = cli_readint32(dest + 4) - EC32(optional_hdr.ImageBase); |
|
488 |
+ newebx = cli_readint32(dest + 16) - EC32(optional_hdr.ImageBase); |
|
489 |
+ newedx = cli_readint32(dest + 20); |
|
490 |
+ |
|
491 |
+ if(newedi != EC32(section_hdr[i].VirtualAddress)) { |
|
492 |
+ cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress)); |
|
493 |
+ free(src); |
|
494 |
+ break; |
|
495 |
+ } |
|
496 |
+ |
|
497 |
+ if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) { |
|
498 |
+ cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
|
499 |
+ free(src); |
|
500 |
+ break; |
|
501 |
+ } |
|
502 |
+ |
|
503 |
+ if(newebx < EC32(section_hdr[i + 1].VirtualAddress) || newebx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 16) { |
|
504 |
+ cli_dbgmsg("FSG: Array of functions out of bounds\n"); |
|
505 |
+ free(src); |
|
506 |
+ break; |
|
507 |
+ } |
|
508 |
+ |
|
509 |
+ /* FIXME: unused atm, needed for pe rebuilding */ |
|
510 |
+ cli_dbgmsg("FSG: found old EP @%x\n", cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr.ImageBase)); |
|
511 |
+ |
|
512 |
+ if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
|
513 |
+ free(section_hdr); |
|
514 |
+ free(src); |
|
515 |
+ return CL_EMEM; |
|
516 |
+ } |
|
517 |
+ |
|
518 |
+ if(unfsg(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize, dsize) == -1) { |
|
519 |
+ cli_dbgmsg("FSG: Unpacking failed\n"); |
|
520 |
+ free(src); |
|
521 |
+ free(dest); |
|
522 |
+ break; |
|
523 |
+ } |
|
524 |
+ |
|
525 |
+ found = 0; |
|
526 |
+ upx_success = 1; |
|
527 |
+ cli_dbgmsg("FSG: Successfully decompressed\n"); |
|
487 | 528 |
} |
488 | 529 |
} |
489 | 530 |
|
490 |
- if(upxfn) { |
|
491 |
- int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i+1].VirtualAddress); |
|
531 |
+ if(found) { |
|
492 | 532 |
|
493 |
- if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff ) { /* FIXME: legit skews?? */ |
|
494 |
- skew = 0; |
|
495 |
- if(!upxfn(src, ssize, dest, dsize)) |
|
496 |
- upx_success = 1; |
|
533 |
+ /* UPX support */ |
|
497 | 534 |
|
498 |
- } else { |
|
499 |
- cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew); |
|
500 |
- if(!upxfn(src + skew, ssize - skew, dest, dsize) || !upxfn(src, ssize, dest, dsize)) |
|
501 |
- upx_success = 1; |
|
535 |
+ strncpy(sname, section_hdr[i].Name, 8); |
|
536 |
+ sname[8] = 0; |
|
537 |
+ cli_dbgmsg("UPX: Section %d name: %s\n", i, sname); |
|
538 |
+ strncpy(sname, section_hdr[i + 1].Name, 8); |
|
539 |
+ sname[8] = 0; |
|
540 |
+ cli_dbgmsg("UPX: Section %d name: %s\n", i + 1, sname); |
|
541 |
+ |
|
542 |
+ if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4)) |
|
543 |
+ cli_dbgmsg("UPX: Possibly hacked UPX section headers\n"); |
|
544 |
+ |
|
545 |
+ /* we assume (i + 1) is UPX1 */ |
|
546 |
+ ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
547 |
+ dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize); |
|
548 |
+ |
|
549 |
+ if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) { |
|
550 |
+ cli_dbgmsg("UPX: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize); |
|
551 |
+ free(section_hdr); |
|
552 |
+ return CL_CLEAN; |
|
502 | 553 |
} |
503 | 554 |
|
504 |
- if(upx_success) |
|
505 |
- cli_dbgmsg("UPX: Successfully decompressed\n"); |
|
506 |
- else |
|
507 |
- cli_dbgmsg("UPX: Prefered decompressor failed\n"); |
|
508 |
- } |
|
555 |
+ if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */ |
|
556 |
+ cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
557 |
+ free(section_hdr); |
|
558 |
+ return CL_CLEAN; |
|
559 |
+ } |
|
509 | 560 |
|
510 |
- if(!upx_success && upxfn != upx_inflate2b) { |
|
511 |
- if(upx_inflate2b(src, ssize, dest, dsize) && upx_inflate2b(src + 0x15, ssize - 0x15, dest, dsize) ) { |
|
512 |
- cli_dbgmsg("UPX: NRV2B decompressor failed\n"); |
|
513 |
- } else { |
|
514 |
- upx_success = 1; |
|
515 |
- cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n"); |
|
561 |
+ /* FIXME: use file operations in case of big files */ |
|
562 |
+ if((src = (char *) cli_malloc(ssize)) == NULL) { |
|
563 |
+ free(section_hdr); |
|
564 |
+ return CL_EMEM; |
|
516 | 565 |
} |
517 |
- } |
|
518 | 566 |
|
519 |
- if(!upx_success && upxfn != upx_inflate2d) { |
|
520 |
- if(upx_inflate2d(src, ssize, dest, dsize) && upx_inflate2d(src+0x15, ssize-0x15, dest, dsize) ) { |
|
521 |
- cli_dbgmsg("UPX: NRV2D decompressor failed\n"); |
|
522 |
- } else { |
|
523 |
- upx_success = 1; |
|
524 |
- cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n"); |
|
567 |
+ if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
|
568 |
+ free(section_hdr); |
|
569 |
+ free(src); |
|
570 |
+ return CL_EMEM; |
|
571 |
+ } |
|
572 |
+ |
|
573 |
+ lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
574 |
+ if(read(desc, src, ssize) != ssize) { |
|
575 |
+ cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
576 |
+ free(section_hdr); |
|
577 |
+ free(src); |
|
578 |
+ free(dest); |
|
579 |
+ return CL_EIO; |
|
525 | 580 |
} |
526 |
- } |
|
527 | 581 |
|
528 |
- if(!upx_success && upxfn != upx_inflate2e) { |
|
529 |
- if(upx_inflate2e(src, ssize, dest, dsize) && upx_inflate2e(src + 0x15, ssize - 0x15, dest, dsize) ) { |
|
530 |
- cli_dbgmsg("UPX: NRV2E decompressor failed\n"); |
|
582 |
+ /* try to detect UPX code */ |
|
583 |
+ |
|
584 |
+ if(lseek(desc, ep, SEEK_SET) == -1) { |
|
585 |
+ cli_dbgmsg("lseek() failed\n"); |
|
586 |
+ free(section_hdr); |
|
587 |
+ free(src); |
|
588 |
+ free(dest); |
|
589 |
+ return CL_EIO; |
|
590 |
+ } |
|
591 |
+ |
|
592 |
+ if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */ |
|
593 |
+ cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep); |
|
594 |
+ free(section_hdr); |
|
595 |
+ free(src); |
|
596 |
+ free(dest); |
|
597 |
+ return CL_EIO; |
|
531 | 598 |
} else { |
532 |
- upx_success = 1; |
|
533 |
- cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n"); |
|
599 |
+ if(cli_memstr(UPX_NRV2B, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, buff + 0x69 + 8, 13)) { |
|
600 |
+ cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n"); |
|
601 |
+ upxfn = upx_inflate2b; |
|
602 |
+ } else if(cli_memstr(UPX_NRV2D, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, buff + 0x69 + 8, 13)) { |
|
603 |
+ cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n"); |
|
604 |
+ upxfn = upx_inflate2d; |
|
605 |
+ } else if(cli_memstr(UPX_NRV2E, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, buff + 0x69 + 8, 13)) { |
|
606 |
+ cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n"); |
|
607 |
+ upxfn = upx_inflate2e; |
|
608 |
+ } |
|
609 |
+ } |
|
610 |
+ |
|
611 |
+ if(upxfn) { |
|
612 |
+ int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress); |
|
613 |
+ |
|
614 |
+ if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff ) { /* FIXME: legit skews?? */ |
|
615 |
+ skew = 0; |
|
616 |
+ if(!upxfn(src, ssize, dest, dsize)) |
|
617 |
+ upx_success = 1; |
|
618 |
+ |
|
619 |
+ } else { |
|
620 |
+ cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew); |
|
621 |
+ if(!upxfn(src + skew, ssize - skew, dest, dsize) || !upxfn(src, ssize, dest, dsize)) |
|
622 |
+ upx_success = 1; |
|
623 |
+ } |
|
624 |
+ |
|
625 |
+ if(upx_success) |
|
626 |
+ cli_dbgmsg("UPX: Successfully decompressed\n"); |
|
627 |
+ else |
|
628 |
+ cli_dbgmsg("UPX: Prefered decompressor failed\n"); |
|
629 |
+ } |
|
630 |
+ |
|
631 |
+ if(!upx_success && upxfn != upx_inflate2b) { |
|
632 |
+ if(upx_inflate2b(src, ssize, dest, dsize) && upx_inflate2b(src + 0x15, ssize - 0x15, dest, dsize) ) { |
|
633 |
+ cli_dbgmsg("UPX: NRV2B decompressor failed\n"); |
|
634 |
+ } else { |
|
635 |
+ upx_success = 1; |
|
636 |
+ cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n"); |
|
637 |
+ } |
|
638 |
+ } |
|
639 |
+ |
|
640 |
+ if(!upx_success && upxfn != upx_inflate2d) { |
|
641 |
+ if(upx_inflate2d(src, ssize, dest, dsize) && upx_inflate2d(src + 0x15, ssize - 0x15, dest, dsize) ) { |
|
642 |
+ cli_dbgmsg("UPX: NRV2D decompressor failed\n"); |
|
643 |
+ } else { |
|
644 |
+ upx_success = 1; |
|
645 |
+ cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n"); |
|
646 |
+ } |
|
647 |
+ } |
|
648 |
+ |
|
649 |
+ if(!upx_success && upxfn != upx_inflate2e) { |
|
650 |
+ if(upx_inflate2e(src, ssize, dest, dsize) && upx_inflate2e(src + 0x15, ssize - 0x15, dest, dsize) ) { |
|
651 |
+ cli_dbgmsg("UPX: NRV2E decompressor failed\n"); |
|
652 |
+ } else { |
|
653 |
+ upx_success = 1; |
|
654 |
+ cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n"); |
|
655 |
+ } |
|
656 |
+ } |
|
657 |
+ |
|
658 |
+ if(!upx_success) { |
|
659 |
+ cli_dbgmsg("UPX: All decompressors failed\n"); |
|
660 |
+ free(src); |
|
661 |
+ free(dest); |
|
534 | 662 |
} |
535 | 663 |
} |
536 | 664 |
|
537 |
- if(!upx_success) { |
|
538 |
- cli_dbgmsg("UPX: All decompressors failed\n"); |
|
539 |
- } else { |
|
540 |
- int ndesc; |
|
665 |
+ if(upx_success) { |
|
666 |
+ int ndesc; |
|
541 | 667 |
|
542 | 668 |
if(cli_leavetemps_flag) { |
543 | 669 |
tempfile = cli_gentemp(NULL); |
544 | 670 |
if((ndesc = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) { |
545 |
- cli_dbgmsg("UPX: Can't create file %s\n", tempfile); |
|
671 |
+ cli_dbgmsg("UPX/FSG: Can't create file %s\n", tempfile); |
|
546 | 672 |
free(tempfile); |
547 | 673 |
free(section_hdr); |
548 | 674 |
free(src); |
... | ... |
@@ -551,7 +678,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
551 | 551 |
} |
552 | 552 |
|
553 | 553 |
if(write(ndesc, dest, dsize) != dsize) { |
554 |
- cli_dbgmsg("Can't write %d bytes\n", dsize); |
|
554 |
+ cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize); |
|
555 | 555 |
free(tempfile); |
556 | 556 |
free(section_hdr); |
557 | 557 |
free(src); |
... | ... |
@@ -560,7 +687,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
560 | 560 |
} |
561 | 561 |
|
562 | 562 |
close(ndesc); |
563 |
- cli_dbgmsg("UPX: Decompressed data saved in %s\n", tempfile); |
|
563 |
+ cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile); |
|
564 | 564 |
free(tempfile); |
565 | 565 |
} |
566 | 566 |
|
... | ... |
@@ -570,10 +697,10 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
570 | 570 |
free(dest); |
571 | 571 |
return CL_VIRUS; |
572 | 572 |
} |
573 |
- } |
|
574 | 573 |
|
575 |
- free(src); |
|
576 |
- free(dest); |
|
574 |
+ free(src); |
|
575 |
+ free(dest); |
|
576 |
+ } |
|
577 | 577 |
} |
578 | 578 |
|
579 | 579 |
/* Petite */ |