Browse code

add support for ELF files in signatures

git-svn: trunk@1723

Tomasz Kojm authored on 2005/09/19 08:19:28
Showing 8 changed files
... ...
@@ -1,3 +1,9 @@
1
+Mon Sep 19 01:15:02 CEST 2005 (tk)
2
+----------------------------------
3
+  * libclamav/elf.c: add cli_elfheader()
4
+  * libclamav/execs.h: new file
5
+  * libclamav/matcher.c: support ELF files in cli_caloff()
6
+
1 7
 Fri Sep 16 16:49:14 CEST 2005 (tk)
2 8
 ----------------------------------
3 9
   * libclamav/upx.c: fix possible buffer overflow (acab)
... ...
@@ -142,7 +142,8 @@ libclamav_la_SOURCES = \
142 142
 	spin.c \
143 143
 	spin.h \
144 144
 	elf.c \
145
-	elf.h
145
+	elf.h \
146
+	execs.h
146 147
 
147 148
 
148 149
 lib_LTLIBRARIES = libclamav.la
... ...
@@ -32,6 +32,7 @@
32 32
 #include "cltypes.h"
33 33
 #include "elf.h"
34 34
 #include "clamav.h"
35
+#include "execs.h"
35 36
 
36 37
 #define DETECT_BROKEN		    (options & CL_SCAN_BLOCKBROKEN)
37 38
 
