Questions regarding editing an elf executable

Anastasios Andronidis anastasis90@gmail.com
Thu Jun 25 01:46:11 GMT 2020


Hello everyone,

please forgive my rather noob-ish question but I'm very confused on how libelf works. 

My end goal is to add a DT_NEEDED entry into an arbitrary elf file, but before this I should just print the DT_NEEDED entries like this:

```C

// Some code that copies a source_elf_file to a new target_elf_file so
// we don't destroy the original binary.

int fd = open(target_elf_file, O_RDWR, 0);

Elf *e = elf_begin(fd, ELF_C_RDWR_MMAP, NULL);

Elf_Scn *scn = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
  GElf_Shdr shdr;
  gelf_getshdr(scn, &shdr);

  if (shdr.sh_type == SHT_DYNAMIC) {
    Elf_Data *data = elf_getdata(scn, data);

    size_t sh_entsize = gelf_fsize(e, ELF_T_DYN, 1, EV_CURRENT);

    for (size_t i = 0; i < shdr.sh_size / sh_entsize; i++) {
      GElf_Dyn dynmem;
      GElf_Dyn *dyn = gelf_getdyn(data, i, &dynmem);

      if (dyn->d_tag == DT_NEEDED) {
        printf("Lib: %s\n", elf_strptr(e, shdr.sh_link, dyn->d_un.d_val));
      }
   }
}

elf_update(e, ELF_C_WRITE);
elf_end(e);
close(fd);
```

1) Notice that I run `elf_update(e, ELF_C_WRITE);` in the end as I had the impression that this command should actually do nothing because I modified nothing. Unfortunately this is not what happens. The resulting elf executable is corrupted. I expected libelf would leave the elf file as it was, or at least produce a valid executable.

In addition, when I'm running `diff <(readelf -a orig_bin) <(readelf -a new_bin)` I see many differences. e.g  I see the following:

```
<       [Requesting program interpreter: ]
---
>       [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
```

Or with `readelf -l`:

```
...
  INTERP         0x0000000000005310 0x0000000000005310 0x0000000000005310
                 0x000000000000001c 0x000000000000001c  R      0x1
readelf: Error: Unable to read program interpreter name
      [Requesting program interpreter: ]
...
```

I using the latest libelf version 180 (manually compiled and installed, the same behavior exists in the default Ubuntu libelf) and running on Ubuntu 18.04.4 LTS.

2) In any case, as I said in the beginning, I want to add an extra entry to `.dynamic` and ideally an extra string to `.dynstr`.

So I tried the following:

2a) As a simple prototype I tried to update and existing GElf_Dyn entry. It didn't work, the elf file is again corrupted.

```C
...
if (shdr.sh_type == SHT_DYNAMIC) {
  ...

  GElf_Dyn dyn;
  assert(gelf_getdyn (data, 0, &dyn) == &dyn);

  dyn.d_un.d_val = 1; // This is a valid index

  gelf_update_dyn(data, 0, &dyn);
}
```

When I run `readelf -l` I see:
```
...
  DYNAMIC        0x000000000001fa38 0x000000000021fa38 0x000000000021fa38
                 0x0000000000000200 0x0000000000000200  RW     0x8
readelf: Warning: the .dynamic section is not contained within the dynamic segment
...
```

2b) I created a new data and copied the old to new. Didn't work.

```C
...
if (shdr.sh_type == SHT_DYNAMIC) {
  ...
  
  // Create a new data container for SHT_DYNAMIC and copy all old values.
  Elf_Data *new_data = elf_newdata(scn);
  *new_data = *data;

  // We will add 1 more entry.
  size_t new_data_size = data->d_size + sh_entsize;
  // Allocate and set the new data buffer.
  void *new_data_buf = malloc(new_data_size);
  new_data->d_buf = new_data_buf;
  new_data->d_size = new_data_size;

  // Copy old data to the new buffer.
  memcpy(new_data->d_buf, data->d_buf, data->d_size);

  // Add our new entry.
  GElf_Dyn *new_data_dyn = new_data->d_buf;
  new_data_dyn[new_data_size / sh_entsize-2].d_tag = DT_NEEDED;
  new_data_dyn[new_data_size / sh_entsize-2].d_un.d_val = 1;

}
```

I'm completely lost as I'm not sure if issue (1) blocks everything, while (2) is ok. Could someone point me to the right direction please?

Kindly,
Anastasios


More information about the Elfutils-devel mailing list