Thread: Printing readable data from ELF file

  1. #1
    Registered User
    Join Date
    Oct 2020
    Posts
    69

    Printing readable data from ELF file

    I want to print the file, program and section headers from an ELF file, but I'm getting some weird results.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    
    typedef struct{
        uint8_t e_ident[16];
        uint16_t e_type; 
        uint16_t e_machine;
        uint32_t e_version;
        uint32_t e_entry;
        uint32_t e_phoff;
        uint32_t e_shoff;
        uint32_t e_flags;
        uint16_t e_ehsize;
        uint16_t e_phentsize;
        uint16_t e_phnum;
        uint16_t e_shentsize;
        uint16_t e_shnum;
        uint16_t e_shstrndx;
    }ELFHEADER;
    
    
    typedef struct{
        uint32_t p_type;
    }PHEADER;
    
    
    typedef struct{
        uint32_t sh_name;
    }SHEADER;
    
    
    int main(int argc, char **argv)
    {
        FILE *fin = fopen("elf.out", "rb");
        ELFHEADER elf;
    
        int x64 = 0;
    
    
        if(fin == NULL)
        {
            fprintf(stderr, "ERROR opening the file\n");
            exit(-1);
        }
    
    
        fread(&elf,sizeof(elf), 1, fin);
    
    
        printf("ELF Header:\n");
    
    
        printf("Magic:\t");
        for(int i = 0; i < 16; i++)
        {
            printf("%02x ", elf.e_ident[i]);
        }
    
    
        printf("\nClass:\t");
        if(elf.e_ident[4] == 1)
        {
            printf("ELF32\n");
            x64 = 0;
        }
        else
        {
            printf("ELF64\n");
            x64 = 1;
        }
    
    
        printf("Data:\t");
        if(elf.e_ident[5] == 1)
        {
            printf("little endian\n");
        }
        else
            printf("big endian\n");
        printf("Version: %x\n", elf.e_ident[6]);
    
    
        printf("OS:\t");
    
    
        switch(elf.e_ident[7])
        {
            case 0x00:
                printf("SYSTEM V\n");
                break;
            case 0x01:
                 printf("HP-UX\n");
                 break;
            case 0x02:
                 printf("NET BSD\n");
                 break;
            case 0x03:
                printf("Linux\n");
                break;
            case 0x04:
                 printf("HP-UX\n");
                 break;
            case 0x05:
                 printf("GNU Hurd\n");
                 break;
            case 0x06:
                printf("Solaris\n");
                break;
            case 0x07:
                 printf("AIX\n");
                 break;
            case 0x08:
                 printf("IRIX\n");
                 break;
            case 0x09:
                printf("FreeBSD\n");
                break;
            case 0x0A:
                 printf("TRU64\n");
                 break;
            case 0x0B:
                 printf("Novell Modesto\n");
                 break;
            case 0x0C:
                printf("OpenBSD\n");
                break;
            case 0x0D:
                 printf("OpenVMS\n");
                 break;
            case 0x0E:
                 printf("NonStop Kernel\n");
                 break;
            case 0x0F:
                printf("AROS\n");
                break;
            case 0x10:
                 printf("Fenix OS\n");
                 break;
            case 0x11:
                 printf("CloudABI\n");
                 break;
            case 0x12:
                printf("Stratus Technologies OpenVOS\n");
                break;
        }
    
    
        printf("ABI Version:\t %x\n", elf.e_ident[8]);
        printf("Type:\t");
    
    
        switch(elf.e_type)
        {
            case 0x00:
                printf("NONE\n");
                break;
            case 0x01:
                 printf("REL\n");
                 break;
            case 0x02:
                 printf("EXEC\n");
                 break;
            case 0x03:
                printf("DYN\n");
                break;
            case 0x04:
                 printf("CORE\n");
                 break;
            case 0x05:
                 printf("LOOS\n");
                 break;
            case 0x06:
                printf("HIOS\n");
                break;
            case 0x07:
                 printf("LOPROC\n");
                 break;
            case 0x08:
                 printf("HIPROC\n");
                 break;
        }
    
    
    //    fseek(fin, 2, SEEK_CUR);
        printf("Machine:\t");
    
    
        switch(elf.e_machine)
        {
            case 0x00:
                printf("No specific instruction set\n");
                break;
            case 0x01:
                 printf("AT&T WE 32100");
                 break;
            case 0x02:
                 printf("SPARC\n");
                 break;
            case 0x03:
                printf("x86\n");
                break;
            case 0x04:
                 printf("Motorola 68000k (M68k)\n");
                 break;
            case 0x05:
                 printf("Motorola 88000 (M88k)\n");
                 break;
            case 0x06:
                printf("Intel MCU\n");
                break;
            case 0x07:
                 printf("Intel 80860\n");
                 break;
            case 0x08:
                 printf("MIPS\n");
                 break;
            case 0x09:
                printf("IBM_System/370\n");
                break;
            case 0x0A:
                 printf("MIPS RS3000 Little-endian\n");
                 break;
            case 0x0B:
                 printf("Reserved for future use\n");
                 break;
            case 0x0C:
                printf("Reserved for future use\n");
                break;
            case 0x0D:
                 printf("Reserved for future use\n");
                 break;
            case 0x0E:
                printf("Hewlett-Packard PA-RISC\n");
                break;
            case 0x0F:
                 printf("Reserved for future use\n");
                 break;
            case 0x13:
                 printf("Intel 80960\n");
                 break;
            case 0x14:
                printf("PowerPC\n");
                break;
            case 0x15:
                 printf("PowerPC(64-bit)\n");
                 break;
            case 0x16:
                 printf("S390, including S390x\n");
                 break;
            case 0x28:
                printf("ARM (up to ARMv7/Aarch32)\n");
                break;
            case 0x2A:
                 printf("SuperH\n");
                 break;
            case 0x32:
                 printf("IA-64\n");
                 break;
            case 0x3E:
                printf("amd64\n");
                break;
            case 0x8C:
                 printf("TMS320C6000 Family\n");
                 break;
            case 0xB7:
                 printf("ARM 64-bits (ARMv8/Aarch64)\n");
                 break;
            case 0xF3:
                printf("RISC-V\n");
                break;
            case 0xF7:
                 printf("Berkeley Packet Filter\n");
                 break;
        case 0x101:
            printf("WDC 65C816\n");
            break;
    
    
        }
    
            printf("Version:\t %x\n", elf.e_version);
    //    fseek(fin, 4, SEEK_CUR);
        //fread(&elfx64,sizeof(elfx64), 1, fin);
        printf("Entry point address:\t %x\n", elf.e_entry);
        printf("Start of program headers:\t %x\n", elf.e_phoff);
        printf("Start of section headers:\t %x\n", elf.e_shoff);
        printf("Flags:\t %x\n", elf.e_flags);
        printf("Size of this header:\t ");
    
    
        if(x64 == 1) // if we have 64-bit architecture
        {
            printf("64 (bytes)\n");
        }
        else
            printf("52 (bytes)\n"); 
    
    
        printf("Size of program headers:\t %x\n", elf.e_phentsize);
        printf("Number of program headers:\t %x\n", elf.e_phnum);
        printf("Size of section headers:\t %x\n", elf.e_shentsize);
        printf("Number of section headers:\t %x\n",elf.e_shnum);
        printf("Section header string table index:\t %x\n", elf.e_shstrndx);
    Output:
    ELF Header:
    Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
    Class: ELF64
    Data: little endian
    Version: 1
    OS: SYSTEM V
    ABI Version: 0
    Type: DYN
    Machine: amd64
    Version: 1
    Entry point address: 1160
    Start of program headers: 0
    Start of section headers: 40
    Flags: 0
    Size of this header: 64 (bytes)
    Size of program headers: 0
    Number of program headers: 0
    Size of section headers: 0
    Number of section headers: 0
    Section header string table index: 0


    Expected Output:
    ELF Header:
    Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
    Class: ELF64
    Data: 2's complement, little endian
    Version: 1 (current)
    OS/ABI: UNIX - System V
    ABI Version: 0
    Type: DYN (Shared object file)
    Machine: Advanced Micro Devices X86-64
    Version: 0x1
    Entry point address: 0x67d0
    Start of program headers: 64 (bytes into file)
    Start of section headers: 140224 (bytes into file)
    Flags: 0x0
    Size of this header: 64 (bytes)
    Size of program headers: 56 (bytes)
    Number of program headers: 13
    Size of section headers: 64 (bytes)
    Number of section headers: 30
    Section header string table index: 29


    As you can see, everything was working as expected until the Entry point address, I've used this Executable and Linkable Format - Wikipedia as a model, and for the expected output I used the command readelf -h ls in a linux terminal. My best guess is that the offset (first column on wiki) is the issue here, I tried using fseek but not a lot of improvement. Any ideas? Thank you in advance and sorry for the long code!

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    On the wikipedia page it shows that there are different sizes of some of the values depending on whether it's 32 or 64 bits. For instance, obviously the entry point can't be 32 bits on a 64 bit machine. Also, remember that structs can have padding. Try reading in all of the values separately instead of as one struct.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
     
    const char *sys_name(uint8_t);
    const char *type_name(uint16_t);
    const char *machine_name(uint16_t);
     
    #define READ(var) fread(&(var), sizeof(var), 1, fin)
     
    int main() {
        FILE *fin = fopen("a.out", "rb");
        if (!fin) {
            fprintf(stderr, "ERROR opening the file\n");
            exit(-1);
        }
     
        uint8_t e_ident[16];
        uint16_t e_type, e_machine;
        uint32_t e_version;
        READ(e_ident);
        READ(e_type);
        READ(e_machine);
        READ(e_version);
     
        printf("ELF Header:\n");
        printf("Magic:\t");
        for (int i = 0; i < 16; i++)
            printf("%02x ", e_ident[i]);
        printf("\nClass:\t");
        if (e_ident[4] == 1)
            printf("ELF32\n");
        else
            printf("ELF64\n");
        printf("Data:\t");
        if (e_ident[5] == 1)
            printf("little endian\n");
        else
            printf("big endian\n");
        printf("Version: %u\n", e_ident[6]);
        printf("OS:\t%s\n", sys_name(e_ident[7]));
        printf("ABI Version:\t %u\n", e_ident[8]);
        printf("Type:\t%s\n", type_name(e_type));
        printf("Machine:\t%s\n", machine_name(e_machine));
        printf("Version:\t 0x%x\n", e_version);
     
        if (e_ident[4] == 1) { // 32_bits
            uint32_t e_entry, e_phoff, e_shoff;
            READ(e_entry);
            READ(e_phoff);
            READ(e_shoff);
            printf("Entry point address:\t 0x%x\n", e_entry);
            printf("Start of program headers:\t %u\n", e_phoff);
            printf("Start of section headers:\t %u\n", e_shoff);
        }
        else if (e_ident[4] == 2) { // 64_bits
            uint64_t e_entry, e_phoff, e_shoff;
            READ(e_entry);
            READ(e_phoff);
            READ(e_shoff);
            printf("Entry point address:\t 0x%lx\n", e_entry);
            printf("Start of program headers:\t %lu\n", e_phoff);
            printf("Start of section headers:\t %lu\n", e_shoff);
        }
        else {
            fprintf(stderr, "bad class: %d\n", e_ident[4]);
            exit(-1);
        }
     
        uint32_t e_flags;
        uint16_t e_ehsize, e_phentsize, e_phnum;
        uint16_t e_shentsize, e_shnum, e_shstrndx;
        READ(e_flags);
        READ(e_ehsize);
        READ(e_phentsize);
        READ(e_phnum);
        READ(e_shentsize);
        READ(e_shnum);
        READ(e_shstrndx);
     
        printf("Flags:\t 0x%x\n", e_flags);
        printf("Size of this header:\t ");
        if (e_ident[4] == 2) // if 64-bit architecture
            printf("64 (bytes)\n");
        else
            printf("52 (bytes)\n"); 
        printf("Size of program headers:\t %u\n", e_phentsize);
        printf("Number of program headers:\t %u\n", e_phnum);
        printf("Size of section headers:\t %u\n", e_shentsize);
        printf("Number of section headers:\t %u\n", e_shnum);
        printf("Section header string table index:\t %u\n", e_shstrndx);
     
        fclose(fin);
        return 0;
    }
     
    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";
    }
    Last edited by john.c; 03-10-2021 at 05:29 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Oct 2020
    Posts
    69
    Quote Originally Posted by john.c View Post
    Code:
    const char *sys_name(uint8_t);
    const char *type_name(uint16_t);
    const char *machine_name(uint16_t);
    Could you please explain this part? I don't usually use global variables, why did we declare them globally and not in main. Also, would it be possible to use a struct until entry, then use another struct for entry-shoff (so what is system architecture-dependent) and another struct for the rest. If so, how can I use the results of the said struct based on the result of e_ident[4]? So what I'm trying to say is if I could use structs/unions in solving this. Thank you again!

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > Could you please explain this part? I don't usually use global variables,
    They're not global variables.

    They're function prototypes for the functions that are defined later on in the source file.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Oct 2020
    Posts
    69
    Quote Originally Posted by Salem View Post
    They're function prototypes for the functions that are defined later on in the source file.
    I see, I've never encountered them before, that's why

  6. #6
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,101
    Quote Originally Posted by rmmstn View Post
    I see, I've never encountered them before, that's why
    Then you need to go back and thoroughly study C. Function prototypes are part of the chapter on functions in any book on the C Programming Language. You would have learned about the three major parts of creating and using functions:
    • Function declaration / prototype
    • Function definition
    • Function call

    Plus other related topics:
    • Extern vs. static functions
    • Function pointers
    • Creating and compiling programs with functions in multiple .c files
    • etc...

  7. #7
    Registered User
    Join Date
    Oct 2020
    Posts
    69
    Quote Originally Posted by rstanley View Post
    Then you need to go back and thoroughly study C. Function prototypes are part of the chapter on functions in any book on the C Programming Language. You would have learned about the three major parts of creating and using functions:
    • Function declaration / prototype
    • Function definition
    • Function call

    Plus other related topics:
    • Extern vs. static functions
    • Function pointers
    • Creating and compiling programs with functions in multiple .c files
    • etc...
    Nevermind, I didn't see he defined each function after main :/

  8. #8
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    would it be possible to use a struct
    Sure.
    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";
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  9. #9
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    277
    Quote Originally Posted by john.c View Post
    Sure.
    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";
    }
    Nice!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Printing ordered data from file
    By ipsilante in forum C Programming
    Replies: 1
    Last Post: 01-23-2021, 06:56 AM
  2. Human-readable data storage format - tips?
    By Elysia in forum Tech Board
    Replies: 7
    Last Post: 01-18-2014, 01:57 AM
  3. Reading data from a file and printing it
    By Linux Trojan in forum C Programming
    Replies: 27
    Last Post: 07-02-2011, 12:45 PM
  4. extracting and printing data from a .dat file
    By z0diark in forum C Programming
    Replies: 3
    Last Post: 11-16-2009, 05:07 PM
  5. printing data to a file
    By coralreef in forum C Programming
    Replies: 3
    Last Post: 11-02-2006, 08:10 PM

Tags for this Thread