goblin: elf: The strtab in the section header is wrong.

example

$ cat src/main.rs
use std::fs::File;
use std::io::Read;
use std::env;
use goblin::elf::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
  let args = env::args().collect::<Vec<String>>();
  if args.len() < 2 {
      eprintln!("Usage: {} binary", args[0])
  } else {
      let mut f = File::open(&args[1])?;
      let mut buf = Vec::new();
      f.read_to_end(&mut buf)?;
      let elf = Elf::parse(&buf)?;
      let strtab = elf.shdr_strtab.to_vec().unwrap();
      for s in strtab {
          println!("{}", s)
      }
  }

  Ok(())
}
$ cargo r `which ls`
~ snip ~
    Finished dev [unoptimized + debuginfo] target(s) in 0.16s
     Running `target/debug/readstrtab /usr/bin/ls`

.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.data.rel.ro
.dynamic
.data
.bss
.gnu_debugaltlink
.gnu_debuglink
$ readelf -S `which ls`|grep "\["
  [Nr] Name              Type             Address           Offset
  [ 0]                   NULL             0000000000000000  00000000
  [ 1] .interp           PROGBITS         0000000000000318  00000318
  [ 2] .note.gnu.pr[...] NOTE             0000000000000338  00000338
  [ 3] .note.gnu.bu[...] NOTE             0000000000000358  00000358
  [ 4] .note.ABI-tag     NOTE             000000000000037c  0000037c
  [ 5] .gnu.hash         GNU_HASH         00000000000003a0  000003a0
  [ 6] .dynsym           DYNSYM           0000000000000450  00000450
  [ 7] .dynstr           STRTAB           0000000000001050  00001050
  [ 8] .gnu.version      VERSYM           0000000000001616  00001616
  [ 9] .gnu.version_r    VERNEED          0000000000001718  00001718
  [10] .rela.dyn         RELA             00000000000017b8  000017b8
  [11] .rela.plt         RELA             0000000000002bf8  00002bf8
  [12] .init             PROGBITS         0000000000004000  00004000
  [13] .plt              PROGBITS         0000000000004020  00004020
  [14] .plt.got          PROGBITS         00000000000046c0  000046c0
  [15] .plt.sec          PROGBITS         00000000000046f0  000046f0
  [16] .text             PROGBITS         0000000000004d80  00004d80
  [17] .fini             PROGBITS         0000000000018bc4  00018bc4
  [18] .rodata           PROGBITS         0000000000019000  00019000
  [19] .eh_frame_hdr     PROGBITS         000000000001e324  0001e324
  [20] .eh_frame         PROGBITS         000000000001ec70  0001ec70
  [21] .init_array       INIT_ARRAY       0000000000022fd0  00021fd0
  [22] .fini_array       FINI_ARRAY       0000000000022fd8  00021fd8
  [23] .data.rel.ro      PROGBITS         0000000000022fe0  00021fe0
  [24] .dynamic          DYNAMIC          0000000000023a58  00022a58
  [25] .got              PROGBITS         0000000000023c58  00022c58
  [26] .data             PROGBITS         0000000000024000  00023000
  [27] .bss              NOBITS           0000000000024280  00023268
  [28] .gnu_debugaltlink PROGBITS         0000000000000000  00023268
  [29] .gnu_debuglink    PROGBITS         0000000000000000  000232b4
  [30] .shstrtab         STRTAB           0000000000000000  000232e8

.pltdoesn’t appear in shdr_strtab.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 16 (12 by maintainers)

Most upvoted comments

StrTab::parse records the offset of the string so that it can be taken into account in get_at using a binary search.

The equivalent of readelf -S is to iterate over the section headers, and then use strtab.get_at(section.sh_name). There is never a good reason to iterate over individual strings in a StrTab in my opinion.

Edit: like this

      let elf = Elf::parse(&buf)?;
      for section in elf.section_headers {
          println!("{}", elf.shdr_strtab.get_at(section.sh_name).unwrap());
      }

Also, I would like to fix the parsing of Elf.shdr_strtab in the future, is this a wrong idea?

What needs fixing?