git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@724 77e5149b-7576-45b1-b177-96237e5ba77b
Tomasz Kojm authored on 2004/08/05 05:11:18... | ... |
@@ -1,3 +1,12 @@ |
1 |
+Wed Aug 4 22:03:56 CEST 2004 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: pe: improve detection of broken executable files |
|
4 |
+ * libclamav: new scan option CL_BROKEN (report broken executables as |
|
5 |
+ Broken.Executable) |
|
6 |
+ * clamscan: new option --detect-broken |
|
7 |
+ * clamd: new directive DetectBrokenExecutables |
|
8 |
+ * docs: update manual pages |
|
9 |
+ |
|
1 | 10 |
Wed Aug 4 19:59:54 BST 2004 (njh) |
2 | 11 |
---------------------------------- |
3 | 12 |
* libclamav: Improved the decoding of multipart messages and MIME headers |
... | ... |
@@ -314,6 +314,12 @@ int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *cop |
314 | 314 |
if(cfgopt(copt, "ScanPE")) { |
315 | 315 |
logg("Portable Executable support enabled.\n"); |
316 | 316 |
options |= CL_PE; |
317 |
+ |
|
318 |
+ if(cfgopt(copt, "DetectBrokenExecutables")) { |
|
319 |
+ logg("Detection of broken executables enabled.\n"); |
|
320 |
+ options |= CL_BROKEN; |
|
321 |
+ } |
|
322 |
+ |
|
317 | 323 |
} else { |
318 | 324 |
logg("Portable Executable support disabled.\n"); |
319 | 325 |
} |
... | ... |
@@ -224,10 +224,12 @@ void help(void) |
224 | 224 |
mprintf(" --no-ole2 Disable OLE2 support\n"); |
225 | 225 |
mprintf(" --no-html Disable HTML support\n"); |
226 | 226 |
mprintf(" --no-archive Disable libclamav archive support\n"); |
227 |
- mprintf(" --block-encrypted Block encrypted archives.\n"); |
|
227 |
+ mprintf(" --detect-broken Try to detect broken executable files\n"); |
|
228 |
+ mprintf(" --block-encrypted Block encrypted archives\n"); |
|
228 | 229 |
mprintf(" --max-space=#n Extract first #n kilobytes only\n"); |
229 | 230 |
mprintf(" --max-files=#n Extract first #n files only\n"); |
230 | 231 |
mprintf(" --max-recursion=#n Maximal recursion level\n"); |
232 |
+ mprintf(" --max-ratio=#n Maximum compression ratio limit\n"); |
|
231 | 233 |
mprintf(" --unzip[=FULLPATH] Enable support for .zip files\n"); |
232 | 234 |
mprintf(" --unrar[=FULLPATH] Enable support for .rar files\n"); |
233 | 235 |
mprintf(" --arj[=FULLPATH] Enable support for .arj files\n"); |
... | ... |
@@ -421,6 +421,9 @@ int scanfile(const char *filename, struct cl_node *root, const struct passwd *us |
421 | 421 |
else |
422 | 422 |
options |= CL_ARCHIVE; |
423 | 423 |
|
424 |
+ if(optl(opt, "detect-broken")) |
|
425 |
+ options |= CL_BROKEN; |
|
426 |
+ |
|
424 | 427 |
if(optl(opt, "block-encrypted")) |
425 | 428 |
options |= CL_ENCRYPTED; |
426 | 429 |
|
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
.\" Manual page created by Tomasz Kojm, 20021001. |
2 |
-.TH "clamav.conf" "5" "March 14, 2004" "Tomasz Kojm" "Clam AntiVirus" |
|
2 |
+.TH "clamav.conf" "5" "August 4, 2004" "Tomasz Kojm" "Clam AntiVirus" |
|
3 | 3 |
.SH "NAME" |
4 | 4 |
.LP |
5 | 5 |
\fBclamav.conf\fR \- a configuration file for Clam AntiVirus Daemon |
... | ... |
@@ -164,6 +164,11 @@ PE stands for Portable Executable \- it's an executable file format used in all |
164 | 164 |
.br |
165 | 165 |
Default: enabled. |
166 | 166 |
.TP |
167 |
+\fBDetectBrokenExecutables\fR |
|
168 |
+With this option clamav will try to detect broken executables and mark them as Broken.Executable. |
|
169 |
+.br |
|
170 |
+Default: disabled. |
|
171 |
+.TP |
|
167 | 172 |
\fBScanOLE2\fR |
168 | 173 |
Enables scanning of Microsoft Office document macros. |
169 | 174 |
.br |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
.\" Manual page created by Tomasz Kojm, 14/15 IV 2002 |
2 |
-.TH "clamscan" "1" "March 14, 2004" "Tomasz Kojm" "Clam AntiVirus" |
|
2 |
+.TH "clamscan" "1" "August 4, 2004" "Tomasz Kojm" "Clam AntiVirus" |
|
3 | 3 |
.SH "NAME" |
4 | 4 |
.LP |
5 | 5 |
clamscan \- scan files and directories against viruses |
... | ... |
@@ -82,6 +82,9 @@ Disable support for HTML detection and normalisation. |
82 | 82 |
\fB\-\-no\-archive\fR |
83 | 83 |
Disable archive support built in libclamav. |
84 | 84 |
.TP |
85 |
+\fB\-\-detect\-broken\fR |
|
86 |
+Mark broken executables as viruses (Broken.Executable). |
|
87 |
+.TP |
|
85 | 88 |
\fB\-\-block\-encrypted\fR |
86 | 89 |
Mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR). |
87 | 90 |
.TP |
... | ... |
@@ -144,6 +144,11 @@ MaxDirectoryRecursion 15 |
144 | 144 |
# required for decompression of popular executable packers such as UPX. |
145 | 145 |
ScanPE |
146 | 146 |
|
147 |
+# With this option clamav will try to detect broken executables and mark |
|
148 |
+# them as Broken.Executable |
|
149 |
+#DetectBrokenExecutables |
|
150 |
+ |
|
151 |
+ |
|
147 | 152 |
## |
148 | 153 |
## Documents |
149 | 154 |
## |
... | ... |
@@ -42,6 +42,8 @@ |
42 | 42 |
#define IMAGE_NT_SIGNATURE 0x00004550 |
43 | 43 |
#define IMAGE_OPTIONAL_SIGNATURE 0x010b |
44 | 44 |
|
45 |
+#define DETECT_BROKEN (options & CL_BROKEN) |
|
46 |
+ |
|
45 | 47 |
#define UPX_NRV2B "\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x11\xc9\x75\x20\x41\x01\xdb" |
46 | 48 |
#define UPX_NRV2D "\x83\xf0\xff\x74\x78\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9" |
47 | 49 |
#define UPX_NRV2E "\xeb\x52\x31\xc9\x83\xe8\x03\x72\x11\xc1\xe0\x08\x8a\x06\x46\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5" |
... | ... |
@@ -213,7 +215,6 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
213 | 213 |
return CL_CLEAN; |
214 | 214 |
} |
215 | 215 |
|
216 |
- /* cli_dbgmsg("Machine type: "); */ |
|
217 | 216 |
switch(EC16(file_hdr.Machine)) { |
218 | 217 |
case 0x14c: |
219 | 218 |
cli_dbgmsg("Machine type: 80386\n"); |
... | ... |
@@ -253,12 +254,22 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
253 | 253 |
|
254 | 254 |
if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr)) { |
255 | 255 |
cli_warnmsg("Broken PE header detected.\n"); |
256 |
+ if(DETECT_BROKEN) { |
|
257 |
+ if(virname) |
|
258 |
+ *virname = "Broken.Executable"; |
|
259 |
+ return CL_VIRUS; |
|
260 |
+ } |
|
256 | 261 |
return CL_CLEAN; |
257 | 262 |
} |
258 | 263 |
|
259 | 264 |
if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) { |
260 | 265 |
cli_dbgmsg("Can't optional file header\n"); |
261 |
- return CL_EIO; |
|
266 |
+ if(DETECT_BROKEN) { |
|
267 |
+ if(virname) |
|
268 |
+ *virname = "Broken.Executable"; |
|
269 |
+ return CL_VIRUS; |
|
270 |
+ } |
|
271 |
+ return CL_CLEAN; |
|
262 | 272 |
} |
263 | 273 |
|
264 | 274 |
cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr.MajorLinkerVersion); |
... | ... |
@@ -304,12 +315,23 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
304 | 304 |
return CL_EMEM; |
305 | 305 |
} |
306 | 306 |
|
307 |
+ if(fstat(desc, &sb) == -1) { |
|
308 |
+ cli_dbgmsg("fstat failed\n"); |
|
309 |
+ free(section_hdr); |
|
310 |
+ return CL_EIO; |
|
311 |
+ } |
|
312 |
+ |
|
307 | 313 |
for(i = 0; i < nsections; i++) { |
308 | 314 |
|
309 | 315 |
if(read(desc, §ion_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) { |
310 | 316 |
cli_dbgmsg("Can't read section header\n"); |
311 | 317 |
cli_dbgmsg("Possibly broken PE file\n"); |
312 | 318 |
free(section_hdr); |
319 |
+ if(DETECT_BROKEN) { |
|
320 |
+ if(virname) |
|
321 |
+ *virname = "Broken.Executable"; |
|
322 |
+ return CL_VIRUS; |
|
323 |
+ } |
|
313 | 324 |
return CL_CLEAN; |
314 | 325 |
} |
315 | 326 |
|
... | ... |
@@ -339,6 +361,17 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
339 | 339 |
cli_dbgmsg("Section's memory is executable\n"); |
340 | 340 |
cli_dbgmsg("------------------------------------\n"); |
341 | 341 |
|
342 |
+ if(EC32(section_hdr[i].PointerToRawData) + EC32(section_hdr[i].SizeOfRawData) > sb.st_size) { |
|
343 |
+ cli_dbgmsg("Possibly broken PE file - Section %d out of file (Offset@ %d, Rsize %d, Total filesize %d)\n", i, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData), sb.st_size); |
|
344 |
+ free(section_hdr); |
|
345 |
+ if(DETECT_BROKEN) { |
|
346 |
+ if(virname) |
|
347 |
+ *virname = "Broken.Executable"; |
|
348 |
+ return CL_VIRUS; |
|
349 |
+ } |
|
350 |
+ return CL_CLEAN; |
|
351 |
+ } |
|
352 |
+ |
|
342 | 353 |
if(!i) { |
343 | 354 |
min = EC32(section_hdr[i].VirtualAddress); |
344 | 355 |
max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData); |
... | ... |
@@ -349,33 +382,22 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
349 | 349 |
if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max) |
350 | 350 |
max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData); |
351 | 351 |
} |
352 |
- } |
|
353 | 352 |
|
354 |
- if(fstat(desc, &sb) == -1) { |
|
355 |
- cli_dbgmsg("fstat failed\n"); |
|
356 |
- free(section_hdr); |
|
357 |
- return CL_EIO; |
|
358 | 353 |
} |
359 | 354 |
|
360 | 355 |
if((ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) { |
361 | 356 |
cli_dbgmsg("Possibly broken PE file\n"); |
362 |
- broken = 1; |
|
363 |
- } |
|
364 |
- |
|
365 |
- /* simple sanity check */ |
|
366 |
- if(!broken && EC32(section_hdr[nsections - 1].PointerToRawData) + EC32(section_hdr[nsections - 1].SizeOfRawData) > sb.st_size) { |
|
367 |
- cli_dbgmsg("Possibly broken PE file - Section %d out of file (Offset@ %d, Rsize %d, Total filesize %d, EP@ %d)\n", nsections - 1, EC32(section_hdr[nsections - 1].PointerToRawData), EC32(section_hdr[nsections - 1].SizeOfRawData), sb.st_size, ep); |
|
368 |
- broken = 1; |
|
369 |
- } |
|
370 |
- |
|
371 |
- if(broken) { |
|
372 | 357 |
free(section_hdr); |
358 |
+ if(DETECT_BROKEN) { |
|
359 |
+ if(virname) |
|
360 |
+ *virname = "Broken.Executable"; |
|
361 |
+ return CL_VIRUS; |
|
362 |
+ } |
|
373 | 363 |
return CL_CLEAN; |
374 | 364 |
} |
375 | 365 |
|
376 | 366 |
cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep); |
377 | 367 |
|
378 |
- |
|
379 | 368 |
/* UPX support */ |
380 | 369 |
|
381 | 370 |
/* try to find the first section with physical size == 0 */ |
... | ... |
@@ -559,8 +581,10 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c |
559 | 559 |
found = 2; |
560 | 560 |
|
561 | 561 |
lseek(desc, ep, SEEK_SET); |
562 |
- if(read(desc, buff, 200) != 200) |
|
562 |
+ if(read(desc, buff, 200) != 200) { |
|
563 |
+ free(section_hdr); |
|
563 | 564 |
return CL_EIO; |
565 |
+ } |
|
564 | 566 |
|
565 | 567 |
if(buff[0] != '\xb8' || cli_readint32(buff + 1) != EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(optional_hdr.ImageBase)) { |
566 | 568 |
if(buff[0] != '\xb8' || cli_readint32(buff + 1) != EC32(section_hdr[nsections - 2].VirtualAddress) + EC32(optional_hdr.ImageBase)) |
... | ... |
@@ -63,6 +63,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
63 | 63 |
{"TemporaryDirectory", OPT_STR}, |
64 | 64 |
{"MaxFileSize", OPT_COMPSIZE}, |
65 | 65 |
{"ScanPE", OPT_NOARG}, |
66 |
+ {"DetectBrokenExecutables", OPT_NOARG}, |
|
66 | 67 |
{"ScanMail", OPT_NOARG}, |
67 | 68 |
{"ScanHTML", OPT_NOARG}, |
68 | 69 |
{"ScanOLE2", OPT_NOARG}, |