Browse code

add PE dumper

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@556 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2004/05/12 08:30:57
Showing 7 changed files
... ...
@@ -1,3 +1,9 @@
1
+Wed May 12 01:27:56 CEST 2004 (tk)
2
+----------------------------------
3
+  * libclamav: initial PE parser/dumper (not yet activated). It will be
4
+	       connected with UPX and WinZIP SFX unpackers and a disassembler
5
+	       soon.
6
+
1 7
 Tue May 11 02:07:55 CEST 2004 (tk)
2 8
 ----------------------------------
3 9
   * libclamav: scanners: revert to old X-* magic strings
... ...
@@ -81,6 +81,8 @@ libclamav_la_SOURCES = \
81 81
 	vba_extract.h \
82 82
 	cltypes.h \
83 83
 	msexpand.c \
84
-	msexpand.h
84
+	msexpand.h \
85
+	pe.c \
86
+	pe.h
85 87
 
86 88
 lib_LTLIBRARIES = libclamav.la
... ...
@@ -182,7 +182,9 @@ libclamav_la_SOURCES = \
182 182
 	vba_extract.h \
183 183
 	cltypes.h \
184 184
 	msexpand.c \
185
-	msexpand.h
185
+	msexpand.h \
186
+	pe.c \
187
+	pe.h
186 188
 
187 189
 
188 190
 lib_LTLIBRARIES = libclamav.la
... ...
@@ -197,7 +199,8 @@ am_libclamav_la_OBJECTS = matcher.lo md5.lo others.lo readdb.lo cvd.lo \
197 197
 	dsig.lo str.lo scanners.lo unrarlib.lo zzip-dir.lo zzip-err.lo \
198 198
 	zzip-file.lo zzip-info.lo zzip-io.lo zzip-stat.lo zzip-zip.lo \
199 199
 	strc.lo blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo \
200
-	table.lo text.lo ole2_extract.lo vba_extract.lo msexpand.lo
200
+	table.lo text.lo ole2_extract.lo vba_extract.lo msexpand.lo \
201
+	pe.lo
201 202
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
202 203
 
203 204
 DEFS = @DEFS@
... ...
@@ -212,11 +215,11 @@ am__depfiles_maybe = depfiles
212 212
 @AMDEP_TRUE@	./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \
213 213
 @AMDEP_TRUE@	./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \
214 214
 @AMDEP_TRUE@	./$(DEPDIR)/ole2_extract.Plo ./$(DEPDIR)/others.Plo \
215
-@AMDEP_TRUE@	./$(DEPDIR)/readdb.Plo ./$(DEPDIR)/scanners.Plo \
216
-@AMDEP_TRUE@	./$(DEPDIR)/snprintf.Plo ./$(DEPDIR)/str.Plo \
217
-@AMDEP_TRUE@	./$(DEPDIR)/strc.Plo ./$(DEPDIR)/strrcpy.Plo \
218
-@AMDEP_TRUE@	./$(DEPDIR)/table.Plo ./$(DEPDIR)/text.Plo \
219
-@AMDEP_TRUE@	./$(DEPDIR)/unrarlib.Plo \
215
+@AMDEP_TRUE@	./$(DEPDIR)/pe.Plo ./$(DEPDIR)/readdb.Plo \
216
+@AMDEP_TRUE@	./$(DEPDIR)/scanners.Plo ./$(DEPDIR)/snprintf.Plo \
217
+@AMDEP_TRUE@	./$(DEPDIR)/str.Plo ./$(DEPDIR)/strc.Plo \
218
+@AMDEP_TRUE@	./$(DEPDIR)/strrcpy.Plo ./$(DEPDIR)/table.Plo \
219
+@AMDEP_TRUE@	./$(DEPDIR)/text.Plo ./$(DEPDIR)/unrarlib.Plo \
220 220
 @AMDEP_TRUE@	./$(DEPDIR)/vba_extract.Plo \
221 221
 @AMDEP_TRUE@	./$(DEPDIR)/zzip-dir.Plo ./$(DEPDIR)/zzip-err.Plo \
222 222
 @AMDEP_TRUE@	./$(DEPDIR)/zzip-file.Plo ./$(DEPDIR)/zzip-info.Plo \
