Last active
September 11, 2020 02:45
-
-
Save telescreen/14fb685f8651b6a85ee40b4669095008 to your computer and use it in GitHub Desktop.
Parse ELF Header
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <elf.h> | |
#include <errno.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
void dumpSymTab(unsigned char *mem) | |
{ | |
Elf64_Ehdr *ehdr; | |
Elf64_Phdr *phdr; | |
Elf64_Shdr *shdr; | |
Elf64_Sym* symtab; | |
int symcount; | |
const char *symname; | |
char *StringTable; | |
ehdr = (Elf64_Ehdr*)mem; | |
phdr = (Elf64_Phdr*)&mem[ehdr->e_phoff]; | |
shdr = (Elf64_Shdr*)&mem[ehdr->e_shoff]; | |
for (int i = 0; i < ehdr->e_shnum; i++) { | |
if (shdr[i].sh_type == SHT_SYMTAB) { | |
symtab = (Elf64_Sym*)&mem[shdr[i].sh_offset]; | |
symcount = shdr[i].sh_size / shdr[i].sh_entsize; | |
symname = &StringTable[shdr[i].sh_name]; | |
StringTable = &mem[shdr[shdr[i].sh_link].sh_offset]; | |
} | |
} | |
printf("Symbol table %s contains %d entries.\n", symname, symcount); | |
printf("%4s%12s%10s%8s%8s%5s%8s\n", | |
"Num:", "Value", "Size", "Type", "Bind", "Ndx", "Name"); | |
for (int j = 0; j < symcount; j++) { | |
printf("%4.0d %-16.16lx %4ld ", j, symtab[j].st_value, symtab[j].st_size); | |
switch (ELF64_ST_TYPE(symtab[j].st_info)) { | |
case STT_NOTYPE: | |
printf("%-10s", "NOTYPE"); | |
break; | |
case STT_OBJECT: | |
printf("%-10s", "OBJECT"); | |
break; | |
case STT_FUNC: | |
printf("%-10s", "FUNC"); | |
break; | |
case STT_SECTION: | |
printf("%-10s", "SECTION"); | |
break; | |
case STT_FILE: | |
printf("%-10s", "FILE"); | |
break; | |
case STT_LOPROC: | |
printf("%-10s", "LOPROC"); | |
break; | |
case STT_HIPROC: | |
printf("%-10s", "HIPROC"); | |
break; | |
} | |
switch (ELF64_ST_BIND(symtab[j].st_info)) { | |
case STB_LOCAL: | |
printf("%-8s", "LOCAL"); | |
break; | |
case STB_GLOBAL: | |
printf("%-8s", "GLOBAL"); | |
break; | |
case STB_WEAK: | |
printf("%-8s", "WEAK"); | |
break; | |
case STB_LOPROC: | |
printf("%-8s", "LOPROC"); | |
break; | |
case STB_HIPROC: | |
printf("%-8s", "HIPROC"); | |
break; | |
} | |
switch(symtab[j].st_shndx) { | |
case SHN_UNDEF: | |
printf("%-6s", "UND"); | |
break; | |
case SHN_ABS: | |
printf("%-6s", "ABS"); | |
break; | |
case SHN_COMMON: | |
printf("%-6s", "ABS"); | |
break; | |
default: | |
printf("%-6d", symtab[j].st_shndx); | |
} | |
printf("%-10s", &StringTable[symtab[j].st_name]); | |
printf("\n"); | |
} | |
} | |
void dumpSectionHeaders(unsigned char *mem) | |
{ | |
Elf64_Ehdr *ehdr; | |
Elf64_Phdr *phdr; | |
Elf64_Shdr *shdr; | |
ehdr = (Elf64_Ehdr*)mem; | |
phdr = (Elf64_Phdr*)&mem[ehdr->e_phoff]; | |
shdr = (Elf64_Shdr*)&mem[ehdr->e_shoff]; | |
char *StringTable = &mem[shdr[ehdr->e_shstrndx].sh_offset]; | |
printf("There are %d section headers starting at %lx\n", | |
ehdr->e_shnum, ehdr->e_shoff); | |
printf("Section headers:\n"); | |
for(int i = 1; i < ehdr->e_shnum; i++) { | |
printf("%-20s 0x%-8lx 0x%lx\n", | |
&StringTable[shdr[i].sh_name], shdr[i].sh_addr, shdr[i].sh_offset); | |
} | |
} | |
void dumpProgramHeaders(unsigned char *mem) | |
{ | |
Elf64_Ehdr *ehdr; | |
Elf64_Phdr *phdr; | |
ehdr = (Elf64_Ehdr*)mem; | |
phdr = (Elf64_Phdr*)&mem[ehdr->e_phoff]; | |
switch(ehdr->e_type) { | |
case ET_REL: | |
printf("ELF file type is REL (Relocatable File)\n"); | |
break; | |
case ET_EXEC: | |
printf("ELF file type is EXEC (Executable File)\n"); | |
break; | |
case ET_DYN: | |
printf("ELF file type is DYN (Shared Object File)\n"); | |
break; | |
case ET_CORE: | |
printf("ELF file type is CORE (Core File)\n"); | |
break; | |
default: | |
printf("ELF file type is Unknown type\n"); | |
break; | |
} | |
printf("%-30s%#lx\n", "Entry point address:", ehdr->e_entry); | |
printf("There are %d program ehdrs, starting at offset %#lx (%ld bytes)\n", | |
ehdr->e_phnum, ehdr->e_phoff, ehdr->e_phoff); | |
printf("\nProgram Headers\n"); | |
printf("%-15s%-12s%-20s%-20s%-12s%-12s%-6s%-8s\n", | |
"Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz", "MemSiz", "Flags", "Align"); | |
for (int i = 0; i < ehdr->e_phnum; i++) { | |
switch(phdr[i].p_type) { | |
case PT_LOAD: | |
printf("%-15s", "LOAD"); | |
break; | |
case PT_DYNAMIC: | |
printf("%-15s", "DYNAMIC"); | |
break; | |
case PT_INTERP: | |
printf("%-15s", "INTERP"); | |
break; | |
case PT_NOTE: | |
printf("%-15s", "NOTE"); | |
break; | |
case PT_SHLIB: | |
printf("%-15s", "SHLIB"); | |
break; | |
case PT_PHDR: | |
printf("%-15s", "PHDR"); | |
break; | |
case PT_GNU_STACK: | |
printf("%-15s", "GNU_STACK"); | |
break; | |
case PT_NULL: | |
printf("%-15s", "NULL"); | |
break; | |
default: | |
printf("%-15s", "Unknown Type"); | |
break; | |
} | |
printf("0x%-10.8lx", phdr[i].p_offset); | |
printf("0x%-18.16lx", phdr[i].p_vaddr); | |
printf("0x%-18.16lx", phdr[i].p_paddr); | |
printf("0x%-10.8lx", phdr[i].p_filesz); | |
printf("0x%-10.8lx", phdr[i].p_memsz); | |
(phdr[i].p_flags & PF_R) > 0 ? printf("R") : printf("%4s", ""); | |
(phdr[i].p_flags & PF_W) > 0 ? printf("W") : printf(" "); | |
(phdr[i].p_flags & PF_X) > 0 ? printf("%-4s", "X") : printf("%-4s", ""); | |
printf("0x%-3lx", phdr[i].p_align); | |
printf("\n"); | |
} | |
} | |
void dumpELFHeader(unsigned char *mem) | |
{ | |
#define PRINT(hdr, content) printf(" %-30s%s\n", hdr, content) | |
Elf64_Ehdr *ehdr; | |
ehdr = (Elf64_Ehdr*)mem; | |
printf("ELF Header:\n"); | |
printf(" Magic: "); | |
for(int i = 0; i < EI_NIDENT; i++) { | |
printf("%02x ", ehdr->e_ident[i]); | |
} | |
printf("\n"); | |
switch(ehdr->e_ident[EI_CLASS]) { | |
case ELFCLASS32: | |
PRINT("Class:", "ELF32"); | |
break; | |
case ELFCLASS64: | |
PRINT("Class:", "ELF64"); | |
break; | |
default: | |
PRINT("Class:", "Unknown Data Format"); | |
break; | |
} | |
switch(ehdr->e_ident[EI_DATA]) { | |
case ELFDATA2LSB: | |
PRINT("Data:", "Two's complement, little-endian."); | |
break; | |
case ELFDATA2MSB: | |
PRINT("Data:", "Two's complement, big-endian."); | |
break; | |
default: | |
PRINT("Data:", "Unknown Data Format"); | |
break; | |
} | |
if (ehdr->e_ident[EI_VERSION] == EV_CURRENT) { | |
PRINT("Version:", "1 (Current)"); | |
} else { | |
PRINT("Version:", "Unknown"); | |
} | |
switch(ehdr->e_ident[EI_OSABI]) { | |
case ELFOSABI_SYSV: | |
PRINT("OS/ABI:", "SYS-V"); | |
break; | |
case ELFOSABI_LINUX: | |
PRINT("OS/ABI:", "LINUX"); | |
break; | |
} | |
switch(ehdr->e_type) { | |
case ET_REL: | |
PRINT("Type:", "REL (Relocatable File)"); | |
break; | |
case ET_EXEC: | |
PRINT("Type:", "EXEC (Executable File)"); | |
break; | |
case ET_DYN: | |
PRINT("Type:", "DYN (Shared Object File)"); | |
break; | |
case ET_CORE: | |
PRINT("Type:", "CORE (Core File)"); | |
break; | |
default: | |
PRINT("Type:", "Unknown type"); | |
break; | |
} | |
printf(" %-30s%#lx\n", "Entry point address:", ehdr->e_entry); | |
printf(" %-30s%#lx (base10: %ld)\n", "Program ehdrs Offset:", ehdr->e_phoff, ehdr->e_phoff); | |
printf(" %-30s%#lx (base10: %ld)\n", "Section ehdrs Offset:", ehdr->e_shoff, ehdr->e_shoff); | |
printf(" %-30s%d (bytes)\n", "Size of program ehdrs:", ehdr->e_phentsize); | |
printf(" %-30s%d\n", "Number of program ehdrs:", ehdr->e_phnum); | |
printf(" %-30s%d (bytes)\n", "Size of section ehdrs:", ehdr->e_shentsize); | |
printf(" %-30s%d\n", "Number of section ehdrs:", ehdr->e_shnum); | |
#undef PRINT | |
} | |
void usage() | |
{ | |
fprintf(stderr, "Usage: relf <option(s)> <filename>\n"); | |
fprintf(stderr, " Display ELF information\n"); | |
fprintf(stderr, " Options are: \n"); | |
fprintf(stderr, " -h:\t Display the elf header\n"); | |
fprintf(stderr, " -l:\t Display the all program headers\n"); | |
fprintf(stderr, " -S:\t Display the all section headers\n"); | |
} | |
int main(int argc, char **argv) | |
{ | |
int opt; | |
int show_header = 0; | |
int show_sections = 0; | |
int show_program_hdr = 0; | |
int show_symtab = 0; | |
int opt_count = 0; | |
int fileno; | |
struct stat st; | |
unsigned char *mem; | |
while ((opt = getopt(argc, argv, "hlSs")) != -1) { | |
opt_count ++; | |
switch(opt) { | |
case 'h': | |
show_header = 1; | |
break; | |
case 'S': | |
show_sections = 1; | |
break; | |
case 's': | |
show_symtab = 1; | |
break; | |
case 'l': | |
show_program_hdr = 1; | |
break; | |
default: | |
usage(); | |
exit(EXIT_FAILURE); | |
} | |
} | |
if ((argc > 1) && (opt_count == 0)) { | |
usage(); | |
exit(EXIT_FAILURE); | |
} | |
if ((fileno = open(argv[optind], O_RDONLY)) < 0) { | |
perror("Error when open file"); | |
exit(EXIT_FAILURE); | |
} | |
if (fstat(fileno, &st) < 0) { | |
perror("Error getting file attribute"); | |
exit(EXIT_FAILURE); | |
} | |
/* First read the header to decide the file is ELF32 or ELF64 */ | |
mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fileno, 0); | |
if (mem == MAP_FAILED) { | |
fprintf(stderr, "Error when mapping file\n"); | |
exit(EXIT_FAILURE); | |
} | |
close(fileno); | |
if (show_header) { | |
dumpELFHeader(mem); | |
} | |
if (show_program_hdr) { | |
dumpProgramHeaders(mem); | |
} | |
if (show_sections) { | |
dumpSectionHeaders(mem); | |
} | |
if (show_symtab) { | |
dumpSymTab(mem); | |
} | |
munmap(mem, st.st_size); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment