df9f16fa |
*do_convert = conv;
*is64 = format64;
/* Solve bit-size and conversion pronto */
file_hdr->hdr64.e_type = EC16(file_hdr->hdr64.e_type, conv);
file_hdr->hdr64.e_machine = EC16(file_hdr->hdr64.e_machine, conv);
file_hdr->hdr64.e_version = EC32(file_hdr->hdr64.e_version, conv);
if(format64) {
/* Read rest of 64-bit header */
if(fmap_readn(map, file_hdr->hdr32.pad, sizeof(struct elf_file_hdr32), ELF_HDR_SIZEDIFF)
!= ELF_HDR_SIZEDIFF) {
/* Not an ELF file? */
cli_dbgmsg("ELF: Can't read file header\n");
return CL_BREAK;
}
/* Now endian convert, if needed */
if(conv) {
file_hdr->hdr64.e_entry = EC64(file_hdr->hdr64.e_entry, conv);
file_hdr->hdr64.e_phoff = EC64(file_hdr->hdr64.e_phoff, conv);
file_hdr->hdr64.e_shoff = EC64(file_hdr->hdr64.e_shoff, conv);
file_hdr->hdr64.e_flags = EC32(file_hdr->hdr64.e_flags, conv);
file_hdr->hdr64.e_ehsize = EC16(file_hdr->hdr64.e_ehsize, conv);
file_hdr->hdr64.e_phentsize = EC16(file_hdr->hdr64.e_phentsize, conv);
file_hdr->hdr64.e_phnum = EC16(file_hdr->hdr64.e_phnum, conv);
file_hdr->hdr64.e_shentsize = EC16(file_hdr->hdr64.e_shentsize, conv);
file_hdr->hdr64.e_shnum = EC16(file_hdr->hdr64.e_shnum, conv);
file_hdr->hdr64.e_shstrndx = EC16(file_hdr->hdr64.e_shstrndx, conv);
}
}
else {
/* Convert 32-bit structure, if needed */
if(conv) {
file_hdr->hdr32.hdr.e_entry = EC32(file_hdr->hdr32.hdr.e_entry, conv);
file_hdr->hdr32.hdr.e_phoff = EC32(file_hdr->hdr32.hdr.e_phoff, conv);
file_hdr->hdr32.hdr.e_shoff = EC32(file_hdr->hdr32.hdr.e_shoff, conv);
file_hdr->hdr32.hdr.e_flags = EC32(file_hdr->hdr32.hdr.e_flags, conv);
file_hdr->hdr32.hdr.e_ehsize = EC16(file_hdr->hdr32.hdr.e_ehsize, conv);
file_hdr->hdr32.hdr.e_phentsize = EC16(file_hdr->hdr32.hdr.e_phentsize, conv);
file_hdr->hdr32.hdr.e_phnum = EC16(file_hdr->hdr32.hdr.e_phnum, conv);
file_hdr->hdr32.hdr.e_shentsize = EC16(file_hdr->hdr32.hdr.e_shentsize, conv);
file_hdr->hdr32.hdr.e_shnum = EC16(file_hdr->hdr32.hdr.e_shnum, conv);
file_hdr->hdr32.hdr.e_shstrndx = EC16(file_hdr->hdr32.hdr.e_shstrndx, conv);
}
/* Wipe pad for safety */
memset(file_hdr->hdr32.pad, 0, ELF_HDR_SIZEDIFF);
}
return CL_CLEAN;
}
/* Read 32-bit program headers */
static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
struct elf_file_hdr32 *file_hdr, uint8_t conv)
{
struct elf_program_hdr32 *program_hdr = NULL;
uint16_t phnum, phentsize;
uint32_t entry, fentry, phoff;
uint32_t i;
uint8_t err;
/* Program headers and Entry */
phnum = file_hdr->e_phnum;
cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
if(phnum > 128) {
cli_dbgmsg("ELF: Suspicious number of program headers\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
entry = file_hdr->e_entry;
if(phnum && entry) {
phentsize = file_hdr->e_phentsize;
/* Sanity check */
if(phentsize != sizeof(struct elf_program_hdr32)) {
cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
phoff = file_hdr->e_phoff;
if(ctx) {
cli_dbgmsg("ELF: Program header table offset: %d\n", phoff);
}
if(phnum) {
program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, sizeof(struct elf_program_hdr32));
if(!program_hdr) {
cli_errmsg("ELF: Can't allocate memory for program headers\n");
return CL_EMEM;
}
if(ctx) {
cli_dbgmsg("------------------------------------\n");
}
}
for(i = 0; i < phnum; i++) {
err = 0;
if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr32)) != sizeof(struct elf_program_hdr32))
err = 1;
phoff += sizeof(struct elf_program_hdr32);
if(err) {
cli_dbgmsg("ELF: Can't read segment #%d\n", i);
if(ctx) {
cli_dbgmsg("ELF: Possibly broken ELF file\n");
}
free(program_hdr);
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_BREAK;
}
if(ctx) {
cli_dbgmsg("ELF: Segment #%d\n", i);
cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv));
cli_dbgmsg("ELF: Segment offset: 0x%x\n", EC32(program_hdr[i].p_offset, conv));
cli_dbgmsg("ELF: Segment virtual address: 0x%x\n", EC32(program_hdr[i].p_vaddr, conv));
cli_dbgmsg("ELF: Segment real size: 0x%x\n", EC32(program_hdr[i].p_filesz, conv));
cli_dbgmsg("ELF: Segment virtual size: 0x%x\n", EC32(program_hdr[i].p_memsz, conv));
cli_dbgmsg("------------------------------------\n");
}
}
fentry = cli_rawaddr32(entry, program_hdr, phnum, conv, &err);
free(program_hdr);
if(err) {
cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
if(ctx) {
cli_dbgmsg("ELF: Entry point address: 0x%.8x\n", entry);
cli_dbgmsg("ELF: Entry point offset: 0x%.8x (%d)\n", fentry, fentry);
}
}
if(elfinfo) {
elfinfo->ep = fentry;
}
return CL_CLEAN;
}
/* Read 64-bit program headers */
static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
struct elf_file_hdr64 *file_hdr, uint8_t conv)
{
struct elf_program_hdr64 *program_hdr = NULL;
uint16_t phnum, phentsize;
uint64_t entry, fentry, phoff;
uint32_t i;
uint8_t err;
/* Program headers and Entry */
phnum = file_hdr->e_phnum;
cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
if(phnum > 128) {
cli_dbgmsg("ELF: Suspicious number of program headers\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
entry = file_hdr->e_entry;
if(phnum && entry) {
phentsize = file_hdr->e_phentsize;
/* Sanity check */
if (phentsize != sizeof(struct elf_program_hdr64)) {
cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
phoff = file_hdr->e_phoff;
if(ctx) {
cli_dbgmsg("ELF: Program header table offset: %d\n", phoff);
}
if(phnum) {
program_hdr = (struct elf_program_hdr64 *) cli_calloc(phnum, sizeof(struct elf_program_hdr64));
if(!program_hdr) {
cli_errmsg("ELF: Can't allocate memory for program headers\n");
return CL_EMEM;
}
if(ctx) {
cli_dbgmsg("------------------------------------\n");
}
}
for(i = 0; i < phnum; i++) {
err = 0;
if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr64)) != sizeof(struct elf_program_hdr64))
err = 1;
phoff += sizeof(struct elf_program_hdr64);
if(err) {
cli_dbgmsg("ELF: Can't read segment #%d\n", i);
if(ctx) {
cli_dbgmsg("ELF: Possibly broken ELF file\n");
}
free(program_hdr);
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_BREAK;
}
if(ctx) {
cli_dbgmsg("ELF: Segment #%d\n", i);
cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv));
cli_dbgmsg("ELF: Segment offset: 0x%x\n", EC64(program_hdr[i].p_offset, conv));
cli_dbgmsg("ELF: Segment virtual address: 0x%x\n", EC64(program_hdr[i].p_vaddr, conv));
cli_dbgmsg("ELF: Segment real size: 0x%x\n", EC64(program_hdr[i].p_filesz, conv));
cli_dbgmsg("ELF: Segment virtual size: 0x%x\n", EC64(program_hdr[i].p_memsz, conv));
cli_dbgmsg("------------------------------------\n");
}
}
fentry = cli_rawaddr64(entry, program_hdr, phnum, conv, &err);
free(program_hdr);
if(err) {
cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
if(ctx) {
cli_dbgmsg("ELF: Entry point address: 0x%.16x\n", entry);
cli_dbgmsg("ELF: Entry point offset: 0x%.16x (%d)\n", fentry, fentry);
}
}
if(elfinfo) {
elfinfo->ep = fentry;
}
return CL_CLEAN;
}
/* 32-bit version of section header parsing */
static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
struct elf_file_hdr32 *file_hdr, uint8_t conv)
{
struct elf_section_hdr32 *section_hdr = NULL;
uint16_t shnum, shentsize;
uint32_t shoff, i;
shnum = file_hdr->e_shnum;
cli_dbgmsg("ELF: Number of sections: %d\n", shnum);
if(ctx && (shnum > 2048)) {
cli_dbgmsg("ELF: Number of sections > 2048, skipping\n");
return CL_BREAK;
}
else if(elfinfo && (shnum > 256)) {
cli_dbgmsg("ELF: Suspicious number of sections\n");
return CL_BREAK;
}
if(elfinfo) {
elfinfo->nsections = shnum;
}
shentsize = file_hdr->e_shentsize;
/* Sanity check */
if(shentsize != sizeof(struct elf_section_hdr32)) {
cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
if(elfinfo && !shnum) {
return CL_CLEAN;
}
shoff = file_hdr->e_shoff;
if(ctx)
cli_dbgmsg("ELF: Section header table offset: %d\n", shoff);
if(elfinfo) {
elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section));
if(!elfinfo->section) {
cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
return CL_EMEM;
}
}
if(shnum) {
section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
if(!section_hdr) {
cli_errmsg("ELF: Can't allocate memory for section headers\n");
if(elfinfo) {
free(elfinfo->section);
elfinfo->section = NULL;
}
return CL_EMEM;
}
if(ctx) {
cli_dbgmsg("------------------------------------\n");
}
}
/* Loop over section headers */
for(i = 0; i < shnum; i++) {
uint32_t sh_type, sh_flags;
if(fmap_readn(map, §ion_hdr[i], shoff, sizeof(struct elf_section_hdr32)) != sizeof(struct elf_section_hdr32)) {
cli_dbgmsg("ELF: Can't read section header\n");
if(ctx) {
cli_dbgmsg("ELF: Possibly broken ELF file\n");
}
free(section_hdr);
if(elfinfo) {
free(elfinfo->section);
elfinfo->section = NULL;
}
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_BREAK;
}
shoff += sizeof(struct elf_section_hdr32);
if(elfinfo) {
elfinfo->section[i].rva = EC32(section_hdr[i].sh_addr, conv);
elfinfo->section[i].raw = EC32(section_hdr[i].sh_offset, conv);
elfinfo->section[i].rsz = EC32(section_hdr[i].sh_size, conv);
}
if(ctx) {
cli_dbgmsg("ELF: Section %u\n", i);
cli_dbgmsg("ELF: Section offset: %u\n", EC32(section_hdr[i].sh_offset, conv));
cli_dbgmsg("ELF: Section size: %u\n", EC32(section_hdr[i].sh_size, conv));
sh_type = EC32(section_hdr[i].sh_type, conv);
sh_flags = EC32(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK;
cli_elf_sectionlog(sh_type, sh_flags);
cli_dbgmsg("------------------------------------\n");
}
}
free(section_hdr);
return CL_CLEAN;
}
/* 64-bit version of section header parsing */
static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
struct elf_file_hdr64 *file_hdr, uint8_t conv)
{
struct elf_section_hdr64 *section_hdr = NULL;
uint16_t shnum, shentsize;
uint32_t i;
uint64_t shoff;
shnum = file_hdr->e_shnum;
cli_dbgmsg("ELF: Number of sections: %d\n", shnum);
if(ctx && (shnum > 2048)) {
cli_dbgmsg("ELF: Number of sections > 2048, skipping\n");
return CL_BREAK;
}
else if(elfinfo && (shnum > 256)) {
cli_dbgmsg("ELF: Suspicious number of sections\n");
return CL_BREAK;
}
if(elfinfo) {
elfinfo->nsections = shnum;
}
shentsize = file_hdr->e_shentsize;
/* Sanity check */
if(shentsize != sizeof(struct elf_section_hdr64)) {
cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n");
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
}
if(elfinfo && !shnum) {
return CL_CLEAN;
}
shoff = file_hdr->e_shoff;
if(ctx)
cli_dbgmsg("ELF: Section header table offset: %d\n", shoff);
if(elfinfo) {
elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section));
if(!elfinfo->section) {
cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
return CL_EMEM;
}
}
if(shnum) {
section_hdr = (struct elf_section_hdr64 *) cli_calloc(shnum, shentsize);
if(!section_hdr) {
cli_errmsg("ELF: Can't allocate memory for section headers\n");
if(elfinfo) {
free(elfinfo->section);
elfinfo->section = NULL;
}
return CL_EMEM;
}
if(ctx) {
cli_dbgmsg("------------------------------------\n");
}
}
/* Loop over section headers */
for(i = 0; i < shnum; i++) {
uint32_t sh_type, sh_flags;
if(fmap_readn(map, §ion_hdr[i], shoff, sizeof(struct elf_section_hdr64)) != sizeof(struct elf_section_hdr64)) {
cli_dbgmsg("ELF: Can't read section header\n");
if(ctx) {
cli_dbgmsg("ELF: Possibly broken ELF file\n");
}
free(section_hdr);
if(elfinfo) {
free(elfinfo->section);
elfinfo->section = NULL;
}
if(ctx && DETECT_BROKEN) {
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_BREAK;
}
shoff += sizeof(struct elf_section_hdr64);
if(elfinfo) {
elfinfo->section[i].rva = EC64(section_hdr[i].sh_addr, conv);
elfinfo->section[i].raw = EC64(section_hdr[i].sh_offset, conv);
elfinfo->section[i].rsz = EC64(section_hdr[i].sh_size, conv);
}
if(ctx) {
cli_dbgmsg("ELF: Section %u\n", i);
cli_dbgmsg("ELF: Section offset: %u\n", EC64(section_hdr[i].sh_offset, conv));
cli_dbgmsg("ELF: Section size: %u\n", EC64(section_hdr[i].sh_size, conv));
sh_type = EC32(section_hdr[i].sh_type, conv);
sh_flags = (uint32_t)(EC64(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK);
cli_elf_sectionlog(sh_type, sh_flags);
cli_dbgmsg("------------------------------------\n");
}
}
free(section_hdr);
return CL_CLEAN;
}
/* Print section type and selected flags to the log */
static void cli_elf_sectionlog(uint32_t sh_type, uint32_t sh_flags)
{
switch(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(sh_flags & ELF_SHF_WRITE)
cli_dbgmsg("ELF: Section contains writable data\n");
if(sh_flags & ELF_SHF_ALLOC)
cli_dbgmsg("ELF: Section occupies memory\n");
if(sh_flags & ELF_SHF_EXECINSTR)
cli_dbgmsg("ELF: Section contains executable code\n");
}
/* Scan function for ELF */
int cli_scanelf(cli_ctx *ctx)
{
union elf_file_hdr file_hdr;
fmap_t *map = *ctx->fmap;
int ret;
uint8_t conv = 0, is64 = 0;
cli_dbgmsg("in cli_scanelf\n");
/* Load header to determine size and class */
ret = cli_elf_fileheader(ctx, map, &file_hdr, &conv, &is64);
if(ret == CL_BREAK) {
return CL_CLEAN; /* here, break means "exit but report clean" */
}
else if(ret != CL_CLEAN) {
return ret;
}
/* Log File type and machine type */
switch(file_hdr.hdr64.e_type) { |