... ...
@@ -294,6 +297,7 @@ distclean-compile:
294 294
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msexpand.Plo@am__quote@
295 295
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ole2_extract.Plo@am__quote@
296 296
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/others.Plo@am__quote@
297
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe.Plo@am__quote@
297 298
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdb.Plo@am__quote@
298 299
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanners.Plo@am__quote@
299 300
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snprintf.Plo@am__quote@
300 301
new file mode 100644
... ...
@@ -0,0 +1,276 @@
0
+/*
1
+ *  Copyright (C) 2004 Tomasz Kojm <tkojm@clamav.net>
2
+ *
3
+ *  Implementation (header structures) based on the PE format description
4
+ *  by B. Luevelsmeyer
5
+ *
6
+ *  This program is free software; you can redistribute it and/or modify
7
+ *  it under the terms of the GNU General Public License as published by
8
+ *  the Free Software Foundation; either version 2 of the License, or
9
+ *  (at your option) any later version.
10
+ *
11
+ *  This program is distributed in the hope that it will be useful,
12
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ *  GNU General Public License for more details.
15
+ *
16
+ *  You should have received a copy of the GNU General Public License
17
+ *  along with this program; if not, write to the Free Software
18
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
+ */
20
+
21
+#if HAVE_CONFIG_H
22
+#include "clamav-config.h"
23
+#endif
24
+
25
+#include <stdio.h>
26
+#include <string.h>
27
+#include <sys/types.h>
28
+#include <sys/stat.h>
29
+#include <fcntl.h>
30
+#include <sys/stat.h>
31
+#include <unistd.h>
32
+#include <time.h>
33
+
34
+#include "cltypes.h"
35
+#include "clamav.h"
36
+#include "others.h"
37
+
38
+#define IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
39
+#define IMAGE_NT_SIGNATURE	    0x00004550
40
+#define IMAGE_OPTIONAL_SIGNATURE    0x010b
41
+
42
+struct pe_image_file_hdr {
43
+    uint32_t Magic;
44
+    uint16_t Machine;
45
+    uint16_t NumberOfSections;
46
+    uint32_t TimeDateStamp;		    /* unreliable */
47
+    uint32_t PointerToSymbolTable;	    /* debug */
48
+    uint32_t NumberOfSymbols;		    /* debug */
49
+    uint16_t SizeOfOptionalHeader;	    /* == 224 */
50
+    uint16_t Characteristics;
51
+};
52
+
53
+struct pe_image_data_dir {
54
+    uint32_t VirtualAddress;
55
+    uint32_t Size;
56
+};
57
+
58
+struct pe_image_optional_hdr {
59
+    uint16_t Magic;
60
+    uint8_t  MajorLinkerVersion;		    /* unreliable */
61
+    uint8_t  MinorLinkerVersion;		    /* unreliable */
62
+    uint32_t SizeOfCode;			    /* unreliable */
63
+    uint32_t SizeOfInitializedData;		    /* unreliable */
64
+    uint32_t SizeOfUninitializedData;		    /* unreliable */
65
+    uint32_t AddressOfEntryPoint;
66
+    uint32_t BaseOfCode;
67
+    uint32_t BaseOfData;
68
+    uint32_t ImageBase;				    /* multiple of 64 KB */
69
+    uint32_t SectionAlignment;			    /* usually 32 or 4096 */
70
+    uint32_t FileAlignment;			    /* usually 32 or 512 */
71
+    uint16_t MajorOperatingSystemVersion;	    /* not used */
72
+    uint16_t MinorOperatingSystemVersion;	    /* not used */
73
+    uint16_t MajorImageVersion;			    /* unreliable */
74
+    uint16_t MinorImageVersion;			    /* unreliable */
75
+    uint16_t MajorSubsystemVersion;
76
+    uint16_t MinorSubsystemVersion;
77
+    uint32_t Win32VersionValue;			    /* ? */
78
+    uint32_t SizeOfImage;
79
+    uint32_t SizeOfHeaders;
80
+    uint32_t CheckSum;				    /* NT drivers only */
81
+    uint16_t Subsystem;
82
+    uint16_t DllCharacteristics;
83
+    uint32_t SizeOfStackReserve;
84
+    uint32_t SizeOfStackCommit;
85
+    uint32_t SizeOfHeapReserve;
86
+    uint32_t SizeOfHeapCommit;
87
+    uint32_t LoaderFlags;			    /* ? */
88
+    uint32_t NumberOfRvaAndSizes;		    /* unreliable */
89
+    struct pe_image_data_dir DataDirectory[16];
90
+};
91
+
92
+struct pe_image_section_hdr {
93
+    uint8_t Name[8];			    /* may not end with NULL */
94
+    /*
95
+    union {
96
+	uint32_t PhysicalAddress;
97
+	uint32_t VirtualSize;
98
+    } AddrSize;
99
+    */
100
+    uint32_t VirtualSize;
101
+    uint32_t VirtualAddress;
102
+    uint32_t SizeOfRawData;		    /* multiple of FileAlignment */
103
+    uint32_t PointerToRawData;		    /* offset to the section's data */
104
+    uint32_t PointerToRelocations;	    /* object files only */
105
+    uint32_t PointerToLinenumbers;	    /* object files only */
106
+    uint16_t NumberOfRelocations;	    /* object files only */
107
+    uint16_t NumberOfLinenumbers;	    /* object files only */
108
+    uint32_t Characteristics;
109
+};
110
+
111
+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)
112
+{
113
+	uint16_t e_magic; /* DOS signature ("MZ") */
114
+	uint32_t e_lfanew; /* address of new exe header */
115
+	struct pe_image_file_hdr file_hdr;
116
+	struct pe_image_optional_hdr optional_hdr;
117
+	struct pe_image_section_hdr section_hdr;
118
+	struct stat sb;
119
+	char sname[9];
120
+	int i;
121
+
122
+
123
+    if(read(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
124
+	cli_dbgmsg("Can't read DOS signature.\n");
125
+	return -1;
126
+    }
127
+
128
+    if(e_magic != IMAGE_DOS_SIGNATURE) {
129
+	cli_dbgmsg("Invalid DOS signature\n");
130
+	return -1;
131
+    }
132
+
133
+    lseek(desc, 58, SEEK_CUR); /* skip to the end of the DOS header */
134
+
135
+    if(read(desc, &e_lfanew, sizeof(e_lfanew)) != sizeof(e_lfanew)) {
136
+	cli_dbgmsg("Can't read new header address.\n");
137
+	return -1;
138
+    }
139
+
140
+    cli_dbgmsg("e_lfanew == %d\n", e_lfanew);
141
+    if(!e_lfanew) {
142
+	cli_dbgmsg("Not a PE file\n");
143
+	return -2;
144
+    }
145
+
146
+    lseek(desc, e_lfanew, SEEK_SET);
147
+
148
+    if(read(desc, &file_hdr, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
149
+	cli_dbgmsg("Can't read file header\n");
150
+	return -1;
151
+    }
152
+
153
+    if(file_hdr.Magic != IMAGE_NT_SIGNATURE) {
154
+	cli_dbgmsg("Invalid PE signature\n");
155
+	return -2;
156
+    }
157
+
158
+    cli_dbgmsg("Machine type: ");
159
+    switch(file_hdr.Machine) {
160
+	case 0x14c:
161
+	    cli_dbgmsg("80386\n");
162
+	    break;
163
+	case 0x014d:
164
+	    cli_dbgmsg("80486\n");
165
+	    break;
166
+	case 0x014e:
167
+	    cli_dbgmsg("80586\n");
168
+	    break;
169
+	case 0x162:
170
+	    cli_dbgmsg("R3000\n");
171
+	    break;
172
+	case 0x166:
173
+	    cli_dbgmsg("R4000\n");
174
+	    break;
175
+	case 0x168:
176
+	    cli_dbgmsg("R10000\n");
177
+	    break;
178
+	case 0x184:
179
+	    cli_dbgmsg("DEC Alpha AXP\n");
180
+	    break;
181
+	case 0x1f0:
182
+	    cli_dbgmsg("PowerPC\n");
183
+	    break;
184
+	default:
185
+	    cli_dbgmsg("Unknown\n");
186
+    }
187
+
188
+    cli_dbgmsg("NumberOfSections: %d\n", file_hdr.NumberOfSections);
189
+    cli_dbgmsg("TimeDateStamp: %s", ctime((time_t *) &file_hdr.TimeDateStamp));
190
+
191
+    cli_dbgmsg("SizeOfOptionalHeader: %d\n", file_hdr.SizeOfOptionalHeader);
192
+
193
+    if(file_hdr.SizeOfOptionalHeader != sizeof(struct pe_image_optional_hdr)) {
194
+	cli_warnmsg("Broken PE header detected.\n");
195
+	return -1;
196
+    }
197
+
198
+    if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) {
199
+	cli_dbgmsg("Can't optional file header\n");
200
+	return -1;
201
+    }
202
+
203
+    cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr.MajorLinkerVersion);
204
+    cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr.MinorLinkerVersion);
205
+    cli_dbgmsg("SizeOfCode: %d\n", optional_hdr.SizeOfCode);
206
+    cli_dbgmsg("SizeOfInitializedData: %d\n", optional_hdr.SizeOfInitializedData);
207
+    cli_dbgmsg("SizeOfUninitializedData: %d\n", optional_hdr.SizeOfUninitializedData);
208
+    cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", optional_hdr.AddressOfEntryPoint);
209
+    cli_dbgmsg("SectionAlignment: %d\n", optional_hdr.SectionAlignment);
210
+    cli_dbgmsg("FileAlignment: %d\n", optional_hdr.FileAlignment);
211
+    cli_dbgmsg("MajorSubsystemVersion: %d\n", optional_hdr.MajorSubsystemVersion);
212
+    cli_dbgmsg("MinorSubsystemVersion: %d\n", optional_hdr.MinorSubsystemVersion);
213
+    cli_dbgmsg("SizeOfImage: %d\n", optional_hdr.SizeOfImage);
214
+    cli_dbgmsg("SizeOfHeaders: %d\n", optional_hdr.SizeOfHeaders);
215
+
216
+    cli_dbgmsg("Subsystem: ");
217
+    switch(optional_hdr.Subsystem) {
218
+	case 1:
219
+	    cli_dbgmsg("Native (a driver ?)\n");
220
+	    break;
221
+	case 2:
222
+	    cli_dbgmsg("Win32 GUI\n");
223
+	    break;
224
+	case 3:
225
+	    cli_dbgmsg("Win32 console\n");
226
+	    break;
227
+	case 5:
228
+	    cli_dbgmsg("OS/2 console\n");
229
+	    break;
230
+	case 7:
231
+	    cli_dbgmsg("POSIX console\n");
232
+	    break;
233
+	default:
234
+	    cli_dbgmsg("Unknown\n");
235
+    }
236
+
237
+    cli_dbgmsg("NumberOfRvaAndSizes: %d\n", optional_hdr.NumberOfRvaAndSizes);
238
+
239
+    for(i = 0; i < file_hdr.NumberOfSections; i++) {
240
+
241
+	if(read(desc, &section_hdr, sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) {
242
+	    cli_dbgmsg("Can't read section header\n");
243
+	    return -1;
244
+	}
245
+
246
+	strncpy(sname, section_hdr.Name, 8);
247
+	sname[8] = 0;
248
+	cli_dbgmsg("------------------------------------\n");
249
+	cli_dbgmsg("Section name: %s\n", sname);
250
+	cli_dbgmsg("VirtualSize: %d\n", section_hdr.VirtualSize);
251
+	cli_dbgmsg("VirtualAddress: 0x%x\n", section_hdr.VirtualAddress);
252
+	cli_dbgmsg("Section size: %d\n", section_hdr.SizeOfRawData);
253
+	cli_dbgmsg("PointerToRawData: 0x%x (%d)\n", section_hdr.PointerToRawData, section_hdr.PointerToRawData);
254
+
255
+	if(section_hdr.Characteristics & 0x20)
256
+	    cli_dbgmsg("Section contains executable code.\n");
257
+
258
+	if(section_hdr.Characteristics & 0x20000000)
259
+	    cli_dbgmsg("Section's memory is executable.\n");
260
+    }
261
+
262
+    if(fstat(desc, &sb) == -1) {
263
+	cli_dbgmsg("stat failed\n");
264
+	return -1;
265
+    }
266
+
267
+    if(section_hdr.PointerToRawData + section_hdr.SizeOfRawData > sb.st_size) {
268
+	cli_warnmsg("Possibly broken PE file\n");
269
+	return -1;
270
+    }
271
+
272
+    /* to be continued ... */
273
+
274
+    return 0;
275
+}
0 276
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+/*
1
+ *  Copyright (C) 2004 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 __PE_H
19
+#define __PE_H
20
+
21
+#include "clamav.h"
22
+
23
+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
+
25
+#endif
... ...
@@ -71,6 +71,10 @@ struct cli_magic_s {
71 71
 #define MAGIC_BUFFER_SIZE 26
72 72
 static const struct cli_magic_s cli_magic[] = {
73 73
 
74
+    /* Executables */
75
+
76
+    /* {0,  "MZ",				2,  "DOS/W32 executable", CL_DOSEXE}, */
77
+
74 78
     /* Archives */
75 79
 
76 80
     {0,  "Rar!",			4,  "RAR",		  CL_RARFILE},
... ...
@@ -984,6 +988,11 @@ static int cli_magic_scandesc(int desc, const char **virname, long int *scanned,
984 984
     type = cli_filetype(magic, bread);
985 985
 
986 986
     switch(type) {
987
+	case CL_DOSEXE:
988
+	    /* temporarily the return code is ignored */
989
+	    cli_scanpe(desc, virname, scanned, root, limits, options, reclev);
990
+	    break;
991
+
987 992
 	case CL_RARFILE:
988 993
 	    if(!DISABLE_RAR && SCAN_ARCHIVE && !cli_scanrar_inuse)
989 994
 		ret = cli_scanrar(desc, virname, scanned, root, limits, options, reclev);
... ...
@@ -22,6 +22,7 @@
22 22
 
23 23
 typedef enum {
24 24
     CL_UNKNOWN_TYPE = 0,
25
+    CL_DOSEXE,
25 26
     CL_DATAFILE,
26 27
     CL_MAILFILE,
27 28
     CL_GZFILE,