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 0x5310 0x5310 0x5310
0x001c 0x001c 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:
```
...
DYNAMIC0x0001fa38 0x0021fa38 0x0021fa38
0x0200 0x0200 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