4

This post is asking about modifying / patching or even hexediting - due to lack of better methods (see Notes) an elf binary to adjust functions / symbols / versions they point to - and keeping ld.so happy + asking for some Tools to ease this process.

Recompilation of the binaries is not in the scope of the solution I am looking for, neither is a dissassembly of the binary, neither is using LD_* env. variables (not because they aren't valid solutions, but due to my different use-case) except for solutions akin to the one here: writing a 'dummy' function, which exposes the desired soname, and does tricks ld.so in some clever way.

There are 2 situations, for which I'd appreciate some help from the community:

  1. The first one, binary_a, has following unmet dependency, amongst others:
$  ldd binary_a 
binary_a: /usr/lib/x86_64-linux-gnu/libcdio.so.13: version `CDIO_13' not found (required by binary_a) 

which is normal, since my OS has a newer version of libcdio, namely libcdio.so.17. My goal is to try to adjust the binary to use that one instead.

What I did was :

  • use an hexeditor (since I couldn't find a Tool to do that) to change CDIO_13 -> CDIO_17 in the .dynstr section (yes, this version appears in the libcdio.so.17 file - checked that using objdump -SdV libcdio.so.17 or objdump -T libcdio.so.17 )
  • use patchelf (or again hexedit) as such:

$ patchelf --replace-needed libcdio.so.13 libcdio.so.17 binary_a

but this doesn't seems to work, since ldd still complains (although it is actually ld.so which complains, since ldd is just a bash wrapper script around it):

$ LD_DEBUG=libs  ldd ./binary_a | fgrep -i libcdio.
     30345:     find library=libcdio.so.17 [0]; searching
     30345:       trying file=/usr/lib/x86_64-linux-gnu/libcdio.so.17
     30345:     /usr/lib/x86_64-linux-gnu/libcdio.so.17: error: **version lookup error: version `CDIO_17' not found (required by ./binary_a) (continued)**
**./binary_a: /usr/lib/x86_64-linux-gnu/libcdio.so.17: version `CDIO_17' not found (required by ./binary_a)**
        libcdio.so.17 => /usr/lib/x86_64-linux-gnu/libcdio.so.17 (0x00007fbadca1e000)

To confirm: at this point, there are not references to the old .so , or to the old version (CDIO_13) in the binary, also sonames for the dependency (see soname explained ) is also valid & objdump / readelf have no issues with modified binary: they see the new version, i.e. CDIO_17 throughout the binary.

My guess is that the problem for which ld rejects the binary might be related to the vna_hash entry in the Elfxx_Vernaux struct. (see 3 for reference) being messed up by the edit, or some other anti-tampering safeguards which elf format has, makes ld to invalidate it, or is ld.so's cache somehow interferring ? Or is it that I'm hitting the case "if two .so file has same function name, only the first one would accepted." mentioned 2 s.o. same name ?

The removal of libcdio (+ some other cd/dvd-related libs), should, theoretically, not impact the functionality of binary_a (media player), since the laptop doesn't have a dvd drive anyway. There is also the possibility of 'weakening' those symbols, however, am not sure if that would suffice to have ld.so ignore them - haven't tested, however according to 5 it should take me closer to reaching my goal.

  1. The second case involves, binary_b, which has a dependency to libncurses.so.6, on version NCURSES6_5.0.19991023. My goal here is to force it to use libncurses.so.5 which only exposes version NCURSES_5.0.19991023 -notice the lack of '6' after 'NCURSES' which, by hexediting it, would change the length of the corresponding entry in the .dynstr Table. As with previous binary, this version exists in the libncurses.so.5 file, and the file is found & readable by ldd.

Notes:

(1) I've tried elfsh (which after fixing some compile error, errors out about not recognising the elf header), rizin/cutter...

I've tried patchelf (before doing any modification), which fails for following command, presumably because the file is stripped already:

- $ patchelf --remove-needed libcdio.so.13  binary_a
- $ ldd binary_a 
Inconsistency detected by ld.so: dl-version.c: 205: _dl_check_map_versions: Assertion `needed != NULL' failed!

(2) Objcopy and elfedit seem like good candidates; however, the info gathered from their man pages about (if) such possibility & how to do it is lacking + my understanding about this whole s.o. libs subject - remains meager, so I'd appreaciate some good pointers here !

(3) The other idea was to try to manually add a new dummy version entry in the .dynstr Table, which is not trivial (see dt_hash article), but I'd need a more step-by-step walkthrough of what the steps should be. Thus, I would add NCURSES_5.0.19991023, and take its offset and overwrite the vna_name entry in the corresponding Elfxx_Vernaux structure with this offset and / or overwriting the vna_flags entry (?), not sure ... 3

There is a similar case in 5, in which the author deals with a similar case (although a more simplistic one, one in which the versions already exists in the binary), and another one in Trick ldand those solutions I could maybe use, provided I'd first managed to somehow add my needed version in the elf header...

Any pointers as to what is wrong (about ldd complains) and how to achieve my goals, would be very much appreciated, Thanks !

References:

cg79
  • 63
  • 5

0 Answers0