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