Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define READ(f, var) fread(&(var), sizeof(var), 1, (f))
typedef struct ElfHeader {
uint8_t ident[16];
uint16_t type, machine;
uint32_t version;
union { uint32_t entry32; uint64_t entry64; };
union { uint32_t phoff32; uint64_t phoff64; };
union { uint32_t shoff32; uint64_t shoff64; };
uint32_t flags;
uint16_t ehsize, phentsize, phnum;
uint16_t shentsize, shnum, shstrndx;
} ElfHeader;
void readElfHeader(FILE *fin, ElfHeader *elf);
void printElfHeader(const ElfHeader *elf);
const char *sys_name(uint8_t sys);
const char *type_name(uint16_t type);
const char *machine_name(uint16_t machine);
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fin = fopen(argv[1], "rb");
if (!fin) {
fprintf(stderr, "Error: cannot open input file\n");
exit(EXIT_FAILURE);
}
ElfHeader elf;
readElfHeader(fin, &elf);
fclose(fin);
printElfHeader(&elf);
return 0;
}
void readElfHeader(FILE *fin, ElfHeader *elf) {
READ(fin, elf->ident);
READ(fin, elf->type);
READ(fin, elf->machine);
READ(fin, elf->version);
if (elf->ident[4] == 1) { // 32_bits
READ(fin, elf->entry32);
READ(fin, elf->phoff32);
READ(fin, elf->shoff32);
} else if (elf->ident[4] == 2) { // 64_bits
READ(fin, elf->entry64);
READ(fin, elf->phoff64);
READ(fin, elf->shoff64);
} else {
fprintf(stderr, "Error: bad class: %d\n", elf->ident[4]);
exit(EXIT_FAILURE);
}
READ(fin, elf->flags);
READ(fin, elf->ehsize);
READ(fin, elf->phentsize);
READ(fin, elf->phnum);
READ(fin, elf->shentsize);
READ(fin, elf->shnum);
READ(fin, elf->shstrndx);
}
void printElfHeader(const ElfHeader *elf) {
printf("ELF Header:\n");
printf(" Magic: ");
for (int i = 0; i < 16; i++) printf(" %02x", elf->ident[i]);
printf("\n %-34s %s\n", "Class:", elf->ident[4] == 1 ? "ELF32" : "ELF64");
printf(" %-34s %s endian\n", "Data:", elf->ident[5] == 1 ? "little" : "endian");
printf(" %-34s %u\n", "Version:", elf->ident[6]);
printf(" %-34s %s\n", "OS:", sys_name(elf->ident[7]));
printf(" %-34s %u\n", "ABI Version:", elf->ident[8]);
printf(" %-34s %s\n", "Type:", type_name(elf->type));
printf(" %-34s %s\n", "Machine:", machine_name(elf->machine));
printf(" %-34s %x\n", "Version:", elf->version);
if (elf->ident[4] == 1) { // 32_bits
printf(" %-34s %x\n", "Entry point address:", elf->entry32);
printf(" %-34s %u\n", "Start of program headers:", elf->phoff32);
printf(" %-34s %u\n", "Start of section headers:", elf->shoff32);
} else { // 64_bits
printf(" %-34s %lx\n", "Entry point address:", elf->entry64);
printf(" %-34s %lu\n", "Start of program headers:", elf->phoff64);
printf(" %-34s %lu\n", "Start of section headers:", elf->shoff64);
}
printf(" %-34s %x\n", "Flags:", elf->flags);
printf(" %-34s %u (bytes)\n", "Size of this header:", elf->ident[4] == 1 ? 32 : 64);
printf(" %-34s %u\n", "Size of program headers:", elf->phentsize);
printf(" %-34s %u\n", "Number of program headers:", elf->phnum);
printf(" %-34s %u\n", "Size of section headers:", elf->shentsize);
printf(" %-34s %u\n", "Number of section headers:", elf->shnum);
printf(" %-34s %u\n", "Section header string table index:", elf->shstrndx);
}
const char *sys_name(uint8_t sys) {
switch (sys) {
case 0x00: return "SYSTEM V";
case 0x01: return "HP-UX";
case 0x02: return "NET BSD";
case 0x03: return "Linux";
case 0x04: return "HP-UX";
case 0x05: return "GNU Hurd";
case 0x06: return "Solaris";
case 0x07: return "AIX";
case 0x08: return "IRIX";
case 0x09: return "FreeBSD";
case 0x0A: return "TRU64";
case 0x0B: return "Novell Modesto";
case 0x0C: return "OpenBSD";
case 0x0D: return "OpenVMS";
case 0x0E: return "NonStop Kernel";
case 0x0F: return "AROS";
case 0x10: return "Fenix OS";
case 0x11: return "CloudABI";
case 0x12: return "Stratus Technologies OpenVOS";
}
return "Unknown";
}
const char *type_name(uint16_t type) {
switch (type) {
case 0x00: return "NONE";
case 0x01: return "REL";
case 0x02: return "EXEC";
case 0x03: return "DYN";
case 0x04: return "CORE";
case 0xFE00: return "LOOS";
case 0xFEFF: return "HIOS";
case 0xFF00: return "LOPROC";
case 0xFFFF: return "HIPROC";
}
return "Unknown";
}
const char *machine_name(uint16_t machine) {
switch (machine) {
case 0x00: return "No specific instruction set";
case 0x01: return "AT&T WE 32100";
case 0x02: return "SPARC";
case 0x03: return "x86";
case 0x04: return "Motorola 68000k (M68k)";
case 0x05: return "Motorola 88000 (M88k)";
case 0x06: return "Intel MCU";
case 0x07: return "Intel 80860";
case 0x08: return "MIPS";
case 0x09: return "IBM_System/370";
case 0x0A: return "MIPS RS3000 Little-endian";
case 0x0B: return "Reserved for future use";
case 0x0C: return "Reserved for future use";
case 0x0D: return "Reserved for future use";
case 0x0E: return "Hewlett-Packard PA-RISC";
case 0x0F: return "Reserved for future use";
case 0x13: return "Intel 80960";
case 0x14: return "PowerPC";
case 0x15: return "PowerPC(64-bit)";
case 0x16: return "S390, including S390x";
case 0x28: return "ARM (up to ARMv7/Aarch32)";
case 0x2A: return "SuperH";
case 0x32: return "IA-64";
case 0x3E: return "amd64";
case 0x8C: return "TMS320C6000 Family";
case 0xB7: return "ARM 64-bits (ARMv8/Aarch64)";
case 0xF3: return "RISC-V";
case 0xF7: return "Berkeley Packet Filter";
case 0x101: return "WDC 65C816";
}
return "Unknown";
}