Skip to content

Instantly share code, notes, and snippets.

@telescreen
Last active September 11, 2020 02:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save telescreen/14fb685f8651b6a85ee40b4669095008 to your computer and use it in GitHub Desktop.
Save telescreen/14fb685f8651b6a85ee40b4669095008 to your computer and use it in GitHub Desktop.
Parse ELF Header
#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