/*
 * elf_dissector.c - ELF files dissector
 *
 * Tip: y0u will see better on an Eterm or Xterm Terminal ;)...
 *
 * If y0u want something like a rainbow jeje, compile like this =):
 * $gcc elf_dissector.c -o elf_dissector -DCOLOURS -Wall -O2
 * 
 * nitr0us < nitrousenador .at. gmail .dot. com >
 * Mexico
 */

#include<elf.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<getopt.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>

#ifdef	COLOURS
#define RED	"\033[31m"
#define WHITE	"\033[01m"
#define RESET	"\033[00m"
#else
#define RED	""
#define WHITE	""
#define RESET	""
#endif

/* MODES */
#define	HEADER	(1 << 0)
#define	SECTION	(1 << 1)
#define	PROGRAM	(1 << 2)
#define	SYMBOL	(1 << 3)
#define DYNAMIC (1 << 4)
#define RELOC	(1 << 5)
#define ALL	(HEADER + SECTION + PROGRAM + SYMBOL + DYNAMIC + RELOC)

void usage(const char *);
void banner();
int elf_identification(int);
void elf_header(Elf32_Ehdr);
void sht(char *);
void pht(char *);
void symbols(char *);
void dynamic(char *);
void relocations(char *);

int	numeric = 0;
int	shstrtab_offset = 0;

int main(int argc, char **argv)
{
	int		fd, opt, mode = 0;
	char		*elfptr;
	struct stat	statinfo;
	Elf32_Ehdr	header;
	Elf32_Shdr	shstrtab_section;

	if(argc < 3)
		usage(argv[0]);

	while((opt = getopt(argc, argv, "naHSPsdrh")) != EOF)
		switch(opt){
				case 'n':
					numeric = 1;
					break;
				case 'a':
					mode |= ALL;
					break;
				case 'H':
					mode |= HEADER;
					break;
				case 'S':
					mode |= SECTION;
					break;
				case 'P':
					mode |= PROGRAM;
					break;
				case 's':
					mode |= SYMBOL;
					break;
				case 'd':
					mode |= DYNAMIC;
					break;
				case 'r':
					mode |= RELOC;
					break;
				case 'h':
				default:
					usage(argv[0]);
		}

	if(argv[optind] == NULL){
		fprintf(stderr, "Give me an ELF file\n");
		usage(argv[0]);
	}

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

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

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

	if((elfptr = (char *) mmap(NULL, statinfo.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED){
		perror("mmap");
		close(fd);
		exit(-1);
	}

	close(fd);

	banner();

	header = *(Elf32_Ehdr *) elfptr;
	shstrtab_section = *(Elf32_Shdr *) (elfptr + header.e_shoff + header.e_shstrndx * sizeof(Elf32_Shdr));
	if(shstrtab_section.sh_size > 0)
		shstrtab_offset  = shstrtab_section.sh_offset;

	if(mode & HEADER){
		printf("%sELF HEADER:%s\n", RED, RESET);
		elf_header(header);
	}
	if(mode & SECTION){
		printf("\n%sSECTION HEADER TABLE:%s\n", RED, RESET);
		if(header.e_shoff == 0)
			printf("[%sNO SECTION HEADER TABLE FOUND%s]\n", WHITE, RESET);
		else
			sht(elfptr);
	}
	if(mode & PROGRAM){
		printf("\n%sPROGRAM HEADER TABLE:%s\n", RED, RESET);
		pht(elfptr);
	}
	if(mode & SYMBOL){
		printf("\n%sSYMBOL TABLE:%s\n", RED, RESET);
		symbols(elfptr);
	}
	if(mode & DYNAMIC){
		printf("\n%sDYNAMIC INFORMATION:%s\n", RED, RESET);
		dynamic(elfptr);
	}
	if(mode & RELOC){
		printf("\n%sRELOCATIONS:%s\n", RED, RESET);
		relocations(elfptr);
	}

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

void usage(const char *self)
{
	fprintf(stderr, "Usage: %s [-n] <options> <elf_file>\n", self);
	fprintf(stderr, "\tOptions:\n");
	fprintf(stderr, "\t-n\tPrint everything in numeric values\n");
	fprintf(stderr, "\t-a\tAll(-HSPs)\n");
	fprintf(stderr, "\t-H\tELF header\n");
	fprintf(stderr, "\t-S\tSection headers\n");
	fprintf(stderr, "\t-P\tProgram headers\n");
	fprintf(stderr, "\t-s\tSymbol Table\n");
	fprintf(stderr, "\t-d\tDynamic information\n");
	fprintf(stderr, "\t-r\tRelocations\n");
	fprintf(stderr, "\t-h\tThis help\n");
	exit(0);
}

void banner()
{
	printf("%s######################################################%s\n", RED, RESET);
	printf("%s##%s%s                 ELF Dissector                    %s%s##%s\n", RED, RESET, WHITE, RESET, RED, RESET);
	printf("%s##%s%s                  by nitr0us                      %s%s##%s\n", RED, RESET, WHITE, RESET, RED, RESET);
	printf("%s##%s%s         nitrousenador.at.gmail.dot.com           %s%s##%s\n", RED, RESET, WHITE, RESET, RED, RESET);
	printf("%s##%s%s                                                  %s%s##%s\n", RED, RESET, WHITE, RESET, RED, RESET);
	printf("%s##%s%s                    Mexico                        %s%s##%s\n", RED, RESET, WHITE, RESET, RED, RESET);
	printf("%s######################################################%s\n\n", RED, RESET);
}

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;
	}

	return 1;
}

void elf_header(Elf32_Ehdr hdr)
{
	int		k;

	printf("%se_ident:%s\t\t", WHITE, RESET);
	for(k = 0; k < EI_NIDENT; k++)
		printf("%.2x ", hdr.e_ident[k]);

	printf("\n%se_ident[EI_CLASS]:%s\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_ident[EI_CLASS]);
	else
		switch(hdr.e_ident[EI_CLASS]){
			case ELFCLASSNONE:
				printf("ELFCLASSNONE");
				break;
			case ELFCLASS32:
				printf("ELFCLASS32");
				break;
			case ELFCLASS64:
				printf("ELFCLASS64");
				break;
			default:
				printf("%sINVALID CLASS%s (0x%x)", RED, RESET, hdr.e_ident[EI_CLASS]);
		}

	printf("\n%se_ident[EI_DATA]:%s\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_ident[EI_DATA]);
	else
		switch(hdr.e_ident[EI_DATA]){
			case ELFDATANONE:
				printf("ELFDATANONE");
				break;
			case ELFDATA2LSB:
				printf("ELFDATA2LSB");
				break;
			case ELFDATA2MSB:
				printf("ELFDATA2MSB");
				break;
			default:
				printf("%sINVALID DATA%s (0x%x)", RED, RESET, hdr.e_ident[EI_DATA]);
		}

	printf("\n%se_ident[EI_VERSION]:%s\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_ident[EI_VERSION]);
	else{
		if(hdr.e_ident[EI_VERSION] == EV_CURRENT)
			printf("EV_CURRENT");
		else
			printf("%sINVALID VERSION%s (0x%x)", RED, RESET, hdr.e_ident[EI_VERSION]);
	}

	printf("\n%se_ident[EI_OSABI]:%s\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_ident[EI_OSABI]);
	else
		switch(hdr.e_ident[EI_OSABI]){
			case ELFOSABI_SYSV:
				printf("ELFOSABI_SYSV");
				break;
			case ELFOSABI_NETBSD:
				printf("ELFOSABI_NETBSD");
				break;
			case ELFOSABI_OPENBSD:
				printf("ELFOSABI_OPENBSD");
				break;
			case ELFOSABI_FREEBSD:
				printf("ELFOSABI_FREEBSD");
				break;
			case ELFOSABI_LINUX:
				printf("ELFOSABI_LINUX");
				break;
			case ELFOSABI_SOLARIS:
				printf("ELFOSABI_SOLARIS");
				break;
			default:
				printf("%s0x%x%s", RED, hdr.e_ident[EI_OSABI], RESET);
		}

	printf("\n%se_ident[EI_ABIVERSION]:%s\t0x%x", WHITE, RESET, hdr.e_ident[EI_ABIVERSION]);

	printf("\n%se_type:%s\t\t\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_type);
	else
		switch(hdr.e_type){
			case ET_NONE:
				printf("ET_NONE");
				break;
			case ET_REL:
				printf("ET_REL");
				break;
			case ET_EXEC:
				printf("ET_EXEC");
				break;
			case ET_DYN:
				printf("ET_DYN");
				break;
			case ET_CORE:
				printf("ET_CORE");
				break;
			default:
				printf("%s0x%x%s", RED, hdr.e_type, RESET);
		}

	printf("\n%se_machine:%s\t\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_machine);
	else
		switch(hdr.e_machine){
			case EM_NONE:
				printf("EM_NONE");
				break;
			case EM_SPARC:
				printf("EM_SPARC");
				break;
			case EM_386:
				printf("EM_386");
				break;
			case EM_MIPS:
				printf("EM_MIPS");
				break;
			case EM_PARISC:
				printf("EM_PARISC");
				break;
			case EM_PPC:
				printf("EM_PPC");
				break;
			case EM_SPARCV9:
				printf("EM_SPARCV9");
				break;
			default:
				printf("%s0x%x%s", RED, hdr.e_machine, RESET);
		}

	printf("\n%se_version:%s\t\t", WHITE, RESET);
	if(numeric)
		printf("0x%x", hdr.e_version);
	else
		switch(hdr.e_version){
			case EV_NONE:
				printf("EV_NONE");
				break;
			case EV_CURRENT:
				printf("EV_CURRENT");
				break;
			default:
				printf("%s0x%x%s", RED, hdr.e_version, RESET);
		}

	printf("\n%se_entry:%s\t\t0x%.8x", WHITE, RESET, hdr.e_entry);
	printf("\n%se_phoff:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_phoff, hdr.e_phoff);
	printf("\n%se_shoff:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_shoff, hdr.e_shoff);
	printf("\n%se_ehsize:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_ehsize, hdr.e_ehsize);
	printf("\n%se_phentsize:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_phentsize, hdr.e_phentsize);
	printf("\n%se_phnum:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_phnum, hdr.e_phnum);
	printf("\n%se_shentsize:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_shentsize, hdr.e_shentsize);
	printf("\n%se_shnum:%s\t\t0x%.8x\t(%d)", WHITE, RESET, hdr.e_shnum, hdr.e_shnum);
	printf("\n%se_shstrndx:%s\t\t0x%.8x\t(%d)\n", WHITE, RESET, hdr.e_shstrndx, hdr.e_shstrndx);
}

void sht(char *mem)
{
	int		k;
	Elf32_Ehdr	hdr = *(Elf32_Ehdr *) mem;
	Elf32_Shdr	*sections = (Elf32_Shdr *) (mem + hdr.e_shoff);

	printf("%s[NR] sh_name           sh_type       sh_flags   sh_addr  sh_offset sh_size  sh_link sh_info sh_addralign sh_entsize%s\n", WHITE, RESET);

	for(k = 0; k < hdr.e_shnum; k++, sections++){
		printf("[%2d] ", k);

		if(numeric)
			printf("0x%-15.8x ", sections->sh_name);
		else{
			if(shstrtab_offset == 0)
				printf("0x%-15.8x ", sections->sh_name);
			else
				printf("%-17s ", mem + shstrtab_offset + sections->sh_name);
		}

		if(numeric)
			printf("0x%-11.8x ", sections->sh_type);
		else
			switch(sections->sh_type){
				case SHT_NULL:
					printf("%-13s ", "SHT_NULL");
					break;
				case SHT_PROGBITS:
					printf("%-13s ", "SHT_PROGBITS");
					break;
				case SHT_SYMTAB:
					printf("%-13s ", "SHT_SYMTAB");
					break;
				case SHT_STRTAB:
					printf("%-13s ", "SHT_STRTAB");
					break;
				case SHT_RELA:
					printf("%-13s ", "SHT_RELA");
					break;
				case SHT_HASH:
					printf("%-13s ", "SHT_HASH");
					break;
				case SHT_DYNAMIC:
					printf("%-13s ", "SHT_DYNAMIC");
					break;
				case SHT_NOTE:
					printf("%-13s ", "SHT_NOTE");
					break;
				case SHT_NOBITS:
					printf("%-13s ", "SHT_NOBITS");
					break;
				case SHT_REL:
					printf("%-13s ", "SHT_REL");
					break;
				case SHT_SHLIB:
					printf("%-13s ", "SHT_SHLIB");
					break;
				case SHT_DYNSYM:
					printf("%-13s ", "SHT_DYNSYM");
					break;
				case SHT_INIT_ARRAY:
					printf("%-13s ", "SHT_INIT_ARRAY");
					break;
				case SHT_FINI_ARRAY:
					printf("%-13s ", "SHT_ARRAY");
					break;
				case SHT_GNU_verdef:
					printf("%-13s ", "SHT_VERDEF");
					break;
				case SHT_GNU_verneed:
					printf("%-13s ", "SHT_VERNEED");
					break;
				case SHT_GNU_versym:
					printf("%-13s ", "SHT_VERSYM");
					break;
				default:
					printf("%s0x%-11.8x%s ", RED, sections->sh_type, RESET);
			}

		if(numeric)
			printf(" 0x%.4x  ", sections->sh_flags);
		else
			printf(" %c %c %c   ",
					(sections->sh_type & SHF_WRITE) ? 'W' : ' ',
					(sections->sh_type & SHF_ALLOC) ? 'A' : ' ',
					(sections->sh_type & SHF_EXECINSTR) ? 'X' : ' ');

		printf("0x%.8x ", sections->sh_addr);
		printf("0x%.7x ", sections->sh_offset);
		printf("0x%.6x ", sections->sh_size);
		printf("  0x%.2x  ", sections->sh_link);
		printf("0x%.4x  ", sections->sh_info);
		printf("    0x%.2x    ", sections->sh_addralign);
		printf("   0x%.2x\n", sections->sh_entsize);
	}
}

void pht(char *mem)
{
	int		k;
	Elf32_Ehdr	hdr = *(Elf32_Ehdr *) mem;
	Elf32_Phdr	*phdrs = (Elf32_Phdr *) (mem + hdr.e_phoff);

	printf("%s[NR] p_type           p_offset    p_vaddr     p_paddr     p_filesz    p_memsz     p_flags  p_align%s\n", WHITE, RESET);

	for(k = 0; k < hdr.e_phnum; k++, phdrs++){
		printf("[%2d] ", k);

		if(numeric)
			printf("0x%-14.8x ", phdrs->p_type);
		else
			switch(phdrs->p_type){
				case PT_NULL:
					printf("%-17s", "PT_NULL");
					break;
				case PT_LOAD:
					printf("%-17s", "PT_LOAD");
					break;
				case PT_DYNAMIC:
					printf("%-17s", "PT_DYNAMIC");
					break;
				case PT_INTERP:
					printf("%-17s", "PT_INTERP");
					break;
				case PT_NOTE:
					printf("%-17s", "PT_NOTE");
					break;
				case PT_SHLIB:
					printf("%-17s", "PT_SHLIB");
					break;
				case PT_PHDR:
					printf("%-17s", "PT_PHDR");
					break;
				case PT_GNU_EH_FRAME:
					printf("%-17s", "PT_GNU_EH_FRAME");
					break;
				case PT_GNU_STACK:
					printf("%-17s", "PT_GNU_STACK");
					break;
				default:
					printf("%s0x%-14.8x%s ", RED, phdrs->p_type, RESET);
			}

		printf("0x%.8x  ", phdrs->p_offset);
		printf("0x%.8x  ", phdrs->p_vaddr);
		printf("0x%.8x  ", phdrs->p_paddr);
		printf("0x%.8x  ", phdrs->p_filesz);
		printf("0x%.8x  ", phdrs->p_memsz);

		if(numeric)
			printf("0x%.4x   ", phdrs->p_flags);
		else
			printf(" %c %c %c   ",
					(phdrs->p_type & PF_X) ? 'X' : ' ',
					(phdrs->p_type & PF_W) ? 'W' : ' ',
					(phdrs->p_type & PF_R) ? 'R' : ' ');

		printf("0x%.4x\n", phdrs->p_align);

		if(phdrs->p_type == PT_INTERP)
			printf("[Interpreter: %s%s%s]\n", WHITE, mem + phdrs->p_offset, RESET);
	}
}

void symbols(char *mem)
{
	int		k, l, flag = 0, strtab_off;
	Elf32_Ehdr	hdr = *(Elf32_Ehdr *) mem;
	Elf32_Shdr	*shdr = (Elf32_Shdr *) (mem + hdr.e_shoff), stringtable;
	Elf32_Sym	*sym;

	for(k = 0; k < hdr.e_shnum; k++, shdr++){
		if(shdr->sh_type != SHT_SYMTAB && shdr->sh_type != SHT_DYNSYM)
			continue;

		flag = 1;

		printf("Found symbol table [%s%s%s] with %d entries:\n", WHITE, mem + shstrtab_offset + shdr->sh_name, RESET, shdr->sh_size / shdr->sh_entsize);

		sym = (Elf32_Sym *) (mem + shdr->sh_offset);
		stringtable = *(Elf32_Shdr *) (mem + hdr.e_shoff + (shdr->sh_link * sizeof(Elf32_Shdr)));
		strtab_off  = stringtable.sh_offset;

		printf("%s[ NR ] st_value   st_size     TYPE        BINDING    VISIBILITY     st_shndx    st_name%s\n", WHITE, RESET);

		for(l = 0; l < shdr->sh_size / shdr->sh_entsize; l++, sym++){
			printf("[%4d] ", l);

			printf("0x%.8x ", sym->st_value);
			printf("0x%.5x  ", sym->st_size);

			if(numeric)
				printf("   0x%.2x ", sym->st_info);
			else
				switch(ELF32_ST_TYPE(sym->st_info)){
					case STT_NOTYPE:
						printf("%-12s  ", "STT_NOTYPE");
						break;
					case STT_OBJECT:
						printf("%-12s  ", "STT_OBJECT");
						break;
					case STT_FUNC:
						printf("%-12s  ", "STT_FUNC");
						break;
					case STT_SECTION:
						printf("%-12s  ", "STT_SECTION");
						break;
					case STT_FILE:
						printf("%-12s  ", "STT_FILE");
						break;
					case STT_COMMON:
						printf("%-12s  ", "STT_COMMON");
						break;
					case STT_TLS:
						printf("%-12s  ", "STT_TLS");
						break;
					case STT_NUM:
						printf("%-12s  ", "STT_NUM");
						break;
					default:
						printf("   %s0x%.2x%s       ", RED, sym->st_info, RESET);
				}

			if(numeric)
				printf("        0x%.2x ", sym->st_info);
			else
				switch(ELF32_ST_BIND(sym->st_info)){
					case STB_LOCAL:
						printf("%-11s ", "STB_LOCAL");
						break;
					case STB_GLOBAL:
						printf("%-11s ", "STB_GLOBAL");
						break;
					case STB_WEAK:
						printf("%-11s ", "STB_WEAK");
						break;
					case STB_NUM:
						printf("%-11s ", "STB_NUM");
						break;
					default:
						printf("  %s0x%.2x%s       ", RED, sym->st_info, RESET);
				}

			if(numeric)
				printf("        0x%.2x        ", sym->st_other);
			else
				switch(ELF32_ST_VISIBILITY(sym->st_other)){
					case STV_DEFAULT:
						printf("%-14s ", "STV_DEFAULT");
						break;
					case STV_INTERNAL:
						printf("%-14s ", "STV_INTERNAL");
						break;
					case STV_HIDDEN:
						printf("%-14s ", "STV_HIDDEN");
						break;
					case STV_PROTECTED:
						printf("%-14s ", "STV_PROTECTED");
						break;
					default:
						printf("   %s0x%.2x%s        ", RED, sym->st_other, RESET);	
				}

			if(numeric)
				printf(" 0x%.4x     ", sym->st_shndx);
			else
				switch(sym->st_shndx){
					case SHN_UNDEF:
						printf("%-11s ", "SHN_UNDEF");
						break;
					case SHN_ABS:
						printf("%-11s ", "SHN_ABS");
						break;
					case SHN_COMMON:
						printf("%-11s ", "SHN_COMMON");
						break;
					default:
						printf("  0x%.2x      ", sym->st_other);
				}

			printf("%s\n", mem + strtab_off + sym->st_name);
		}

		putchar('\n');
	}

	if(!flag)
		printf("[%sNO SYMBOL TABLE FOUND%s]\n", WHITE, RESET);
}

void dynamic(char *mem)
{
	int		k, l, flag = 0, strtab_offset;
	Elf32_Ehdr	hdr = *(Elf32_Ehdr *) mem;
	Elf32_Shdr	*shdr = (Elf32_Shdr *) (mem + hdr.e_shoff), stringtable;
	Elf32_Dyn	*dyn;

	for(k = 0; k < hdr.e_shnum; k++, shdr++){
		if(shdr->sh_type != SHT_DYNAMIC)
			continue;

		flag = 1;

		printf("Found Dynamic Section [%s%s%s] with %d entries:\n", WHITE, mem + shstrtab_offset + shdr->sh_name, RESET, shdr->sh_size / shdr->sh_entsize);

		dyn = (Elf32_Dyn *) (mem + shdr->sh_offset);
		stringtable = *(Elf32_Shdr *) (mem + hdr.e_shoff + (shdr->sh_link * sizeof(Elf32_Shdr)));
		strtab_offset  = stringtable.sh_offset;

		printf("%s[ NR ]  d_tag       TYPE                 NAME/VALUE%s\n", WHITE, RESET);

		for(l = 0; l < shdr->sh_size / shdr->sh_entsize; l++, dyn++){
			printf("[%4d]  ", l);

			printf("0x%.8x  ", dyn->d_tag);

			if(numeric)
				printf("0x%.8x           ", dyn->d_tag);
			else
				switch(dyn->d_tag){
					case DT_NULL:
						printf("%-20s ", "DT_NULL");
						break;
					case DT_NEEDED:
						printf("%-20s ", "DT_NEEDED");
						break;
					case DT_PLTRELSZ:
						printf("%-20s ", "DT_PLTRELSZ");
						break;
					case DT_PLTGOT:
						printf("%-20s ", "DT_PLTGOT");
						break;
					case DT_HASH:
						printf("%-20s ", "DT_HASH");
						break;
					case DT_STRTAB:
						printf("%-20s ", "DT_STRTAB");
						break;
					case DT_SYMTAB:
						printf("%-20s ", "DT_SYMTAB");
						break;
					case DT_STRSZ:
						printf("%-20s ", "DT_STRSZ");
						break;
					case DT_SYMENT:
						printf("%-20s ", "DT_SYMENT");
						break;
					case DT_INIT:
						printf("%-20s ", "DT_INIT");
						break;
					case DT_FINI:
						printf("%-20s ", "DT_FINI");
						break;
					case DT_SONAME:
						printf("%-20s ", "DT_SONAME");
						break;
					case DT_RPATH:
						printf("%-20s ", "DT_RPATH");
						break;
					case DT_SYMBOLIC:
						printf("%-20s ", "DT_SYMBOLIC");
						break;
					case DT_REL:
						printf("%-20s ", "DT_REL");
						break;
					case DT_RELSZ:
						printf("%-20s ", "DT_RELSZ");
						break;
					case DT_RELENT:
						printf("%-20s ", "DT_RELENT");
						break;
					case DT_PLTREL:
						printf("%-20s ", "DT_PLTREL");
						break;
					case DT_DEBUG:
						printf("%-20s ", "DT_DEBUG");
						break;
					case DT_TEXTREL:
						printf("%-20s ", "DT_TEXTREL");
						break;
					case DT_JMPREL:
						printf("%-20s ", "DT_JMPREL");
						break;
					case DT_BIND_NOW:
						printf("%-20s ", "DT_BIND_NOW");
						break;
					case DT_INIT_ARRAY:
						printf("%-20s ", "DT_INIT_ARRAY");
						break;
					case DT_FINI_ARRAY:
						printf("%-20s ", "DT_FINI_ARRAY");
						break;
					case DT_INIT_ARRAYSZ:
						printf("%-20s ", "DT_INIT_ARRAYSZ");
						break;
					case DT_FINI_ARRAYSZ:
						printf("%-20s ", "DT_FINI_ARRAYSZ");
						break;
					case DT_VERSYM:
						printf("%-20s ", "DT_VERSYM");
						break;
					case DT_RELCOUNT:
						printf("%-20s ", "DT_RELCOUNT");
						break;
					case DT_VERDEF:
						printf("%-20s ", "DT_VERDEF");
						break;
					case DT_VERDEFNUM:
						printf("%-20s ", "DT_VERDEFNUM");
						break;
					case DT_VERNEED:
						printf("%-20s ", "DT_VERNEED");
						break;
					case DT_VERNEEDNUM:
						printf("%-20s ", "DT_VERNEEDNUM");
						break;
					default:
						printf("%s0x%.8x%s           ", RED, dyn->d_tag, RESET);
				}

			switch(dyn->d_tag){
				case DT_NEEDED:
				case DT_SONAME:
				case DT_RPATH:
					printf("%s\n", mem + strtab_offset + dyn->d_un.d_val);
					break;
				case DT_PLTGOT:
				case DT_HASH:
				case DT_INIT:
				case DT_FINI:
				case DT_REL:
				case DT_JMPREL:
				case DT_VERSYM:
				case DT_VERNEED:
					printf("0x%.8x\n", dyn->d_un.d_ptr);
					break;
				case DT_PLTRELSZ:
				case DT_STRSZ:
				case DT_SYMENT:
				case DT_RELSZ:
				case DT_RELENT:
					printf("%d bytes\n", dyn->d_un.d_val);
					break;
				default:
					putchar('\n');
			}

			if(dyn->d_tag == DT_NULL)	/* End of _DYNAMIC[] */
				break;
		}

	}

	if(!flag)
		printf("[%sNO DYNAMIC SECTION FOUND%s]\n", WHITE, RESET);
}

void relocations(char *mem)
{
	int		k, l, symndx = 0, flag = 0, symstrtab_offset;
	Elf32_Ehdr	hdr = *(Elf32_Ehdr *) mem;
	Elf32_Shdr	*shdr = (Elf32_Shdr *) (mem + hdr.e_shoff), *shdr_table, symtab_section, stringtable;
	Elf32_Rel	*rel;
	Elf32_Sym	*sym;

	shdr_table = shdr;

	for(k = 0; k < hdr.e_shnum; k++, shdr++){
		if(shdr->sh_type != SHT_REL)
			continue;

		flag = 1;

		printf("Found Relocation Section [%s%s%s] with %d entries:\n", WHITE, mem + shstrtab_offset + shdr->sh_name, RESET, shdr->sh_size / shdr->sh_entsize);

		symtab_section = shdr_table[shdr->sh_link];
		stringtable = *(Elf32_Shdr *) (mem + hdr.e_shoff + (symtab_section.sh_link * sizeof(Elf32_Shdr)));
		symstrtab_offset  = stringtable.sh_offset;
		rel = (Elf32_Rel *) (mem + shdr->sh_offset);
		sym = (Elf32_Sym *) (mem + symtab_section.sh_offset);

		printf("%s[ NR ] r_offset   r_info      TYPE             SYM[ndx]  SYMBOL NAME%s\n", WHITE, RESET);

		for(l = 0; l < shdr->sh_size / shdr->sh_entsize; l++, rel++){
			printf("[%4d] ", l);

			printf("0x%.8x ", rel->r_offset);
			printf("0x%.8x  ", rel->r_info);

			if(numeric)
				printf("0x%.8x     ", rel->r_info);
			else
				switch(ELF32_R_TYPE(rel->r_info)){
					case R_386_NONE:
						printf("%-14s ", "R_386_NONE");
						break;
					case R_386_32:
						printf("%-14s ", "R_386_32");
						break;
					case R_386_PC32:
						printf("%-14s ", "R_386_PC32");
						break;
					case R_386_GOT32:
						printf("%-14s ", "R_386_GOT32");
						break;
					case R_386_PLT32:
						printf("%-14s ", "R_386_PLT32");
						break;
					case R_386_COPY:
						printf("%-14s ", "R_386_COPY");
						break;
					case R_386_GLOB_DAT:
						printf("%-14s ", "R_386_GLOB_DAT");
						break;
					case R_386_JMP_SLOT:
						printf("%-14s ", "R_386_JMP_SLOT");
						break;
					case R_386_RELATIVE:
						printf("%-14s ", "R_386_RELATIVE");
						break;
					case R_386_GOTOFF:
						printf("%-14s ", "R_386_GOTOFF");
						break;
					case R_386_GOTPC:
						printf("%-14s ", "R_386_GOTPC");
						break;
					default:
						printf("%s0x%.8x%s     ", RED, rel->r_info, RESET);
				}

			symndx = ELF32_R_SYM(rel->r_info);
			printf("    %.4d    ", symndx);

			if(ELF32_ST_TYPE(sym[symndx].st_info) == STT_SECTION)
				printf("%s\n", mem + shstrtab_offset + shdr_table[sym[symndx].st_shndx].sh_name);
			else
				printf("%s\n", mem + symstrtab_offset + sym[symndx].st_name);
		}

		putchar('\n');
	}

	if(!flag)
		printf("[%sNO RELOCATIONS FOUND%s]\n", WHITE, RESET);
}
