Browse code

activate pe and upx code

git-svn: trunk@651

Tomasz Kojm authored on 2004/07/06 08:50:55
Showing 15 changed files
... ...
@@ -1,3 +1,12 @@
1
+Tue Jul  6 01:46:41 CEST 2004 (tk)
2
+----------------------------------
3
+  * libclamav: pe, upx: add big-endian support
4
+  * libclamav: activate PE and UPX code (new scan option CL_PE). UPX code
5
+	       still needs some corrections in NRV2D/E decompression routines.
6
+  * clamd: new directive ScanPE
7
+  * clamscan: new option --no-pe
8
+  * docs: update manual pages
9
+
1 10
 Sun Jul  4 16:52:45 CEST 2004 (tk)
2 11
 ----------------------------------
3 12
   * libclamav: Do not scan mail files twice. Separate archive and mail
... ...
@@ -311,6 +311,13 @@ int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *cop
311 311
 	logg("Archive support disabled.\n");
312 312
     }
313 313
 
314
+    if(cfgopt(copt, "ScanPE")) {
315
+	logg("Portable Executable support enabled.\n");
316
+	options |= CL_PE;
317
+    } else {
318
+	logg("Portable Executable support disabled.\n");
319
+    }
320
+
314 321
     if(cfgopt(copt, "ScanMail")) {
315 322
 	logg("Mail files support enabled.\n");
316 323
 	options |= CL_MAIL;
... ...
@@ -200,7 +200,8 @@ void help(void)
200 200
     mprintf("    --stdout                             Write to stdout instead of stderr\n");
201 201
     mprintf("                                         (this help is always written to stdout)\n");
202 202
     mprintf("\n");
203
-    mprintf("    --tempdir=DIRECTORY                  create temporary files in DIRECTORY\n");
203
+    mprintf("    --tempdir=DIRECTORY                  Create temporary files in DIRECTORY\n");
204
+    mprintf("    --leave-temps                        Do not remove temporary files\n");
204 205
     mprintf("    --database=FILE/DIR   -d FILE/DIR    Load virus database from FILE or load\n");
205 206
     mprintf("                                         all .cvd and .db[2] files from DIR\n");
206 207
     mprintf("    --log=FILE            -l FILE        Save scan report to FILE\n");
... ...
@@ -219,6 +220,7 @@ void help(void)
219 219
     mprintf("    --no-summary                         Disable summary at end of scanning\n");
220 220
     mprintf("    --mbox                -m             Treat stdin as a mailbox\n");
221 221
     mprintf("\n");
222
+    mprintf("    --no-pe                              Disable PE analysis\n");
222 223
     mprintf("    --no-ole2                            Disable OLE2 support\n");
223 224
     mprintf("    --no-html                            Disable HTML support\n");
224 225
     mprintf("    --no-archive                         Disable libclamav archive support\n");
... ...
@@ -422,6 +422,11 @@ int scanfile(const char *filename, struct cl_node *root, const struct passwd *us
422 422
     if(optl(opt, "block-encrypted"))
423 423
 	options |= CL_ENCRYPTED;
424 424
 
425
+    if(optl(opt, "no-pe"))
426
+	options &= ~CL_PE;
427
+    else
428
+	options |= CL_PE;
429
+
425 430
     if(optl(opt, "no-ole2"))
426 431
 	options &= ~CL_OLE2;
427 432
     else
... ...
@@ -818,6 +823,9 @@ int checkfile(const char *filename, const struct cl_node *root, const struct cl_
818 818
 	int fd, ret;
819 819
 	const char *virname;
820 820
 
821
+
822
+    mprintf("*Scanning %s\n", filename);
823
+
821 824
     if((fd = open(filename, O_RDONLY)) == -1) {
822 825
 	mprintf("@Can't open file %s\n", filename);
823 826
 	return 54;
... ...
@@ -81,6 +81,7 @@ int main(int argc, char **argv)
81 81
 	    {"disable-archive", 0, 0, 0},
82 82
 	    {"no-archive", 0, 0, 0},
83 83
 	    {"block-encrypted", 0, 0, 0},
84
+	    {"no-pe", 0, 0, 0},
84 85
 	    {"no-ole2", 0, 0, 0},
85 86
 	    {"no-html", 0, 0, 0},
86 87
 	    {"mbox", 0, 0, 'm'},
... ...
@@ -159,6 +159,11 @@ Close the connection when this limit is exceeded.
159 159
 .br 
160 160
 Default: disabled.
161 161
 .TP 
162
+\fBScanPE\fR
163
+PE stands for Portable Executable \- it's an executable file format used in all 32\-bit versions of Windows operating systems. This option allows ClamAV to perform a deeper analysis of executable files and it's also required for decompression of popular executable packers such as UPX.
164
+.br 
165
+Default: enabled.
166
+.TP 
162 167
 \fBScanOLE2\fR
163 168
 Enables scanning of Microsoft Office document macros.
164 169
 .br 
... ...
@@ -40,6 +40,9 @@ Save scan report to FILE.
40 40
 \fB\-\-tempdir=DIRECTORY\fR
41 41
 Create temporary files in DIRECTORY. Directory must be writeable for the 'clamav' user or unprivileged user running clamscan.
42 42
 .TP 
43
+\fB\-\-leave\-temps\fR
44
+Do not remove temporary files.
45
+.TP 
43 46
 \fB\-r, \-\-recursive\fR
44 47
 Scan directories recursively. All the subdirectories in the given directory will be scanned.
45 48
 .TP 
... ...
@@ -67,7 +70,8 @@ Remove infected files. \fBBe careful.\fR
67 67
 \fB\-\-move=DIRECTORY\fR
68 68
 Move infected files into DIRECTORY. Directory must be writeable for the 'clamav' user or unprivileged user running clamscan.
69 69
 .TP 
70
-EXTRACTION OPTIONS:
70
+\fB\-\-no\-pe\fR
71
+PE stands for Portable Executable \- it's an executable file format used in all 32\-bit versions of Windows operating systems. By default ClamAV performs deeper analysis of executable files and tries to decompress popular executable packers such as UPX. This option \fBdisables\fR PE support and is not recommended !
71 72
 .TP 
72 73
 \fB\-\-no\-ole2\fR
73 74
 Disable support for Microsoft Office document files.
... ...
@@ -133,22 +133,33 @@ MaxDirectoryRecursion 15
133 133
 # Do not remove temporary files (for debug purposes).
134 134
 #LeaveTemporaryFiles
135 135
 
136
+
137
+##
138
+## Executable files
139
+##
140
+
141
+# PE stands for Portable Executable - it's an executable file format used
142
+# in all 32-bit versions of Windows operating systems. This option allows
143
+# ClamAV to perform a deeper analysis of executable files and it's also
144
+# required for decompression of popular executable packers such as UPX.
145
+ScanPE
146
+
136 147
 ##
137
-## Document scanning
148
+## Documents
138 149
 ##
139 150
 
140 151
 # This option enables scanning of Microsoft Office document macros.
141 152
 ScanOLE2
142 153
 
143 154
 ##
144
-## Mail support
155
+## Mail files
145 156
 ##
146 157
 
147 158
 # Uncomment this option if you are going to scan mail files.
148 159
 #ScanMail
149 160
 
150 161
 ##
151
-## HTML support
162
+## HTML
152 163
 ##
153 164
 
154 165
 # This option enables HTML detection and normalisation. It's highly
... ...
@@ -156,7 +167,7 @@ ScanOLE2
156 156
 ScanHTML
157 157
 
158 158
 ##
159
-## Archive support
159
+## Archives
160 160
 ##
161 161
 
162 162
 
... ...
@@ -74,6 +74,7 @@ extern "C"
74 74
 #define CL_OLE2		8
75 75
 #define CL_ENCRYPTED    16
76 76
 #define CL_HTML		32
77
+#define CL_PE		64
77 78
 
78 79
 struct cli_patt {
79 80
     short int *pattern;
... ...
@@ -46,7 +46,7 @@ static const struct cli_magic_s cli_magic[] = {
46 46
 
47 47
     /* Executables */
48 48
 
49
-/*  {0,  "MZ",				2,  "DOS/W32 executable", CL_DOSEXE},*/
49
+    {0,  "MZ",				2,  "DOS/W32 executable/library/driver", CL_DOSEXE},
50 50
 
51 51
     /* Archives */
52 52
 
... ...
@@ -45,6 +45,23 @@
45 45
 #define UPX_NRV2D "\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x75\x20"
46 46
 #define UPX_NRV2E "\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x72\xcc"
47 47
 
48
+#if WORDS_BIGENDIAN == 0
49
+#define EC16(v)	(v)
50
+#define EC32(v) (v)
51
+#else
52
+static inline uint16_t EC16(uint16_t v)
53
+{
54
+    return ((v >> 8) + (v << 8));
55
+}
56
+
57
+static inline uint32_t EC32(uint32_t v)
58
+{
59
+    return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
60
+}
61
+#endif
62
+
63
+extern short cli_leavetemps_flag;
64
+
48 65
 struct pe_image_file_hdr {
49 66
     uint32_t Magic;
50 67
     uint16_t Machine;
... ...
@@ -120,7 +137,7 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint
120 120
 
121 121
 
122 122
     for(i = 0; i < nos; i++) {
123
-	if(shp[i].VirtualAddress <= rva && shp[i].VirtualAddress + shp[i].SizeOfRawData > rva) {
123
+	if(EC32(shp[i].VirtualAddress) <= rva && EC32(shp[i].VirtualAddress) + EC32(shp[i].SizeOfRawData) > rva) {
124 124
 	    found = 1;
125 125
 	    break;
126 126
 	}
... ...
@@ -131,7 +148,7 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint
131 131
 	return -1;
132 132
     }
133 133
 
134
-    return rva - shp[i].VirtualAddress + shp[i].PointerToRawData;
134
+    return rva - EC32(shp[i].VirtualAddress) + EC32(shp[i].PointerToRawData);
135 135
 }
136 136
 
137 137
 static int cli_ddump(int desc, int offset, int size, const char *file)
... ...
@@ -144,19 +161,19 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
144 144
 
145 145
     if((pos = lseek(desc, 0, SEEK_CUR)) == -1) {
146 146
 	cli_dbgmsg("Invalid descriptor\n");
147
-	return CL_EIO;
147
+	return -1;
148 148
     }
149 149
 
150 150
     if(lseek(desc, offset, SEEK_SET) == -1) {
151 151
 	cli_dbgmsg("lseek() failed\n");
152 152
 	lseek(desc, pos, SEEK_SET);
153
-	return CL_EIO;
153
+	return -1;
154 154
     }
155 155
 
156 156
     if((ndesc = open(file, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
157 157
 	cli_dbgmsg("Can't create file %s\n", file);
158 158
 	lseek(desc, pos, SEEK_SET);
159
-	return CL_EIO;
159
+	return -1;
160 160
     }
161 161
 
162 162
     while((bread = read(desc, buff, FILEBUFF)) > 0) {
... ...
@@ -166,7 +183,7 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
166 166
 		lseek(desc, pos, SEEK_SET);
167 167
 		close(ndesc);
168 168
 		unlink(file);
169
-		return CL_EIO;
169
+		return -1;
170 170
 	    }
171 171
 	    break;
172 172
 	} else {
... ...
@@ -175,7 +192,7 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
175 175
 		lseek(desc, pos, SEEK_SET);
176 176
 		close(ndesc);
177 177
 		unlink(file);
178
-		return CL_EIO;
178
+		return -1;
179 179
 	    }
180 180
 	}
181 181
 	sum += bread;
... ...
@@ -186,17 +203,38 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
186 186
     return 0;
187 187
 }
188 188
 
189
-int cli_scanpe(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, int *reclev)
189
+int cli_memstr(const char *haystack, int hs, const char *needle, int ns)
190
+{
191
+	const char *pt;
192
+	int n;
193
+
194
+    if(!memcmp(haystack, needle, ns))
195
+	return 1;
196
+
197
+    pt = haystack;
198
+    n = hs;
199
+    while(n && (pt = memchr(pt, needle[0], n))) {
200
+	n--;
201
+	if(!memcmp(pt, needle, ns))
202
+	    return 1;
203
+    }
204
+
205
+    return 0;
206
+}
207
+
208
+int cli_scanpe(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, int *arec, int *mrec)
190 209
 {
191 210
 	uint16_t e_magic; /* DOS signature ("MZ") */
211
+	uint16_t nsections;
192 212
 	uint32_t e_lfanew; /* address of new exe header */
193 213
 	uint32_t ep; /* entry point (raw) */
214
+	uint32_t timestamp;
194 215
 	struct pe_image_file_hdr file_hdr;
195 216
 	struct pe_image_optional_hdr optional_hdr;
196 217
 	struct pe_image_section_hdr *section_hdr;
197 218
 	struct stat sb;
198 219
 	char sname[9], buff[24], *tempfile;
199
-	int i, found;
220
+	int i, found, upx_success = 0;
200 221
 	int (*upxfn)(char *, int , char *, int) = NULL;
201 222
 
202 223
 
... ...
@@ -205,38 +243,38 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
205 205
 	return CL_EIO;
206 206
     }
207 207
 
208
-    if(e_magic != IMAGE_DOS_SIGNATURE) {
208
+    if(EC16(e_magic) != IMAGE_DOS_SIGNATURE) {
209 209
 	cli_dbgmsg("Invalid DOS signature\n");
210
-	return -1;
210
+	return CL_CLEAN;
211 211
     }
212 212
 
213 213
     lseek(desc, 58, SEEK_CUR); /* skip to the end of the DOS header */
214 214
 
215 215
     if(read(desc, &e_lfanew, sizeof(e_lfanew)) != sizeof(e_lfanew)) {
216 216
 	cli_dbgmsg("Can't read new header address\n");
217
-	return -1;
217
+	return CL_EIO;
218 218
     }
219 219
 
220
+    e_lfanew = EC32(e_lfanew);
220 221
     cli_dbgmsg("e_lfanew == %d\n", e_lfanew);
221 222
     if(!e_lfanew) {
222 223
 	cli_dbgmsg("Not a PE file\n");
223
-	return -2;
224
+	return CL_CLEAN;
224 225
     }
225
-
226 226
     lseek(desc, e_lfanew, SEEK_SET);
227 227
 
228 228
     if(read(desc, &file_hdr, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
229 229
 	cli_dbgmsg("Can't read file header\n");
230
-	return -1;
230
+	return CL_EIO;
231 231
     }
232 232
 
233
-    if(file_hdr.Magic != IMAGE_NT_SIGNATURE) {
233
+    if(EC32(file_hdr.Magic) != IMAGE_NT_SIGNATURE) {
234 234
 	cli_dbgmsg("Invalid PE signature (probably NE file)\n");
235
-	return -2;
235
+	return CL_CLEAN;
236 236
     }
237 237
 
238 238
     /* cli_dbgmsg("Machine type: "); */
239
-    switch(file_hdr.Machine) {
239
+    switch(EC16(file_hdr.Machine)) {
240 240
 	case 0x14c:
241 241
 	    cli_dbgmsg("Machine type: 80386\n");
242 242
 	    break;
... ...
@@ -265,35 +303,38 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
265 265
 	    cli_warnmsg("Unknown machine type in PE header\n");
266 266
     }
267 267
 
268
-    cli_dbgmsg("NumberOfSections: %d\n", file_hdr.NumberOfSections);
269
-    cli_dbgmsg("TimeDateStamp: %s", ctime((time_t *) &file_hdr.TimeDateStamp));
268
+    nsections = EC16(file_hdr.NumberOfSections);
269
+    cli_dbgmsg("NumberOfSections: %d\n", nsections);
270
+
271
+    timestamp = EC32(file_hdr.TimeDateStamp);
272
+    cli_dbgmsg("TimeDateStamp: %s", ctime((time_t *) &timestamp));
270 273
 
271
-    cli_dbgmsg("SizeOfOptionalHeader: %d\n", file_hdr.SizeOfOptionalHeader);
274
+    cli_dbgmsg("SizeOfOptionalHeader: %d\n", EC16(file_hdr.SizeOfOptionalHeader));
272 275
 
273
-    if(file_hdr.SizeOfOptionalHeader != sizeof(struct pe_image_optional_hdr)) {
276
+    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr)) {
274 277
 	cli_warnmsg("Broken PE header detected.\n");
275
-	return -1;
278
+	return CL_CLEAN;
276 279
     }
277 280
 
278 281
     if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) {
279 282
 	cli_dbgmsg("Can't optional file header\n");
280
-	return -1;
283
+	return CL_EIO;
281 284
     }
282 285
 
283 286
     cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr.MajorLinkerVersion);
284 287
     cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr.MinorLinkerVersion);
285
-    cli_dbgmsg("SizeOfCode: %d\n", optional_hdr.SizeOfCode);
286
-    cli_dbgmsg("SizeOfInitializedData: %d\n", optional_hdr.SizeOfInitializedData);
287
-    cli_dbgmsg("SizeOfUninitializedData: %d\n", optional_hdr.SizeOfUninitializedData);
288
-    cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", optional_hdr.AddressOfEntryPoint);
289
-    cli_dbgmsg("SectionAlignment: %d\n", optional_hdr.SectionAlignment);
290
-    cli_dbgmsg("FileAlignment: %d\n", optional_hdr.FileAlignment);
291
-    cli_dbgmsg("MajorSubsystemVersion: %d\n", optional_hdr.MajorSubsystemVersion);
292
-    cli_dbgmsg("MinorSubsystemVersion: %d\n", optional_hdr.MinorSubsystemVersion);
293
-    cli_dbgmsg("SizeOfImage: %d\n", optional_hdr.SizeOfImage);
294
-    cli_dbgmsg("SizeOfHeaders: %d\n", optional_hdr.SizeOfHeaders);
295
-
296
-    switch(optional_hdr.Subsystem) {
288
+    cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr.SizeOfCode));
289
+    cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr.SizeOfInitializedData));
290
+    cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr.SizeOfUninitializedData));
291
+    cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr.AddressOfEntryPoint));
292
+    cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr.SectionAlignment));
293
+    cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr.FileAlignment));
294
+    cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr.MajorSubsystemVersion));
295
+    cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr.MinorSubsystemVersion));
296
+    cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr.SizeOfImage));
297
+    cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr.SizeOfHeaders));
298
+
299
+    switch(EC16(optional_hdr.Subsystem)) {
297 300
 	case 1:
298 301
 	    cli_dbgmsg("Subsystem: Native (a driver ?)\n");
299 302
 	    break;
... ...
@@ -313,16 +354,16 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
313 313
 	    cli_warnmsg("Unknown subsystem in PE header\n");
314 314
     }
315 315
 
316
-    cli_dbgmsg("NumberOfRvaAndSizes: %d\n", optional_hdr.NumberOfRvaAndSizes);
316
+    cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr.NumberOfRvaAndSizes));
317 317
 
318
-    section_hdr = (struct pe_image_section_hdr *) cli_calloc(file_hdr.NumberOfSections, sizeof(struct pe_image_section_hdr));
318
+    section_hdr = (struct pe_image_section_hdr *) cli_calloc(nsections, sizeof(struct pe_image_section_hdr));
319 319
 
320 320
     if(!section_hdr) {
321 321
 	cli_dbgmsg("Can't allocate memory for section headers\n");
322 322
 	return CL_EMEM;
323 323
     }
324 324
 
325
-    for(i = 0; i < file_hdr.NumberOfSections; i++) {
325
+    for(i = 0; i < nsections; i++) {
326 326
 
327 327
 	if(read(desc, &section_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) {
328 328
 	    cli_dbgmsg("Can't read section header\n");
... ...
@@ -335,15 +376,15 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
335 335
 	sname[8] = 0;
336 336
 	cli_dbgmsg("------------------------------------\n");
337 337
 	cli_dbgmsg("Section name: %s\n", sname);
338
-	cli_dbgmsg("VirtualSize: %d\n", section_hdr[i].VirtualSize);
339
-	cli_dbgmsg("VirtualAddress: 0x%x\n", section_hdr[i].VirtualAddress);
340
-	cli_dbgmsg("Section size: %d\n", section_hdr[i].SizeOfRawData);
341
-	cli_dbgmsg("PointerToRawData: 0x%x (%d)\n", section_hdr[i].PointerToRawData, section_hdr[i].PointerToRawData);
338
+	cli_dbgmsg("VirtualSize: %d\n", EC32(section_hdr[i].VirtualSize));
339
+	cli_dbgmsg("VirtualAddress: 0x%x\n", EC32(section_hdr[i].VirtualAddress));
340
+	cli_dbgmsg("SizeOfRawData: %d\n", EC32(section_hdr[i].SizeOfRawData));
341
+	cli_dbgmsg("PointerToRawData: 0x%x (%d)\n", EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].PointerToRawData));
342 342
 
343
-	if(section_hdr[i].Characteristics & 0x20) {
343
+	if(EC32(section_hdr[i].Characteristics) & 0x20) {
344 344
 	    cli_dbgmsg("Section contains executable code\n");
345 345
 
346
-	    if(section_hdr[i].VirtualSize < section_hdr[i].SizeOfRawData) {
346
+	    if(EC32(section_hdr[i].VirtualSize) < EC32(section_hdr[i].SizeOfRawData)) {
347 347
 		cli_dbgmsg("Section contains free space\n");
348 348
 		/*
349 349
 		cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize);
... ...
@@ -353,7 +394,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
353 353
 	    }
354 354
 	}
355 355
 
356
-	if(section_hdr[i].Characteristics & 0x20000000)
356
+	if(EC32(section_hdr[i].Characteristics) & 0x20000000)
357 357
 	    cli_dbgmsg("Section's memory is executable\n");
358 358
 
359 359
 /*
... ...
@@ -373,87 +414,136 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
373 373
 	return CL_EIO;
374 374
     }
375 375
 
376
-    ep = cli_rawaddr(optional_hdr.AddressOfEntryPoint, section_hdr, file_hdr.NumberOfSections);
376
+    ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections);
377 377
 
378
-    if(section_hdr[i].PointerToRawData + section_hdr[i].SizeOfRawData > sb.st_size || ep == -1) {
379
-	cli_warnmsg("Possibly broken PE file\n");
378
+    if(EC32(section_hdr[i].PointerToRawData) + EC32(section_hdr[i].SizeOfRawData) > sb.st_size || ep == -1) {
379
+	cli_dbgmsg("Possibly broken PE file\n");
380 380
 	free(section_hdr);
381 381
 	return CL_CLEAN;
382 382
     }
383 383
 
384 384
     cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
385 385
 
386
+
387
+    /* UPX support */
388
+
389
+    /* try to detect UPX code */
390
+
386 391
     if(lseek(desc, ep + 0x78, SEEK_SET) == -1) {
387 392
 	cli_dbgmsg("lseek() failed\n");
388 393
 	free(section_hdr);
389 394
 	return CL_EIO;
390 395
     }
391 396
 
392
-    if(read(desc, buff, 24) != 24) {
393
-	cli_dbgmsg("Can't read 24 bytes at 0x%x (%d)\n", ep + 0x78, ep + 0x78);
397
+    if(read(desc, buff, 13) != 13) {
398
+	cli_dbgmsg("UPX: Can't read 13 bytes at 0x%x (%d)\n", ep + 0x78, ep + 0x78);
394 399
     } else {
395
-	if(!memcmp(buff, UPX_NRV2B, 24)) {
396
-	    cli_dbgmsg("UPX: NRV2B decompressor detected\n");
400
+	if(cli_memstr(UPX_NRV2B, 24, buff, 13)) {
401
+	    cli_dbgmsg("UPX: Looks like a NRV2B decompressor\n");
397 402
 	    upxfn = upx_inflate2b;
398
-	} else if(!memcmp(buff, UPX_NRV2D, 24)) {
399
-	    cli_dbgmsg("UPX: NRV2D decompressor detected\n");
403
+	} else if(cli_memstr(UPX_NRV2D, 24, buff, 13)) {
404
+	    cli_dbgmsg("UPX: Looks like a NRV2D decompressor\n");
400 405
 	    upxfn = upx_inflate2d;
401
-	} else if(!memcmp(buff, UPX_NRV2E, 24)) {
402
-            cli_dbgmsg("UPX: NRV2E decompressor detected\n");
406
+	} else if(cli_memstr(UPX_NRV2E, 24, buff, 13)) {
407
+            cli_dbgmsg("UPX: Looks like a NRV2E decompressor\n");
403 408
 	    upxfn = upx_inflate2e;
404 409
 	}
405 410
     }
406 411
 
407
-    if(upxfn) {
408
-	/* try to find the first section with physical size == 0 */
409
-	found = 0;
410
-	for(i = 0; i < file_hdr.NumberOfSections; i++) {
411
-	    if(!section_hdr[i].SizeOfRawData) {
412
-		found = 1;
413
-		break;
414
-	    }
412
+    /* try to find the first section with physical size == 0 */
413
+    found = 0;
414
+    for(i = 0; i < nsections - 1; i++) {
415
+	if(!section_hdr[i].SizeOfRawData) {
416
+	    found = 1;
417
+	    cli_dbgmsg("UPX: empty section found - assuming UPX compression\n");
418
+	    break;
419
+	}
420
+    }
421
+
422
+    if(found) {
423
+	    int ssize, dsize;
424
+	    char *src, *dest;
425
+
426
+	strncpy(sname, section_hdr[i].Name, 8);
427
+	sname[8] = 0;
428
+	cli_dbgmsg("UPX: Section %d name: %s\n", i, sname);
429
+	strncpy(sname, section_hdr[i + 1].Name, 8);
430
+	sname[8] = 0;
431
+	cli_dbgmsg("UPX: Section %d name: %s\n", i + 1, sname);
432
+
433
+	if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4))
434
+	    cli_dbgmsg("UPX: Possibly hacked UPX section headers\n");
435
+
436
+	/* we assume (i + 1) is UPX1 */
437
+	ssize = EC32(section_hdr[i + 1].SizeOfRawData);
438
+	dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize);
439
+
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;
415 444
 	}
416 445
 
417
-	if(found) {
418
-		uint32_t ssize, dsize;
419
-		char *src, *dest;
446
+	if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
447
+	    free(section_hdr);
448
+	    free(src);
449
+	    return CL_EMEM;
450
+	}
420 451
 
421
-	    /* we assume (i + 1) is UPX1 */
422
-	    if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4))
423
-		cli_dbgmsg("Possibly hacked UPX section headers\n");
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 + 1);
455
+	    free(section_hdr);
456
+	    free(src);
457
+	    free(dest);
458
+	    return CL_EIO;
459
+	}
424 460
 
425
-	    /* FIXME: use file operations in case of big files */
426
-	    ssize = section_hdr[i + 1].SizeOfRawData;
427
-	    dsize = section_hdr[i].VirtualSize + section_hdr[i + 1].VirtualSize;
428
-	    if((src = (char *) malloc(ssize)) == NULL) {
429
-		free(section_hdr);
430
-		return CL_EMEM;
461
+	if(upxfn) {
462
+	    if(upxfn(src, ssize, dest, dsize)) {
463
+		cli_dbgmsg("UPX: Prefered decompressor failed\n");
464
+	    } else {
465
+		upx_success = 1;
466
+		cli_dbgmsg("UPX: Successfuly decompressed\n");
431 467
 	    }
468
+	}
432 469
 
433
-	    if((dest = (char *) malloc(dsize)) == NULL) {
434
-		free(section_hdr);
435
-		free(src);
436
-		return CL_EMEM;
470
+	if(!upx_success && upxfn != upx_inflate2b) {
471
+	    if(upx_inflate2b(src, ssize, dest, dsize)) {
472
+		cli_dbgmsg("UPX: NRV2B decompressor failed\n");
473
+	    } else {
474
+		upx_success = 1;
475
+		cli_dbgmsg("UPX: Successfuly decompressed with NRV2B\n");
437 476
 	    }
477
+	}
438 478
 
439
-	    lseek(desc, section_hdr[i + 1].PointerToRawData, SEEK_SET);
440
-	    if(read(desc, src, ssize) != ssize) {
441
-		cli_dbgmsg("Can't read raw data of section %d\n", i + 1);
442
-		free(section_hdr);
443
-		free(src);
444
-		free(dest);
445
-		return CL_EMEM;
479
+	if(!upx_success && upxfn != upx_inflate2d) {
480
+	    if(upx_inflate2d(src, ssize, dest, dsize)) {
481
+		cli_dbgmsg("UPX: NRV2D decompressor failed\n");
482
+	    } else {
483
+		upx_success = 1;
484
+		cli_dbgmsg("UPX: Successfuly decompressed with NRV2D\n");
446 485
 	    }
486
+	}
447 487
 
448
-	    if(upxfn(src, ssize, dest, dsize)) {
449
-		cli_dbgmsg("UPX decompression failed\n");
488
+	if(!upx_success && upxfn != upx_inflate2e) {
489
+	    if(upx_inflate2e(src, ssize, dest, dsize)) {
490
+		cli_dbgmsg("UPX: NRV2E decompressor failed\n");
450 491
 	    } else {
451
-		    int ndesc;
492
+		upx_success = 1;
493
+		cli_dbgmsg("UPX: Successfuly decompressed with NRV2E\n");
494
+	    }
495
+	}
452 496
 
453
-		tempfile = cl_gentemp(NULL);
497
+	if(!upx_success) {
498
+	    cli_dbgmsg("UPX: All decompressors failed\n");
499
+	} else {
500
+	    int ndesc;
454 501
 
502
+	    if(cli_leavetemps_flag) {
503
+		tempfile = cl_gentemp(NULL);
455 504
 		if((ndesc = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
456
-		    cli_dbgmsg("Can't create file %s\n", tempfile);
505
+		    cli_dbgmsg("UPX: Can't create file %s\n", tempfile);
457 506
 		    free(section_hdr);
458 507
 		    free(src);
459 508
 		    free(dest);
... ...
@@ -469,19 +559,20 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
469 469
 		}
470 470
 
471 471
 		close(ndesc);
472
-
473
-		/* TODO: scan and unlink file */
474
-
475
-		/* unlink(tempfile); */
472
+		cli_dbgmsg("UPX: Decompressed data saved in %s\n", tempfile);
476 473
 		free(tempfile);
477 474
 	    }
478 475
 
479
-	    free(src);
480
-	    free(dest);
481
-
482
-	} else {
483
-	    cli_dbgmsg("UPX sections not found\n");
476
+	    if(cl_scanbuff(dest, dsize, virname, root) == CL_VIRUS) {
477
+		free(section_hdr);
478
+		free(src);
479
+		free(dest);
480
+		return CL_VIRUS;
481
+	    }
484 482
 	}
483
+
484
+	free(src);
485
+	free(dest);
485 486
     }
486 487
 
487 488
     /* to be continued ... */
... ...
@@ -21,6 +21,6 @@
21 21
 
22 22
 #include "clamav.h"
23 23
 
24
-int cli_scanpe(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, int *reclev);
24
+int cli_scanpe(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, int *arec, int *mrec);
25 25
 
26 26
 #endif
... ...
@@ -54,6 +54,7 @@ extern short cli_leavetemps_flag;
54 54
 #include "ole2_extract.h"
55 55
 #include "vba_extract.h"
56 56
 #include "msexpand.h"
57
+#include "pe.h"
57 58
 #include "filetypes.h"
58 59
 #include "htmlnorm.h"
59 60
 
... ...
@@ -70,6 +71,7 @@ extern short cli_leavetemps_flag;
70 70
 #define SCAN_MAIL	    (options & CL_MAIL)
71 71
 #define SCAN_OLE2	    (options & CL_OLE2)
72 72
 #define SCAN_HTML	    (options & CL_HTML)
73
+#define SCAN_PE		    (options & CL_PE)
73 74
 #define DISABLE_RAR	    (options & CL_DISABLERAR)
74 75
 #define DETECT_ENCRYPTED    (options & CL_ENCRYPTED)
75 76
 
... ...
@@ -1048,8 +1050,8 @@ static int cli_magic_scandesc(int desc, const char **virname, long int *scanned,
1048 1048
 
1049 1049
     switch(type) {
1050 1050
 	case CL_DOSEXE:
1051
-	    /* temporarily the return code is ignored */
1052
-	    cli_scanpe(desc, virname, scanned, root, limits, options, arec, mrec);
1051
+	    if(SCAN_PE)
1052
+		ret = cli_scanpe(desc, virname, scanned, root, limits, options, arec, mrec);
1053 1053
 	    break;
1054 1054
 
1055 1055
 	case CL_RARFILE:
... ...
@@ -1150,6 +1152,9 @@ static int cli_scanfile(const char *filename, const char **virname, unsigned lon
1150 1150
 {
1151 1151
 	int fd, ret;
1152 1152
 
1153
+
1154
+    cli_dbgmsg("Scanning %s\n", filename);
1155
+
1153 1156
     /* internal version of cl_scanfile with arec/mrec preserved */
1154 1157
     if((fd = open(filename, O_RDONLY)) == -1)
1155 1158
 	return CL_EOPEN;
... ...
@@ -1165,6 +1170,8 @@ int cl_scanfile(const char *filename, const char **virname, unsigned long int *s
1165 1165
 	int fd, ret;
1166 1166
 
1167 1167
 
1168
+    cli_dbgmsg("Scanning %s\n", filename);
1169
+
1168 1170
     if((fd = open(filename, O_RDONLY)) == -1)
1169 1171
 	return CL_EOPEN;
1170 1172
 
... ...
@@ -36,6 +36,9 @@
36 36
 ** bloatness. My gratitude to whoever wrote it.
37 37
 */
38 38
 
39
+#if HAVE_CONFIG_H
40
+#include "clamav-config.h"
41
+#endif
39 42
 
40 43
 #include <stdio.h>
41 44
 #include <stdlib.h>
... ...
@@ -44,17 +47,33 @@
44 44
 #include <unistd.h>
45 45
 #include <string.h>
46 46
 
47
+#include "cltypes.h"
48
+
47 49
 /* [doubleebx] */
48 50
 
49
-static int doubleebx(char *src, int *myebx, int *scur, int ssize)
51
+static int doubleebx(char *src, int32_t *myebx, int *scur, int ssize)
50 52
 {
51
-  int oldebx = *myebx;
53
+  int32_t oldebx = *myebx;
54
+#if WORDS_BIGENDIAN == 1
55
+  char *pt;
56
+  int32_t shift, i = 0;
57
+#endif
52 58
 
53 59
   *myebx*=2;
54 60
   if ( !(oldebx & 0x7fffffff)) {
55 61
     if (*scur<0 || ssize-*scur<4)
56 62
       return 0;
63
+#if WORDS_BIGENDIAN == 0
57 64
     oldebx = *(int*)(src+*scur);
65
+#else
66
+    oldebx = 0;
67
+    pt = src + *scur;
68
+    for(shift = 0; shift < 32; shift += 8) {
69
+      oldebx |= (pt[i] & 0xff ) << shift;
70
+      i++;
71
+    }
72
+#endif
73
+
58 74
     *myebx = oldebx*2+1;
59 75
     *scur+=4;
60 76
   }
... ...
@@ -65,9 +84,8 @@ static int doubleebx(char *src, int *myebx, int *scur, int ssize)
65 65
 
66 66
 int upx_inflate2b(char *src, int ssize, char *dst, int dsize)
67 67
 {
68
-  int backbytes, backsize, unp_offset = -1, i;
69
-  int myebx = 0;
70
-  int scur=0, dcur=0;
68
+  int32_t backbytes, unp_offset = -1, myebx = 0;
69
+  int scur=0, dcur=0, i, backsize;
71 70
 
72 71
   while (1) {
73 72
     while (doubleebx(src, &myebx, &scur, ssize)) {
... ...
@@ -114,6 +132,7 @@ int upx_inflate2b(char *src, int ssize, char *dst, int dsize)
114 114
       backsize++;
115 115
 
116 116
     backsize++;
117
+
117 118
     for (i = 0; i < backsize; i++) {
118 119
       if (dcur+i<0 || dcur+i>=dsize || dcur+unp_offset+i<0 || dcur+unp_offset+i>=dsize)
119 120
 	return -1;
... ...
@@ -126,9 +145,8 @@ int upx_inflate2b(char *src, int ssize, char *dst, int dsize)
126 126
 
127 127
 int upx_inflate2d(char *src, int ssize, char *dst, int dsize)
128 128
 {
129
-  int backbytes, backsize, unp_offset = -1, i;
130
-  int myebx = 0;
131
-  int scur=0, dcur=0;
129
+  int32_t backbytes, unp_offset = -1, myebx = 0;
130
+  int scur=0, dcur=0, i, backsize;
132 131
 
133 132
   while (1) {
134 133
     while (doubleebx(src, &myebx, &scur, ssize)) {
... ...
@@ -192,9 +210,8 @@ int upx_inflate2d(char *src, int ssize, char *dst, int dsize)
192 192
 
193 193
 int upx_inflate2e(char *src, int ssize, char *dst, int dsize)
194 194
 {
195
-  int backbytes, backsize, unp_offset = -1, i;
196
-  int myebx = 0;
197
-  int scur=0, dcur=0;
195
+  int32_t backbytes, unp_offset = -1, myebx = 0;
196
+  int scur=0, dcur=0, i, backsize;
198 197
 
199 198
   while (1) {
200 199
     while (doubleebx(src, &myebx, &scur, ssize)) {
... ...
@@ -62,6 +62,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages)
62 62
 	    {"PidFile", OPT_STR},
63 63
 	    {"TemporaryDirectory", OPT_STR},
64 64
 	    {"MaxFileSize", OPT_COMPSIZE},
65
+	    {"ScanPE", OPT_NOARG},
65 66
 	    {"ScanMail", OPT_NOARG},
66 67
 	    {"ScanHTML", OPT_NOARG},
67 68
 	    {"ScanOLE2", OPT_NOARG},