I've made some progress and I am now able to link and run my test program under qemu.
I did the following to the original .so lib:
- patchelf --remove-needed all.so
- patchelf --add-needed libx.so
- Then with my own patcher I've removed all versions in the .gnu.version_r section and inserted my own "HOOK" version
- I've set all external functions to "HOOK" version in section .gnu.version
- I've compiled my own shared library libx.so will all external functions
and I've versioned these functions using the linker option --version-script
- I've dumped libx.so with readelf and got the hash value which I then reinserted in the .gnu.version_r of the original lib
Functions in my libx.so then call the equivalent ones from glibc
Code:
int
puts( const char *s )
{
static int ( *fn )( const char *s ) = NULL;
if( fn == NULL )
fn = dlsym( RTLD_NEXT, "puts" );
return fn( s );
}
I've also knocked out the
.init_array and
.fini_array sections just to make sure no code is executed at library loading time.
Now my program links and runs but as soon as I reference a function from the binary shared library (or if I manually use dlopen on it) the execution hangs:
Code:
Reading symbols from ./test...
(No debugging symbols found in ./test)
(gdb) run
Starting program: /home/zzz/test
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".
Start main
^C
Program received signal SIGINT, Interrupt.
0x0000fffff4bfc434 in std::set_unexpected(void (*)()) ()
from ./libscope-auklet.so
(gdb) quit
I presume it is the dynamic linker which fails to resolve the
.plt/.got relocations and ends up in one of the library's function (std::set_unexpected)
I don't see a solution to this last problem so now I will investigate a way to convert that
.so to a (big)
.o.
This means getting rid of the
.dynsym section and replacing all stubs in the
.plt section - not an easy task.