3

I have a number of shared libraries calling each other (.so, ARM, Android), binary-only.

I want to add logging to some functions, funcA(), ..., funcZ() defined in libsomething.so. The functions are called from libstuff1.so, ..., libstuffN.so. I can rename a function in the original library (keeping the name in the same bucket is a bit tricky, but possible).

I want to either:

  1. Add an extra library to the dependency list of the calling library, that is, libstuff1.so originally referenced only libsomething.so, and I want it to reference both libsomething.so and libOneMoreLib.so.
  2. Or, add an extra function to existing library, e.g. in libsomething.so, I rename funcA() to funbQ() and define (that is, add) funcA() to print logs and call funbQ().

How can I do any of these?

3

The required shared libraries are stored as DT_NEEDED entries in the dynamic section of the executable. This entry, in turn, points into the dynamic string table. So, to add another library, you will need to do something like this:

  1. Parse the list of program headers and find the PT_DYNAMIC entry
  2. Map its p_vaddr back to a file offset using the other PT_LOAD entries. (you could use the p_offset field of the PT_DYNAMIC entry itself but it's not guaranteed to be correct.)
  3. Read and parse the dynamic section entries until you hit DT_NULL.
  4. Remember address and size of the string table (DT_STRTAB/DT_STRSZ). Note that it is a virtual address and needs to be mapped back to file offset using the PT_LOAD entries.
  5. Extend the string table with your library's name. You will probably need to find some other place for it since there's unlikely to be enough space at the table's end. If so, you may need to add another PT_LOAD entry to make sure it ends up in the process memory. This will mean shifting all file offsets of other entries. But let's assume you've done it.
  6. Go through the dynamic section again, and update all entries that point into the string table with the new addresses. Also update DT_STRTAB/DT_STRSZ.
  7. Now you can finally add a new DT_NEEDED entry for your lib, and another DT_NULL terminator after it. And hope the new DT_NULL did not overwrite anything important :)
  • Is there a library that can read the .so into memory, converting it into some data structures (like DOM parsers read XML), so that I could add one element to the list and write it back? – 18446744073709551615 Apr 21 '14 at 10:04
  • Haven't seen any. – Igor Skochinsky Apr 21 '14 at 12:48
  • Update: it seems PatchELF implements at least some of the necessary functionality, so you can try extending it, or submit a feature request. – Igor Skochinsky Apr 23 '14 at 13:42
1

A simple way there is. readelf -d libxyz.so all dependencies lists. One of these libraries extend or substitute you can.

1

I know it's not a direct answer to your question, but would something like LD_PRELOAD mechanism allow you to achieve what you want?

With LD_PRELOAD you can specify your library which is to be loaded and functions from that library will be used instead of ones in the original library. This is a common and simple way of doing function hooking on Linux systems.

Here is an example of using LD_PRELOAD to hook functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.