Scanner to look up infection techniques that can be used in ELF modules. Includes function hijacking, relocation files, etc. Runs on linux 2.4.X.
dcd0e0b68ca65f72ca23959a54204f1f589d2cac48c5840fd77dc0b45db13d17
/*
* ELF infection methods scanner 0.1
* Coded by pluf (pluf@mail.ru)
*
* Use:
*
* ./scaner -v -f file_to_check
*
* file_to_check must be a ET_EXEC file
*
* It runs on linux2.4.X
*
* Infection methods supported:
* + text segment infection (padding), data segment infection, or other kind of
* methods that change the real entry point of infected file.
* + altplt function hijacking method
* + dynamic section infection to allow add a new library dependance and make
* easy functions hijacking
* + plt infection and got redirection too allow funtion hijacking
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <elf.h>
int verbose = 0;
unsigned short infected = 0x0000;
struct {
int size;
int vaddr;
int offset;
} section_inf[5];
#define A 0x0001
#define B 0x0020
#define C 0x0100
#define D 0x0200
void
show_method(type)
int type;
{
printf("\n [ Results ]\n");
if (infected & B) printf(" [+] Posible text or data segment infection: entry point dont' referer text segment\n");
if (infected & C) printf(" [+] ALTPLT function hijacking method.\n");
if (infected & D) printf(" [+] Dynamic section infected: posible DT_NEEDED symbol injected instead of orig DT_DEBUG\n");
if (infected & A) printf(" [+] PLT infection and got redirection\n");
printf("\n");
}
int
check_fake_entry(orig_entry)
int orig_entry;
{
if (orig_entry != section_inf[4].vaddr) return (1);
return (0);
}
int
check_function_hijacking(shnum, string, shdr)
int shnum;
const char *string;
Elf32_Shdr *shdr;
{
Elf32_Shdr *shdrp = shdr;
register int i;
for (i = 0; i < shnum; i++) {
if (!strcmp(&string[shdrp->sh_name], ".orig.plt")) return (1);
++shdrp;
}
return (0);
}
int
check_dynamic_infection(len, dyn)
int len;
Elf32_Dyn *dyn;
{
register int i;
for (i = 0; i < (len/sizeof(Elf32_Dyn)); i++) {
if (dyn->d_tag == DT_DEBUG)
return (0);
++dyn;
}
return (1);
}
int
find_symbol(long got_entry, Elf32_Sym *dynsym, char *dynstr)
{
register int i;
int syndym_entries = (section_inf[1].size/sizeof(Elf32_Sym));
int gotp;
gotp = got_entry;
for (i = 0; i < syndym_entries; i++) {
if (dynsym->st_value != 0) {
if (dynsym->st_value == (gotp -= 0x06) ||
dynsym->st_value == (gotp -= 16)) {
if(verbose)
printf(" [%3.5d] %-50.60s (plt-entry -> 0x%.7x) = [ok]\n",
i, &dynstr[dynsym->st_name], dynsym->st_value);
return (1);
}
}
gotp = got_entry;
++dynsym;
}
if (verbose)
printf(" [%c] %-50.60s (plt->entry -> 0x%.7x) = [Bad]\n", '?', &dynstr[dynsym->st_name], dynsym->st_value);
return (0);
}
int
check_plt_infection(Elf32_Sym *dynsym, char *got, char *dynstr)
{
register int i;
Elf32_Sym *dynsymp = dynsym;
char *ptr = got;
long *addr;
int got_entries = (section_inf[0].size/4), bad_entry = 0;
if(verbose)
printf("\n [ Checking for valid dynamic symbols ]\n\n");
addr = (long*)ptr;
for (i = 2, addr+=2; i < got_entries; i++) {
if (*addr != 0)
if (!find_symbol(*addr, dynsymp, dynstr)) ++bad_entry;
++addr;
}
return (bad_entry);
}
char *get_section(Elf32_Shdr *shdr,
char *sdata,
int shnum,
int fd,
const char *string_table,
const char *section_name,
unsigned char id)
{
Elf32_Shdr *shdrp = shdr;
register int i;
int offset;
int size;
int vaddr;
char *buf;
shdrp = (Elf32_Shdr*)sdata;
for (i = 0; i < shnum; i++) {
if (!strcmp(&string_table[shdrp->sh_name], section_name)) {
section_inf[id].offset = shdrp->sh_offset;
section_inf[id].size = shdrp->sh_size;
section_inf[id].vaddr = shdrp->sh_addr;
offset = shdrp->sh_offset;
size = shdrp->sh_size;
vaddr = shdrp->sh_addr;
if (verbose)
printf(" [!] %-12s addr(0x%x) offset(0x%.8x) size(0x%.8x)\n", section_name,
vaddr,offset,size);
}
++shdrp;
}
buf = (char*)malloc(size);
if (buf == NULL) {
perror("malloc");
exit(-1);
}
if (lseek(fd, offset, SEEK_SET) < 0) {
perror("lseek");
exit(-1);
}
if (read(fd, buf, size) != size) {
perror("read");
exit(-1);
}
return (buf);
}
void
help()
{
printf("usage: ./scanner -v -f file\n\n");
exit(-1);
}
int
main(argc, argv)
int argc;
char *argv[];
{
Elf32_Ehdr elf_header;
Elf32_Phdr *phdr;
Elf32_Shdr *shdr, *strtable;
Elf32_Dyn *dynamic;
Elf32_Sym *dynsym;
char *pdata, *sdata, *string, *got, *dynstr, *text;
int shlen, phlen;
char *file;
int fd, op;
printf("\n\n\t--=== Elf infections scanner v0.1 by pluf ==--\n\n");
while ((op=getopt(argc, argv, "vf:")) != -1) {
switch(op) {
case 'v':
verbose +=1;
break;
case 'f':
if (strlen(optarg) > 256)
exit(-1);
file = optarg;
break;
case '?':
case 'h':
default:
help();
}
}
if (argc < 3)
help();
/* open file */
if ((fd = open(file, O_RDONLY)) == -1) { perror("open");exit(-1); }
/*get elf */
if (read(fd, &elf_header, sizeof(elf_header)) < 0) { perror("read");exit(-1); }
/* get program header table */
pdata = (char*)malloc(phlen = sizeof(*phdr)*elf_header.e_phnum);
if (lseek(fd, elf_header.e_phoff, SEEK_SET) <0 ) { perror("lseek");exit(-1); }
if (read(fd, pdata, phlen) < phlen) { perror("read");exit(-1); }
/* get section header table */
sdata = (char*)malloc(shlen = sizeof(*shdr)*elf_header.e_shnum);
if (lseek(fd, elf_header.e_shoff, SEEK_SET) < 0) { perror("lseek");exit(-1); }
if (read(fd, sdata, shlen) < shlen) { perror("read");exit(-1); }
shdr = (Elf32_Shdr*)sdata;
/* get string table */
strtable = &((Elf32_Shdr *)sdata)[elf_header.e_shstrndx];
string = (char*)malloc(strtable->sh_size);
if (string == NULL) { perror("malloc");exit(-1); }
if (lseek(fd, strtable->sh_offset, SEEK_SET) < 0) { perror("lseek");exit(-1); }
if (read(fd, string, strtable->sh_size) != strtable->sh_size) { perror("read");exit(-1); }
if(verbose)
printf(" [ Loading needed sections ]\n\n");
/* get dynamic symbol table (.dynsym section) */
dynsym = (Elf32_Sym*)get_section(shdr, sdata, elf_header.e_shnum, fd, string, ".dynsym",1);
/* get dynamic symbol string table (.dynstr section) */
dynstr = get_section(shdr, sdata, elf_header.e_shnum, fd, string, ".dynstr", 2);
/* get .text section */
text = get_section(shdr, sdata, elf_header.e_shnum, fd, string, ".text",4);
/* get .dynamic section */
dynamic = (Elf32_Dyn*)get_section(shdr, sdata, elf_header.e_shnum, fd, string, ".dynamic",3);
/* get global offset table (.got section) */
got = get_section(shdr, sdata, elf_header.e_shnum, fd, string, ".got", 0);
shdr = (Elf32_Shdr*)sdata;
if (check_plt_infection(dynsym, got, dynstr)) infected |= A;
if (check_fake_entry(elf_header.e_entry)) infected |= B;
if (check_function_hijacking(elf_header.e_shnum, string, shdr)) infected |= C;
if (check_dynamic_infection(section_inf[3].size, dynamic)) infected |= D;
if (!infected) printf("\n [-] This file is clean!!\n\n");
else show_method();
close(fd);
return (0);
}