git-svn: trunk@2448
Tomasz Kojm authored on 2006/10/29 05:46:32... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Sat Oct 28 22:44:46 CEST 2006 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav/elf.c: parse program headers and properly calculate file offset |
|
4 |
+ of entry point |
|
5 |
+ |
|
1 | 6 |
Sat Oct 28 16:56:51 BST 2006 (njh) |
2 | 7 |
---------------------------------- |
3 | 8 |
* clamav-milter: Fix file descriptor leak when more than one email is |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2005 Tomasz Kojm <tkojm@clamav.net> |
|
2 |
+ * Copyright (C) 2005 - 2006 Tomasz Kojm <tkojm@clamav.net> |
|
3 | 3 |
* |
4 | 4 |
* This program is free software; you can redistribute it and/or modify |
5 | 5 |
* it under the terms of the GNU General Public License as published by |
... | ... |
@@ -53,14 +53,36 @@ static inline uint32_t EC32(uint32_t v, uint8_t c) |
53 | 53 |
return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24)); |
54 | 54 |
} |
55 | 55 |
|
56 |
+static uint32_t cli_rawaddr(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16_t phnum, uint8_t conv, uint8_t *err) |
|
57 |
+{ |
|
58 |
+ uint16_t i, found = 0; |
|
59 |
+ |
|
60 |
+ |
|
61 |
+ for(i = 0; i < phnum; i++) { |
|
62 |
+ if(EC32(ph[i].p_vaddr, conv) <= vaddr && EC32(ph[i].p_vaddr, conv) + EC32(ph[i].p_memsz, conv) > vaddr) { |
|
63 |
+ found = 1; |
|
64 |
+ break; |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ if(!found) { |
|
69 |
+ *err = 1; |
|
70 |
+ return 0; |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ *err = 0; |
|
74 |
+ return vaddr - EC32(ph[i].p_vaddr, conv) + EC32(ph[i].p_offset, conv); |
|
75 |
+} |
|
76 |
+ |
|
56 | 77 |
int cli_scanelf(int desc, cli_ctx *ctx) |
57 | 78 |
{ |
58 | 79 |
struct elf_file_hdr32 file_hdr; |
59 | 80 |
struct elf_section_hdr32 *section_hdr; |
60 |
- uint16_t shnum, shentsize; |
|
61 |
- uint32_t entry, shoff, image; |
|
62 |
- uint8_t conv = 0; |
|
63 |
- int i; |
|
81 |
+ struct elf_program_hdr32 *program_hdr; |
|
82 |
+ uint16_t shnum, phnum, shentsize, phentsize; |
|
83 |
+ uint32_t entry, fentry, shoff, phoff, i; |
|
84 |
+ uint8_t conv = 0, err; |
|
85 |
+ |
|
64 | 86 |
|
65 | 87 |
cli_dbgmsg("in cli_scanelf\n"); |
66 | 88 |
|
... | ... |
@@ -81,7 +103,6 @@ int cli_scanelf(int desc, cli_ctx *ctx) |
81 | 81 |
} |
82 | 82 |
|
83 | 83 |
if(file_hdr.e_ident[5] == 1) { |
84 |
- image = 0x8048000; |
|
85 | 84 |
#if WORDS_BIGENDIAN == 0 |
86 | 85 |
cli_dbgmsg("ELF: File is little-endian - conversion not required\n"); |
87 | 86 |
#else |
... | ... |
@@ -89,7 +110,6 @@ int cli_scanelf(int desc, cli_ctx *ctx) |
89 | 89 |
conv = 1; |
90 | 90 |
#endif |
91 | 91 |
} else { |
92 |
- image = 0x10000; |
|
93 | 92 |
#if WORDS_BIGENDIAN == 0 |
94 | 93 |
cli_dbgmsg("ELF: File is big-endian - data conversion enabled\n"); |
95 | 94 |
conv = 1; |
... | ... |
@@ -164,8 +184,92 @@ int cli_scanelf(int desc, cli_ctx *ctx) |
164 | 164 |
} |
165 | 165 |
|
166 | 166 |
entry = EC32(file_hdr.e_entry, conv); |
167 |
- cli_dbgmsg("ELF: Entry point address: 0x%.8x\n", entry); |
|
168 |
- cli_dbgmsg("ELF: Entry point offset: 0x%.8x (%d)\n", entry - image, entry - image); |
|
167 |
+ |
|
168 |
+ /* Program headers */ |
|
169 |
+ |
|
170 |
+ phnum = EC16(file_hdr.e_phnum, conv); |
|
171 |
+ cli_dbgmsg("ELF: Number of program headers: %d\n", phnum); |
|
172 |
+ if(phnum > 128) { |
|
173 |
+ cli_dbgmsg("ELF: Suspicious number of program headers\n"); |
|
174 |
+ if(DETECT_BROKEN) { |
|
175 |
+ if(ctx->virname) |
|
176 |
+ *ctx->virname = "Broken.Executable"; |
|
177 |
+ return CL_VIRUS; |
|
178 |
+ } |
|
179 |
+ return CL_EFORMAT; |
|
180 |
+ } |
|
181 |
+ |
|
182 |
+ if(phnum && entry) { |
|
183 |
+ |
|
184 |
+ phentsize = EC16(file_hdr.e_phentsize, conv); |
|
185 |
+ if(phentsize != sizeof(struct elf_program_hdr32)) { |
|
186 |
+ cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n"); |
|
187 |
+ if(DETECT_BROKEN) { |
|
188 |
+ if(ctx->virname) |
|
189 |
+ *ctx->virname = "Broken.Executable"; |
|
190 |
+ return CL_VIRUS; |
|
191 |
+ } |
|
192 |
+ return CL_EFORMAT; |
|
193 |
+ } |
|
194 |
+ |
|
195 |
+ phoff = EC32(file_hdr.e_phoff, conv); |
|
196 |
+ cli_dbgmsg("ELF: Program header table offset: %d\n", phoff); |
|
197 |
+ if((uint32_t) lseek(desc, phoff, SEEK_SET) != phoff) { |
|
198 |
+ if(DETECT_BROKEN) { |
|
199 |
+ if(ctx->virname) |
|
200 |
+ *ctx->virname = "Broken.Executable"; |
|
201 |
+ return CL_VIRUS; |
|
202 |
+ } |
|
203 |
+ return CL_CLEAN; |
|
204 |
+ } |
|
205 |
+ |
|
206 |
+ program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, phentsize); |
|
207 |
+ if(!program_hdr) { |
|
208 |
+ cli_errmsg("ELF: Can't allocate memory for program headers\n"); |
|
209 |
+ return CL_EMEM; |
|
210 |
+ } |
|
211 |
+ |
|
212 |
+ cli_dbgmsg("------------------------------------\n"); |
|
213 |
+ |
|
214 |
+ for(i = 0; i < phnum; i++) { |
|
215 |
+ |
|
216 |
+ if(read(desc, &program_hdr[i], sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32)) { |
|
217 |
+ cli_dbgmsg("ELF: Can't read segment #%d\n", i); |
|
218 |
+ cli_dbgmsg("ELF: Possibly broken ELF file\n"); |
|
219 |
+ free(program_hdr); |
|
220 |
+ if(DETECT_BROKEN) { |
|
221 |
+ if(ctx->virname) |
|
222 |
+ *ctx->virname = "Broken.Executable"; |
|
223 |
+ return CL_VIRUS; |
|
224 |
+ } |
|
225 |
+ return CL_CLEAN; |
|
226 |
+ } |
|
227 |
+ |
|
228 |
+ cli_dbgmsg("ELF: Segment #%d\n", i); |
|
229 |
+ cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv)); |
|
230 |
+ cli_dbgmsg("ELF: Segment offset: 0x%x\n", EC32(program_hdr[i].p_offset, conv)); |
|
231 |
+ cli_dbgmsg("ELF: Segment virtual address: 0x%x\n", EC32(program_hdr[i].p_vaddr, conv)); |
|
232 |
+ cli_dbgmsg("ELF: Segment real size: 0x%x\n", EC32(program_hdr[i].p_filesz, conv)); |
|
233 |
+ cli_dbgmsg("ELF: Segment virtual size: 0x%x\n", EC32(program_hdr[i].p_memsz, conv)); |
|
234 |
+ cli_dbgmsg("------------------------------------\n"); |
|
235 |
+ } |
|
236 |
+ |
|
237 |
+ fentry = cli_rawaddr(entry, program_hdr, phnum, conv, &err); |
|
238 |
+ free(program_hdr); |
|
239 |
+ if(err) { |
|
240 |
+ cli_dbgmsg("ELF: Can't calculate file offset of entry point\n"); |
|
241 |
+ if(DETECT_BROKEN) { |
|
242 |
+ if(ctx->virname) |
|
243 |
+ *ctx->virname = "Broken.Executable"; |
|
244 |
+ return CL_VIRUS; |
|
245 |
+ } |
|
246 |
+ return CL_EFORMAT; |
|
247 |
+ } |
|
248 |
+ cli_dbgmsg("ELF: Entry point address: 0x%.8x\n", entry); |
|
249 |
+ cli_dbgmsg("ELF: Entry point offset: 0x%.8x (%d)\n", fentry, fentry); |
|
250 |
+ } |
|
251 |
+ |
|
252 |
+ /* Sections */ |
|
169 | 253 |
|
170 | 254 |
shnum = EC16(file_hdr.e_shnum, conv); |
171 | 255 |
cli_dbgmsg("ELF: Number of sections: %d\n", shnum); |
... | ... |
@@ -304,10 +408,11 @@ int cli_elfheader(int desc, struct cli_exe_info *elfinfo) |
304 | 304 |
{ |
305 | 305 |
struct elf_file_hdr32 file_hdr; |
306 | 306 |
struct elf_section_hdr32 *section_hdr; |
307 |
- uint16_t shnum, shentsize; |
|
308 |
- uint32_t entry, shoff, image; |
|
309 |
- uint8_t conv = 0; |
|
310 |
- int i; |
|
307 |
+ struct elf_program_hdr32 *program_hdr; |
|
308 |
+ uint16_t shnum, phnum, shentsize, phentsize, i; |
|
309 |
+ uint32_t entry, fentry = 0, shoff, phoff; |
|
310 |
+ uint8_t conv = 0, err; |
|
311 |
+ |
|
311 | 312 |
|
312 | 313 |
cli_dbgmsg("in cli_elfheader\n"); |
313 | 314 |
|
... | ... |
@@ -328,19 +433,58 @@ int cli_elfheader(int desc, struct cli_exe_info *elfinfo) |
328 | 328 |
} |
329 | 329 |
|
330 | 330 |
if(file_hdr.e_ident[5] == 1) { |
331 |
- image = 0x8048000; |
|
332 | 331 |
#if WORDS_BIGENDIAN == 1 |
333 | 332 |
conv = 1; |
334 | 333 |
#endif |
335 | 334 |
} else { |
336 |
- image = 0x10000; |
|
337 | 335 |
#if WORDS_BIGENDIAN == 0 |
338 | 336 |
conv = 1; |
339 | 337 |
#endif |
340 | 338 |
} |
341 | 339 |
|
340 |
+ phnum = EC16(file_hdr.e_phnum, conv); |
|
341 |
+ if(phnum > 128) { |
|
342 |
+ cli_dbgmsg("ELF: Suspicious number of program headers\n"); |
|
343 |
+ return -1; |
|
344 |
+ } |
|
342 | 345 |
entry = EC32(file_hdr.e_entry, conv); |
343 | 346 |
|
347 |
+ if(phnum && entry) { |
|
348 |
+ phentsize = EC16(file_hdr.e_phentsize, conv); |
|
349 |
+ if(phentsize != sizeof(struct elf_program_hdr32)) { |
|
350 |
+ cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n"); |
|
351 |
+ return -1; |
|
352 |
+ } |
|
353 |
+ |
|
354 |
+ phoff = EC32(file_hdr.e_phoff, conv); |
|
355 |
+ if((uint32_t) lseek(desc, phoff, SEEK_SET) != phoff) { |
|
356 |
+ return -1; |
|
357 |
+ } |
|
358 |
+ |
|
359 |
+ program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, phentsize); |
|
360 |
+ if(!program_hdr) { |
|
361 |
+ cli_errmsg("ELF: Can't allocate memory for program headers\n"); |
|
362 |
+ return -1; |
|
363 |
+ } |
|
364 |
+ |
|
365 |
+ for(i = 0; i < phnum; i++) { |
|
366 |
+ if(read(desc, &program_hdr[i], sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32)) { |
|
367 |
+ cli_dbgmsg("ELF: Can't read segment #%d\n", i); |
|
368 |
+ free(program_hdr); |
|
369 |
+ return -1; |
|
370 |
+ } |
|
371 |
+ } |
|
372 |
+ |
|
373 |
+ fentry = cli_rawaddr(entry, program_hdr, phnum, conv, &err); |
|
374 |
+ free(program_hdr); |
|
375 |
+ if(err) { |
|
376 |
+ cli_dbgmsg("ELF: Can't calculate file offset of entry point\n"); |
|
377 |
+ return -1; |
|
378 |
+ } |
|
379 |
+ } |
|
380 |
+ |
|
381 |
+ elfinfo->ep = fentry; |
|
382 |
+ |
|
344 | 383 |
shnum = EC16(file_hdr.e_shnum, conv); |
345 | 384 |
if(shnum > 256) { |
346 | 385 |
cli_dbgmsg("ELF: Suspicious number of sections\n"); |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2005 Tomasz Kojm <tkojm@clamav.net> |
|
2 |
+ * Copyright (C) 2005 - 2006 Tomasz Kojm <tkojm@clamav.net> |
|
3 | 3 |
* |
4 | 4 |
* Header structures based on ELF: Executable and Linkable Format, Portable |
5 | 5 |
* Formats Specification, Version 1.1 |
... | ... |
@@ -45,6 +45,17 @@ struct elf_file_hdr32 { |
45 | 45 |
uint16_t e_shstrndx; |
46 | 46 |
}; |
47 | 47 |
|
48 |
+struct elf_program_hdr32 { |
|
49 |
+ uint32_t p_type; |
|
50 |
+ uint32_t p_offset; |
|
51 |
+ uint32_t p_vaddr; |
|
52 |
+ uint32_t p_paddr; |
|
53 |
+ uint32_t p_filesz; |
|
54 |
+ uint32_t p_memsz; |
|
55 |
+ uint32_t p_flags; |
|
56 |
+ uint32_t p_align; |
|
57 |
+}; |
|
58 |
+ |
|
48 | 59 |
struct elf_section_hdr32 { |
49 | 60 |
uint32_t sh_name; |
50 | 61 |
uint32_t sh_type; |