... ...
@@ -61,7 +62,7 @@ int cli_scanelf(int desc, const char **virname, long int *scanned, const struct
61 61
 	uint32_t entry, shoff, image;
62 62
 	int i;
63 63
 
64
-    cli_dbgmsg("in cli_elfheader\n");
64
+    cli_dbgmsg("in cli_scanelf\n");
65 65
 
66 66
     if(read(desc, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
67 67
 	/* Not an ELF file? */
... ...
@@ -75,7 +76,7 @@ int cli_scanelf(int desc, const char **virname, long int *scanned, const struct
75 75
     }
76 76
 
77 77
     if(file_hdr.e_ident[4] != 1) {
78
-	cli_dbgmsg("ELF: 64-bit binaries not supported\n");
78
+	cli_dbgmsg("ELF: 64-bit binaries are not supported (yet)\n");
79 79
 	return CL_CLEAN;
80 80
     }
81 81
 
... ...
@@ -180,7 +181,7 @@ int cli_scanelf(int desc, const char **virname, long int *scanned, const struct
180 180
 
181 181
     shentsize = EC16(file_hdr.e_shentsize);
182 182
     if(shentsize != sizeof(struct elf_section_hdr32)) {
183
-	cli_errmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
183
+	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
184 184
         if(DETECT_BROKEN) {
185 185
 	    if(virname)
186 186
             *virname = "Broken.Executable";
... ...
@@ -225,6 +226,7 @@ int cli_scanelf(int desc, const char **virname, long int *scanned, const struct
225 225
 
226 226
 	cli_dbgmsg("ELF: Section %d\n", i);
227 227
 	cli_dbgmsg("ELF: Section offset: %d\n", EC32(section_hdr[i].sh_offset));
228
+	cli_dbgmsg("ELF: Section size: %d\n", EC32(section_hdr[i].sh_size));
228 229
 
229 230
 	switch(EC32(section_hdr[i].sh_type)) {
230 231
 	    case 0x6: /* SHT_DYNAMIC */
... ...
@@ -297,3 +299,91 @@ int cli_scanelf(int desc, const char **virname, long int *scanned, const struct
297 297
     free(section_hdr);
298 298
     return CL_CLEAN;
299 299
 }
300
+
301
+int cli_elfheader(int desc, struct cli_exe_info *elfinfo)
302
+{
303
+	struct elf_file_hdr32 file_hdr;
304
+	struct elf_section_hdr32 *section_hdr;
305
+	uint16_t shnum, shentsize;
306
+	uint32_t entry, shoff, image;
307
+	int i;
308
+
309
+    cli_dbgmsg("in cli_elfheader\n");
310
+
311
+    if(read(desc, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
312
+	/* Not an ELF file? */
313
+	cli_dbgmsg("ELF: Can't read file header\n");
314
+	return -1;
315
+    }
316
+
317
+    if(memcmp(file_hdr.e_ident, "\x7f\x45\x4c\x46", 4)) {
318
+	cli_dbgmsg("ELF: Not an ELF file\n");
319
+	return -1;
320
+    }
321
+
322
+    if(file_hdr.e_ident[4] != 1) {
323
+	cli_dbgmsg("ELF: 64-bit binaries are not supported (yet)\n");
324
+	return -1;
325
+    }
326
+
327
+    if(file_hdr.e_ident[5] == 1) {
328
+	image =  0x8048000;
329
+#if WORDS_BIGENDIAN == 1
330
+	need_conversion = 1;
331
+#endif
332
+    } else {
333
+	image =  0x10000;
334
+#if WORDS_BIGENDIAN == 0
335
+	need_conversion = 1;
336
+#endif
337
+    }
338
+
339
+    entry = EC32(file_hdr.e_entry);
340
+
341
+    shnum = EC16(file_hdr.e_shnum);
342
+    if(shnum > 256) {
343
+	cli_dbgmsg("ELF: Suspicious number of sections\n");
344
+	return -1;
345
+    }
346
+    elfinfo->nsections = shnum;
347
+
348
+    shentsize = EC16(file_hdr.e_shentsize);
349
+    if(shentsize != sizeof(struct elf_section_hdr32)) {
350
+	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
351
+	return -1;
352
+    }
353
+
354
+    shoff = EC32(file_hdr.e_shoff);
355
+    if(lseek(desc, shoff, SEEK_SET) != shoff) {
356
+	/* Possibly broken end of file */
357
+	return -1;
358
+    }
359
+
360
+    elfinfo->section = (struct cli_exe_section *) cli_calloc(elfinfo->nsections, sizeof(struct cli_exe_section));
361
+    if(!elfinfo->section) {
362
+	cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
363
+	return -1;
364
+    }
365
+
366
+    section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
367
+    if(!section_hdr) {
368
+	cli_errmsg("ELF: Can't allocate memory for section headers\n");
369
+	return -1;
370
+    }
371
+
372
+    for(i = 0; i < shnum; i++) {
373
+
374
+	if(read(desc, &section_hdr[i], sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32)) {
375
+            free(section_hdr);
376
+	    free(elfinfo->section);
377
+            return -1;
378
+        }
379
+
380
+	elfinfo->section[i].rva = EC32(section_hdr[i].sh_addr);
381
+	elfinfo->section[i].raw = EC32(section_hdr[i].sh_offset);
382
+	elfinfo->section[i].rsz = EC32(section_hdr[i].sh_size);
383
+    }
384
+
385
+    free(section_hdr);
386
+    return 0;
387
+}
... ...
@@ -24,6 +24,7 @@
24 24
 
25 25
 #include "cltypes.h"
26 26
 #include "clamav.h"
27
+#include "execs.h"
27 28
 
28 29
 struct elf_file_hdr32 {
29 30
     unsigned char e_ident[16];
... ...
@@ -57,4 +58,6 @@ struct elf_section_hdr32 {
57 57
 
58 58
 int cli_scanelf(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec);
59 59
 
60
+int cli_elfheader(int desc, struct cli_exe_info *elfinfo);
61
+
60 62
 #endif
61 63
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+/*
1
+ *  Copyright (C) 2005 Tomasz Kojm <tkojm@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 __EXECS_H
19
+#define __EXECS_H
20
+
21
+#include "cltypes.h"
22
+
23
+struct cli_exe_section {
24
+    uint32_t rva;
25
+    uint32_t vsz;
26
+    uint32_t raw;
27
+    uint32_t rsz;
28
+};
29
+
30
+struct cli_exe_info {
31
+    uint32_t ep;
32
+    uint16_t nsections;
33
+    struct cli_exe_section *section;
34
+};
35
+
36
+#endif
... ...
@@ -34,12 +34,14 @@
34 34
 #include "filetypes.h"
35 35
 #include "matcher.h"
36 36
 #include "pe.h"
37
+#include "elf.h"
38
+#include "execs.h"
37 39
 #include "special.h"
38 40
 
39 41
 #define MD5_BLOCKSIZE 4096
40 42
 
41
-#define TARGET_TABLE_SIZE 6
42
-static int targettab[TARGET_TABLE_SIZE] = { 0, CL_TYPE_MSEXE, CL_TYPE_MSOLE2, CL_TYPE_HTML, CL_TYPE_MAIL, CL_TYPE_GRAPHICS };
43
+#define TARGET_TABLE_SIZE 7
44
+static int targettab[TARGET_TABLE_SIZE] = { 0, CL_TYPE_MSEXE, CL_TYPE_MSOLE2, CL_TYPE_HTML, CL_TYPE_MAIL, CL_TYPE_GRAPHICS, CL_TYPE_ELF };
43 45
 
44 46
 extern short cli_debug_flag;
45 47
 
... ...
@@ -96,40 +98,47 @@ static struct cli_md5_node *cli_vermd5(const unsigned char *md5, const struct cl
96 96
     return NULL;
97 97
 }
98 98
 
99
-static long int cli_caloff(const char *offstr, int fd)
99
+static long int cli_caloff(const char *offstr, int fd, unsigned short ftype)
100 100
 {
101
-	struct cli_pe_info peinfo;
101
+	struct cli_exe_info exeinfo;
102
+	int (*einfo)(int, struct cli_exe_info *) = NULL;
102 103
 	long int offset = -1;
103 104
 	int n;
104 105
 
105 106
 
107
+    if(ftype == CL_TYPE_MSEXE)
108
+	einfo = cli_peheader;
109
+    else if(ftype == CL_TYPE_ELF)
110
+	einfo = cli_elfheader;
111
+
106 112
     if(isdigit(offstr[0])) {
107 113
 	return atoi(offstr);
108
-    } if(!strncmp(offstr, "EP+", 3) || !strncmp(offstr, "EP-", 3)) {
114
+
115
+    } else if(einfo && (!strncmp(offstr, "EP+", 3) || !strncmp(offstr, "EP-", 3))) {
109 116
 	if((n = lseek(fd, 0, SEEK_CUR)) == -1) {
110 117
 	    cli_dbgmsg("Invalid descriptor\n");
111 118
 	    return -1;
112 119
 	}
113 120
 	lseek(fd, 0, SEEK_SET);
114
-	if(cli_peheader(fd, &peinfo)) {
121
+	if(einfo(fd, &exeinfo)) {
115 122
 	    lseek(fd, n, SEEK_SET);
116 123
 	    return -1;
117 124
 	}
118
-	free(peinfo.section);
125
+	free(exeinfo.section);
119 126
 	lseek(fd, n, SEEK_SET);
120 127
 
121 128
 	if(offstr[2] == '+')
122
-	    return peinfo.ep + atoi(offstr + 3);
129
+	    return exeinfo.ep + atoi(offstr + 3);
123 130
 	else
124
-	    return peinfo.ep - atoi(offstr + 3);
131
+	    return exeinfo.ep - atoi(offstr + 3);
125 132
 
126
-    } else if(offstr[0] == 'S') {
133
+    } else if(einfo && offstr[0] == 'S') {
127 134
 	if((n = lseek(fd, 0, SEEK_CUR)) == -1) {
128 135
 	    cli_dbgmsg("Invalid descriptor\n");
129 136
 	    return -1;
130 137
 	}
131 138
 	lseek(fd, 0, SEEK_SET);
132
-	if(cli_peheader(fd, &peinfo)) {
139
+	if(einfo(fd, &exeinfo)) {
133 140
 	    lseek(fd, n, SEEK_SET);
134 141
 	    return -1;
135 142
 	}
... ...
@@ -138,28 +147,28 @@ static long int cli_caloff(const char *offstr, int fd)
138 138
 	if(!strncmp(offstr, "SL", 2)) {
139 139
 
140 140
 	    if(sscanf(offstr, "SL+%ld", &offset) != 1) {
141
-		free(peinfo.section);
141
+		free(exeinfo.section);
142 142
 		return -1;
143 143
 	    }
144 144
 
145
-	    offset += peinfo.section[peinfo.nsections - 1].raw;
145
+	    offset += exeinfo.section[exeinfo.nsections - 1].raw;
146 146
 
147 147
 	} else {
148 148
 
149 149
 	    if(sscanf(offstr, "S%d+%ld", &n, &offset) != 2) {
150
-		free(peinfo.section);
150
+		free(exeinfo.section);
151 151
 		return -1;
152 152
 	    }
153 153
 
154
-	    if(n >= peinfo.nsections) {
155
-		free(peinfo.section);
154
+	    if(n >= exeinfo.nsections) {
155
+		free(exeinfo.section);
156 156
 		return -1;
157 157
 	    }
158 158
 
159
-	    offset += peinfo.section[n].raw;
159
+	    offset += exeinfo.section[n].raw;
160 160
 	}
161 161
 
162
-	free(peinfo.section);
162
+	free(exeinfo.section);
163 163
 	return offset;
164 164
 
165 165
     } else if(!strncmp(offstr, "EOF-", 4)) {
... ...
@@ -226,7 +235,7 @@ int cli_validatesig(unsigned short target, unsigned short ftype, const char *off
226 226
     }
227 227
 
228 228
     if(offstr && desc != -1) {
229
-	    long int off = cli_caloff(offstr, desc);
229
+	    long int off = cli_caloff(offstr, desc, ftype);
230 230
 
231 231
 	if(off == -1) {
232 232
 	    cli_dbgmsg("Bad offset in signature (%s)\n", virname);
... ...
@@ -42,6 +42,7 @@
42 42
 #include "scanners.h"
43 43
 #include "rebuildpe.h"
44 44
 #include "str.h"
45
+#include "execs.h"
45 46
 
46 47
 #define IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
47 48
 #define IMAGE_DOS_SIGNATURE_OLD	    0x4d5a          /* ZM */
... ...
@@ -1479,7 +1480,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1479 1479
     return CL_CLEAN;
1480 1480
 }
1481 1481
 
1482
-int cli_peheader(int desc, struct cli_pe_info *peinfo)
1482
+int cli_peheader(int desc, struct cli_exe_info *peinfo)
1483 1483
 {
1484 1484
 	uint16_t e_magic; /* DOS signature ("MZ") */
1485 1485
 	uint32_t e_lfanew; /* address of new exe header */
... ...
@@ -1547,7 +1548,7 @@ int cli_peheader(int desc, struct cli_pe_info *peinfo)
1547 1547
 	return -1;
1548 1548
     }
1549 1549
 
1550
-    peinfo->section = (struct SECTION *) cli_calloc(peinfo->nsections, sizeof(struct SECTION));
1550
+    peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
1551 1551
 
1552 1552
     if(!peinfo->section) {
1553 1553
 	cli_dbgmsg("Can't allocate memory for section headers\n");
... ...
@@ -23,7 +23,7 @@
23 23
 #define __PE_H
24 24
 
25 25
 #include "clamav.h"
26
-#include "rebuildpe.h"
26
+#include "execs.h"
27 27
 
28 28
 struct pe_image_file_hdr {
29 29
     uint32_t Magic;
... ...
@@ -94,14 +94,8 @@ struct pe_image_section_hdr {
94 94
     uint32_t Characteristics;
95 95
 };
96 96
 
97
-struct cli_pe_info {
98
-    uint32_t ep; /* raw entry point */
99
-    uint16_t nsections;
100
-    struct SECTION *section;
101
-};
102
-
103 97
 int cli_scanpe(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec);
104 98
 
105
-int cli_peheader(int desc, struct cli_pe_info *peinfo);
99
+int cli_peheader(int desc, struct cli_exe_info *peinfo);
106 100
 
107 101
 #endif