mirror of https://github.com/Cisco-Talos/clamav
parent
85883a0248
commit
6ed894e099
@ -0,0 +1,273 @@ |
||||
/*
|
||||
* Copyright (C) 2005 Tomasz Kojm <tkojm@clamav.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#if HAVE_CONFIG_H |
||||
#include "clamav-config.h" |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <sys/stat.h> |
||||
#include <unistd.h> |
||||
#include <time.h> |
||||
|
||||
#include "cltypes.h" |
||||
#include "elf.h" |
||||
#include "clamav.h" |
||||
|
||||
#define DETECT_BROKEN (options & CL_SCAN_BLOCKBROKEN) |
||||
|
||||
#if WORDS_BIGENDIAN == 0 |
||||
#define EC16(v) (v) |
||||
#define EC32(v) (v) |
||||
#else |
||||
static inline uint16_t EC16(uint16_t v) |
||||
{ |
||||
return ((v >> 8) + (v << 8)); |
||||
} |
||||
|
||||
static inline uint32_t EC32(uint32_t v) |
||||
{ |
||||
return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24)); |
||||
} |
||||
#endif |
||||
|
||||
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) |
||||
{ |
||||
struct elf_file_hdr32 file_hdr; |
||||
struct elf_section_hdr32 *section_hdr; |
||||
uint16_t shnum, shentsize; |
||||
uint32_t entry, shoff; |
||||
int i; |
||||
|
||||
cli_dbgmsg("in cli_elfheader\n"); |
||||
|
||||
if(read(desc, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { |
||||
/* Not an ELF file? */ |
||||
cli_dbgmsg("ELF: Can't read file header\n"); |
||||
return CL_CLEAN; |
||||
} |
||||
|
||||
if(memcmp(file_hdr.e_ident, "\x7f\x45\x4c\x46", 4)) { |
||||
cli_dbgmsg("ELF: Not an ELF file\n"); |
||||
return CL_CLEAN; |
||||
} |
||||
|
||||
switch(EC16(file_hdr.e_type)) { |
||||
case 0x0: /* ET_NONE */ |
||||
cli_dbgmsg("ELF: File type: None\n"); |
||||
break; |
||||
case 0x1: /* ET_REL */ |
||||
cli_dbgmsg("ELF: File type: Relocatable\n"); |
||||
break; |
||||
case 0x2: /* ET_EXEC */ |
||||
cli_dbgmsg("ELF: File type: Executable\n"); |
||||
break; |
||||
case 0x3: /* ET_DYN */ |
||||
cli_dbgmsg("ELF: File type: Core\n"); |
||||
break; |
||||
case 0x4: /* ET_CORE */ |
||||
cli_dbgmsg("ELF: File type: Core\n"); |
||||
break; |
||||
default: |
||||
cli_dbgmsg("ELF: File type: Unknown (%d)\n", EC16(file_hdr.e_type)); |
||||
} |
||||
|
||||
switch(EC16(file_hdr.e_machine)) { |
||||
/* Due to a huge list, we only include the most popular machines here */ |
||||
case 0x0: /* EM_NONE */ |
||||
cli_dbgmsg("ELF: Machine type: None\n"); |
||||
break; |
||||
case 0x2: /* EM_SPARC */ |
||||
cli_dbgmsg("ELF: Machine type: SPARC\n"); |
||||
break; |
||||
case 0x3: /* EM_386 */ |
||||
cli_dbgmsg("ELF: Machine type: Intel 80386\n"); |
||||
break; |
||||
case 0x4: /* EM_68K */ |
||||
cli_dbgmsg("ELF: Machine type: Motorola 68000\n"); |
||||
break; |
||||
case 0x8: /* EM_MIPS */ |
||||
cli_dbgmsg("ELF: Machine type: MIPS RS3000\n"); |
||||
break; |
||||
case 0x15: /* EM_PARISC */ |
||||
cli_dbgmsg("ELF: Machine type: HPPA\n"); |
||||
break; |
||||
case 0x20: /* EM_PPC */ |
||||
cli_dbgmsg("ELF: Machine type: PowerPC\n"); |
||||
break; |
||||
case 0x21: /* EM_PPC64 */ |
||||
cli_dbgmsg("ELF: Machine type: PowerPC 64-bit\n"); |
||||
break; |
||||
case 0x22: /* EM_S390 */ |
||||
cli_dbgmsg("ELF: Machine type: IBM S390\n"); |
||||
break; |
||||
case 0x40: /* EM_ARM */ |
||||
cli_dbgmsg("ELF: Machine type: ARM\n"); |
||||
break; |
||||
case 0x41: /* EM_FAKE_ALPHA */ |
||||
cli_dbgmsg("ELF: Machine type: Digital Alpha\n"); |
||||
break; |
||||
case 0x43: /* EM_SPARCV9 */ |
||||
cli_dbgmsg("ELF: Machine type: SPARC v9 64-bit\n"); |
||||
break; |
||||
case 0x50: /* EM_IA_64 */ |
||||
cli_dbgmsg("ELF: Machine type: IA64\n"); |
||||
break; |
||||
default: |
||||
cli_dbgmsg("ELF: Machine type: Unknown (%d)\n", EC16(file_hdr.e_machine)); |
||||
} |
||||
|
||||
entry = EC32(file_hdr.e_entry); |
||||
cli_dbgmsg("ELF: Entry point address: 0x%.8x\n", entry); |
||||
cli_dbgmsg("ELF: Entry point offset: 0x%.8x (%d)\n", entry - 0x8048000, entry - 0x8048000); |
||||
|
||||
shnum = EC16(file_hdr.e_shnum); |
||||
cli_dbgmsg("ELF: Number of sections: %d\n", shnum); |
||||
if(shnum > 256) { |
||||
cli_dbgmsg("ELF: Suspicious number of sections\n"); |
||||
if(DETECT_BROKEN) { |
||||
if(virname) |
||||
*virname = "Broken.Executable"; |
||||
return CL_VIRUS; |
||||
} |
||||
return CL_EFORMAT; |
||||
} |
||||
|
||||
shentsize = EC16(file_hdr.e_shentsize); |
||||
if(shentsize != sizeof(struct elf_section_hdr32)) { |
||||
cli_errmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n"); |
||||
if(DETECT_BROKEN) { |
||||
if(virname) |
||||
*virname = "Broken.Executable"; |
||||
return CL_VIRUS; |
||||
} |
||||
return CL_EFORMAT; |
||||
} |
||||
|
||||
shoff = EC32(file_hdr.e_shoff); |
||||
cli_dbgmsg("ELF: Section header table offset: %d\n", shoff); |
||||
if(lseek(desc, shoff, SEEK_SET) != shoff) { |
||||
/* Possibly broken end of file */ |
||||
if(DETECT_BROKEN) { |
||||
if(virname) |
||||
*virname = "Broken.Executable"; |
||||
return CL_VIRUS; |
||||
} |
||||
return CL_CLEAN; |
||||
} |
||||
|
||||
section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize); |
||||
if(!section_hdr) { |
||||
cli_dbgmsg("ELF: Can't allocate memory for section headers\n"); |
||||
return CL_EMEM; |
||||
} |
||||
|
||||
cli_dbgmsg("------------------------------------\n"); |
||||
|
||||
for(i = 0; i < shnum; i++) { |
||||
|
||||
if(read(desc, §ion_hdr[i], sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32)) { |
||||
cli_dbgmsg("ELF: Can't read section header\n"); |
||||
cli_dbgmsg("ELF: Possibly broken ELF file\n"); |
||||
free(section_hdr); |
||||
if(DETECT_BROKEN) { |
||||
if(virname) |
||||
*virname = "Broken.Executable"; |
||||
return CL_VIRUS; |
||||
} |
||||
return CL_CLEAN; |
||||
} |
||||
|
||||
cli_dbgmsg("ELF: Section %d\n", i); |
||||
cli_dbgmsg("ELF: Section offset: %d\n", EC32(section_hdr[i].sh_offset)); |
||||
|
||||
switch(EC32(section_hdr[i].sh_type)) { |
||||
case 0x6: /* SHT_DYNAMIC */ |
||||
cli_dbgmsg("ELF: Section type: Dynamic linking information\n"); |
||||
break; |
||||
case 0xb: /* SHT_DYNSYM */ |
||||
cli_dbgmsg("ELF: Section type: Symbols for dynamic linking\n"); |
||||
break; |
||||
case 0xf: /* SHT_FINI_ARRAY */ |
||||
cli_dbgmsg("ELF: Section type: Array of pointers to termination functions\n"); |
||||
break; |
||||
case 0x5: /* SHT_HASH */ |
||||
cli_dbgmsg("ELF: Section type: Symbol hash table\n"); |
||||
break; |
||||
case 0xe: /* SHT_INIT_ARRAY */ |
||||
cli_dbgmsg("ELF: Section type: Array of pointers to initialization functions\n"); |
||||
break; |
||||
case 0x8: /* SHT_NOBITS */ |
||||
cli_dbgmsg("ELF: Section type: Empty section (NOBITS)\n"); |
||||
break; |
||||
case 0x7: /* SHT_NOTE */ |
||||
cli_dbgmsg("ELF: Section type: Note section\n"); |
||||
break; |
||||
case 0x0: /* SHT_NULL */ |
||||
cli_dbgmsg("ELF: Section type: Null (no associated section)\n"); |
||||
break; |
||||
case 0x10: /* SHT_PREINIT_ARRAY */ |
||||
cli_dbgmsg("ELF: Section type: Array of pointers to preinit functions\n"); |
||||
break; |
||||
case 0x1: /* SHT_PROGBITS */ |
||||
cli_dbgmsg("ELF: Section type: Program information\n"); |
||||
break; |
||||
case 0x9: /* SHT_REL */ |
||||
cli_dbgmsg("ELF: Section type: Relocation entries w/o explicit addends\n"); |
||||
break; |
||||
case 0x4: /* SHT_RELA */ |
||||
cli_dbgmsg("ELF: Section type: Relocation entries with explicit addends\n"); |
||||
break; |
||||
case 0x3: /* SHT_STRTAB */ |
||||
cli_dbgmsg("ELF: Section type: String table\n"); |
||||
break; |
||||
case 0x2: /* SHT_SYMTAB */ |
||||
cli_dbgmsg("ELF: Section type: Symbol table\n"); |
||||
break; |
||||
case 0x6ffffffd: /* SHT_GNU_verdef */ |
||||
cli_dbgmsg("ELF: Section type: Provided symbol versions\n"); |
||||
break; |
||||
case 0x6ffffffe: /* SHT_GNU_verneed */ |
||||
cli_dbgmsg("ELF: Section type: Required symbol versions\n"); |
||||
break; |
||||
case 0x6fffffff: /* SHT_GNU_versym */ |
||||
cli_dbgmsg("ELF: Section type: Symbol Version Table\n"); |
||||
break; |
||||
default : |
||||
cli_dbgmsg("ELF: Section type: Unknown\n"); |
||||
} |
||||
|
||||
if(EC32(section_hdr[i].sh_flags) & 0x1) /* SHF_WRITE */ |
||||
cli_dbgmsg("ELF: Section contains writable data\n"); |
||||
|
||||
if(EC32(section_hdr[i].sh_flags) & 0x2) /* SHF_ALLOC */ |
||||
cli_dbgmsg("ELF: Section occupies memory\n"); |
||||
|
||||
if(EC32(section_hdr[i].sh_flags) & 0x4) /* SHF_EXECINSTR */ |
||||
cli_dbgmsg("ELF: Section contains executable code\n"); |
||||
|
||||
cli_dbgmsg("------------------------------------\n"); |
||||
} |
||||
|
||||
free(section_hdr); |
||||
return CL_CLEAN; |
||||
} |
@ -0,0 +1,60 @@ |
||||
/*
|
||||
* Copyright (C) 2005 Tomasz Kojm <tkojm@clamav.net> |
||||
* |
||||
* Header structures based on ELF: Executable and Linkable Format, Portable |
||||
* Formats Specification, Version 1.1 |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#ifndef __ELF_H |
||||
#define __ELF_H |
||||
|
||||
#include "cltypes.h" |
||||
#include "clamav.h" |
||||
|
||||
struct elf_file_hdr32 { |
||||
unsigned char e_ident[16]; |
||||
uint16_t e_type; |
||||
uint16_t e_machine; |
||||
uint32_t e_version; |
||||
uint32_t e_entry; |
||||
uint32_t e_phoff; |
||||
uint32_t e_shoff; |
||||
uint32_t e_flags; |
||||
uint16_t e_ehsize; |
||||
uint16_t e_phentsize; |
||||
uint16_t e_phnum; |
||||
uint16_t e_shentsize; |
||||
uint16_t e_shnum; |
||||
uint16_t e_shstrndx; |
||||
}; |
||||
|
||||
struct elf_section_hdr32 { |
||||
uint32_t sh_name; |
||||
uint32_t sh_type; |
||||
uint32_t sh_flags; |
||||
uint32_t sh_addr; |
||||
uint32_t sh_offset; |
||||
uint32_t sh_size; |
||||
uint32_t sh_link; |
||||
uint32_t sh_info; |
||||
uint32_t sh_addralign; |
||||
uint32_t sh_entsize; |
||||
}; |
||||
|
||||
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); |
||||
|
||||
#endif |
Loading…
Reference in new issue