danilo
danilo

Reputation: 56

Find text section of elf in C

What is the right way to get text section of Elf file and display it's content? I've tried to do it myself but it's showing just 250 bites of data, but when I try with readelf command it shows me much more. I think I just made wrong offset to get the section. What is the right approach?

Update: I supplemented the code. Now, it gives me segmentation fault when I want to print symbol names.

Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>

int main(int argc, char *argv[]) {


    int fd;
    int val;

    Elf32_Ehdr elfHdr;
    Elf32_Shdr sectHdr;
    Elf32_Shdr textSection;
    Elf32_Shdr *symtab = NULL;
    Elf32_Shdr *strtab = NULL;
    FILE* ElfFile = NULL;
    char* SectNames = NULL;

    if(argc != 2) {
        perror("Chose file!");
        return -1;
    }   



    ElfFile = fopen(argv[1],"r");
    if(ElfFile == NULL) {
        printf("Error opening file");
        return -1;
    }


    fread(&elfHdr, 1, sizeof(Elf32_Ehdr), ElfFile);




    fseek(ElfFile, elfHdr.e_shoff + elfHdr.e_shstrndx * elfHdr.e_shentsize, SEEK_SET);
    fread(&sectHdr, 1, sizeof(sectHdr), ElfFile);
    SectNames = malloc(sectHdr.sh_size);
    fseek(ElfFile, sectHdr.sh_offset, SEEK_SET);
    fread(SectNames, 1, sectHdr.sh_size, ElfFile);

    printf("\nSECTION HEADERS:\n\n");



    for (int idx = 0; idx < elfHdr.e_shnum; idx++){
        char* name = "";

        fseek(ElfFile, elfHdr.e_shoff + idx * sizeof(sectHdr), SEEK_SET);
        fread(&sectHdr, 1, sizeof(sectHdr), ElfFile);

        // print section name
        if (sectHdr.sh_name);
        name = SectNames + sectHdr.sh_name;

        if(strcmp(name,".text") == 0) {
            textSection = sectHdr;
        }

        if(strcmp(name, ".symtab") == 0) {
            //symbolTable = (Elf32_Sym*)sectHdr.sh_addr;
            symtab = (Elf32_Shdr*) &sectHdr;
        }
        if(strcmp(name, ".strtab") == 0) {
            strtab = (Elf32_Shdr *) &sectHdr;
        }

        printf("%s\n", name);
    }

    printf("\nTEXT SECTION (zacetek: 0x%lx):\n\n", textSection.sh_addr);
    printf("Section size: %i\n\n", textSection.sh_size);

    fseek(ElfFile, textSection.sh_addr, SEEK_SET);
    
    for(int i=0; i < textSection.sh_size; i = i+32) {
        int value;
        fseek(ElfFile, textSection.sh_addr + i, SEEK_SET);
        fread(&value, 1, sizeof(value), ElfFile);
        printf("0x%x\n", value);
    }
    
    fclose(ElfFile);

    //read file content to the buffer

    char* source = NULL;
    FILE *fp = fopen(argv[1],"r");
    if(fp != NULL) {
        if(fseek(fp, 0L, SEEK_END) == 0) {
            long bufsize = ftell(fp);
            if(bufsize == -1) {
                printf("Error setting buffer size!");
                return -1;
            }
            source = malloc(sizeof(char) * (bufsize + 1));

            if(fseek(fp, 0L, SEEK_SET) != 0) {
                printf("Error line 120");
                return -1;
            }
            size_t newLen = fread(source, sizeof(char), bufsize, fp);
            if(ferror(fp) != 0) {
                fputs("Error reading file", stderr);
            }
            else {
                source[newLen++] = '\0';
            }
        }
        fclose(fp);
    }

    char* data = &source;


    printf("\nSymbol table names:\n\n");
    printf("\nSize of symbolTableHeader: %i\n", symtab->sh_size);
    
    printf("\nSymbol table names:\n\n");
    
    
    Elf32_Sym *sym = (Elf32_Sym*)(data + symtab->sh_offset);
    char *str = (char*) (data + strtab->sh_offset);

    for(size_t i = 0; i < symtab->sh_size / sizeof(Elf32_Sym); i++) {
        printf("%s\n", str + sym[i].st_name); //this is where it throws me segmentation fault (core dumped)
    }





    return 0;
}

Upvotes: 3

Views: 3037

Answers (1)

Employed Russian
Employed Russian

Reputation: 213754

I think I just made wrong offset to get the section.

Your program iterates over all sections, so at the end of the first loop, sectHdr contains the section header of the last section, which is unlikely to the .text section.

So in the second loop you print the contents of whatever section happened to be the last.

To print the .text section, you need to save its section header when you come across it.

Update:

So if I do for loop over all sections and then strcmp with every name, and when I find matching with .text I save the adress of that header.

You don't save the address of that header -- you save the contents.

What about if I want to access to Symbol table, which is not Section (has its own type: Elf32_Sym), how do I reach that table?

The symbol table does have its own section (containing a set of Elf32_Sym records). See this answer.

Update 2:

This code:

    if(strcmp(name, ".symtab") == 0) {
        //symbolTable = (Elf32_Sym*)sectHdr.sh_addr;
        symtab = (Elf32_Shdr*) &sectHdr;
    }
    if(strcmp(name, ".strtab") == 0) {
        strtab = (Elf32_Shdr *) &sectHdr;
    }

is obviously broken: you save a pointer to memory that you overwrite on each iteration of the loop. You must save a copy of .symtab and .strtab section header (just as you do for .text).

An even better solution is to mmap the entire file into memory. Then you can save pointers to various parts of it (that's what the other answer does -- the data there points to the start of mmaped region).

Upvotes: 1

Related Questions