Search code examples
celfreadelf

How to find `.strtab` in an ELF file?


When running readelf -S I get:

  [27] .strtab           STRTAB           0000000000000000  00001630
       00000000000001d7  0000000000000000           0     0     1
  [28] .shstrtab         STRTAB           0000000000000000  00001807
       0000000000000103  0000000000000000           0     0     1

How can I get the index of .strtab? At first I tried to detect it using the Type field, but that won't work as you can see (27 and 28 have same type). Plus I can't be sure that it will be the first of type STRTAB to appear.

My struct with some explanations:

/*
 * Section header.
 */
typedef struct {
    Elf64_Word sh_name;    /* Section name (index into the
                       section header string table). */
    Elf64_Word sh_type;    /* Section type. */
    Elf64_Xword sh_flags;    /* Section flags. */
    Elf64_Addr sh_addr;    /* Address in memory image. */
    Elf64_Off sh_offset;    /* Offset in file. */
    Elf64_Xword sh_size;    /* Size in bytes. */
    Elf64_Word sh_link;    /* Index of a related section. */
    Elf64_Word sh_info;    /* Depends on section type. */
    Elf64_Xword sh_addralign;    /* Alignment in bytes. */
    Elf64_Xword sh_entsize;    /* Size of each entry in section. */
} Elf64_Shdr;

Solution

  • How can I get the index of .strtab?

    You read the Elf64_Shdrs one by one. When you've read the 28th entry, you will have read the .strtab, and you'll know its index.

    You'll know that it's the .strtab section by comparing its name with ".strtab" string literal.

    (You are probably intending to ask a different question, but if that's the case, you haven't expressed it well.)

    Update:

    Can't I do anything else rather than comparing strings

    Maybe. If your real question is finding the .strtab section, then not really.

    (which is somehow hard) can I assume it will be the first STRTAB in the file for example?

    There is no guarantee that that will be the case.

    Note: if you are worried about the speed of strcmp(), note that you can only do that strcmp() when .sh_type == SHT_STRTAB, and since there are usually at most two such sections in any given file, the concern about the speed of strcmp() is likely misplaced. Your code would look something like:

      if (shdr.sh_type == SHT_STRTAB) {
        const char *sh_name = contents_of_shstrab + shdr.sh_name;
        if (strcmp(sh_name, ".strtab") == 0) {
          /* found .strtab; do whatever you need with it */
        }
      }
    

    Update 2:

    your solution is wrong, please see: http://stackoverflow.com/questions/68074508/

    You can't claim that my solution is wrong, since I haven't provided a complete solution. It is also not wrong.

    Here is complete code (with most error checking omitted):

    #include <elf.h>
    #include <fcntl.h>
    #include <link.h>
    #include <stdio.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    
    int main(int argc, char *argv[])
    {
      if (argc < 1) return 1;
    
      int fd = open(argv[1], O_RDONLY);
      if (fd == -1) return 2;
    
      struct stat st_buf;
      if (fstat(fd, &st_buf) != 0) return 3;
    
      char *data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
      if (data == MAP_FAILED) return 4;
    
      const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr) *)data;
      const ElfW(Shdr) *shdr = (const ElfW(Shdr) *)(data + ehdr->e_shoff);
    
      const char *shstrtab = data + shdr[ehdr->e_shstrndx].sh_offset;
    
      for (int j = 0; j < ehdr->e_shnum; j++) {
        printf("[%2d] %s\n", j, shstrtab + shdr[j].sh_name);
      }
    
      return 0;
    }
    
    $ gcc -g t.c -Wall
    $ ./a.out ./a.out
    [ 0]
    [ 1] .interp
    [ 2] .note.gnu.build-id
    [ 3] .note.ABI-tag
    [ 4] .gnu.hash
    [ 5] .dynsym
    [ 6] .dynstr
    ...
    [32] .symtab
    [33] .strtab
    [34] .shstrtab