Les fichiers ELF, la suite

Dans le premier article, nous avons appris à lire l'en-tête d'un fichier exécutable à l'aide de la commande readelf.

Nous allons maintenant, montrer comment il est programmatiquement possible de lire le contenu d'un fichier elf.

le programme

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

/*
    Ce programme utilise la structure d?clar?e dans /usr/include/linux.h
    
    typedef struct elf64_hdr {
    unsigned char   e_ident[EI_NIDENT]; // ELF "magic number" 
        Elf64_Half e_type;
        Elf64_Half e_machine;
        Elf64_Word e_version;
        Elf64_Addr e_entry;     // Entry point virtual address    
        Elf64_Off e_phoff;      // Program header table file offset 
        Elf64_Off e_shoff;      // Section header table file offset 
        Elf64_Word e_flags;
        Elf64_Half e_shstrndx;
        Elf64_Half e_ehsize;
        Elf64_Half e_phentsize;
        Elf64_Half e_phnum;
        Elf64_Half e_shentsize;
        Elf64_Half e_shnum;
    } Elf64_Ehdr;
    
    Commande de compilation:
    $ gcc simple02.c -o simple02 -no-pie
*/


#include <elf.h>
#include <stdio.h>
#include <stdlib.h>


int main(void)
{
    Elf64_Ehdr Ehdr;
    FILE *infile;
    int i;

    infile = fopen("simple01", "r");

    fread(&Ehdr, sizeof(Elf64_Ehdr), 1, infile);
    // gestion d'erreur
    if(infile==NULL)
    {
        perror("Une erreur est survenue lors de l'ouverture du fichier elf...");
        exit(5001);
    }   
    // afficher des 4 premier bytes.
    for(i=0; i<4; i++)
    {
        printf(" Ehdr.e_ident[%d]: 0x02%x\n", i, Ehdr.e_ident[i]);
    }
    
    // afficher le e_type
    printf("     Ehdr.e_type: 0x%02x ", Ehdr.e_type);
        
    switch (Ehdr.e_type)
    {
        case ET_NONE:   puts("(ET_NONE: No file type.)");
                break;
        case ET_REL:    puts("(ET_REL: Relocatable file.)");
                break;
        case ET_EXEC:   puts("(ET_EXEC: Executable file.)");
                break;
        case ET_DYN:    puts("(ET_DYN: Shared object file.)");  
                break;
        case ET_CORE:   puts("(ET_CORE: Core file.)");
                break;
        case ET_LOPROC: puts("(ET_LOPROC: Processor Specific.)");
                break;
        case ET_HIPROC: puts("(ET_HIPROC: Processor Specific.)");
                break;
        default:
                puts("Unknown type !");
    }
            
    // afficher la e_machine
    printf("  Ehdr.e_machine: 0x%02x ", Ehdr.e_machine);
    if ( Ehdr.e_machine == EM_X86_64 )
    {
        puts("(EM_X86_64: AMD x86-64)");
    }
    // afficher la version
    printf("  Ehdr.e_version: 0x%04x\n", Ehdr.e_version);
    
    printf("    Ehdr.e_entry: 0x%08lx\n", Ehdr.e_entry);
    printf("    Ehdr.e_phoff: 0x%08lx\n", Ehdr.e_phoff);
    printf("    Ehdr.e_shoff: 0x%08lx\n", Ehdr.e_shoff);
    printf("    Ehdr.e_flags: 0x%04x\n", Ehdr.e_flags);
    printf(" Ehdr.e_shstrndx: 0x%02x\n", Ehdr.e_shstrndx);
    printf("   Ehdr.e_ehsize: 0x%02x\n", Ehdr.e_ehsize);
    printf("Ehdr.e_phentsize: 0x%02x\n", Ehdr.e_phentsize);
    printf("    Ehdr.e_phnum: 0x%02x\n", Ehdr.e_phnum);
    printf("Ehdr.e_shentsize: 0x%02x\n", Ehdr.e_shentsize);
    printf("    Ehdr.e_shnum: 0x%02x\n", Ehdr.e_shnum);
    
    return(0);
}
        

Voilà, le style est assez simple. L'obectif ici étant de montrer l'existance des fichiers d'include proposant des structures permettant de lire le contenu d'un fichier elf. Le programme pourrait être complété avec tous les codes e_machines déclarés dans le fichier /usr/include/linux/elf-em.h.

N'hésitez pas à vous construire un programme vous même pour bien comprendre comment tout cela fonctionne, et peut-être même à vous construire votre premier outil personnel vous permettant d'analyser votre fichier.

Vous pouvez aussi utiliser les pages du manuel Linux pour augmenter la précision des informations remontées.

$ man elf

Cette aide est disponible en français: man elf

La prochaine étape consite à lire les en-têtes de programmes et de sections.

Pour cela nous disposont déjà des indications retournée par notre programme.