git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@2448 77e5149b-7576-45b1-b177-96237e5ba77b
| ... | ... |
@@ -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; |