在Android上自己实现一个linker

分析完linker,可以尝试自己实现一个共享库的加载器,实现加载任意共享库,并在/proc/[pid]/maps中隐藏

目标

在demo中,我们需要了三个库libhelloworld.so、liblua.so、liblink.so。其中liblink.so是正常从Dalvic调用进来的,已经加载到了内存。libhelloworld.so中依赖liblua.so。libhellowrold.so中的函数helloworld()会调用liblua.so的函数,并且需要执行lua脚本。

我们需要实现自己的dlopen和dlsym,加载libhelloworld.so,调用其中的helloworld,运行任意lua脚本。同时加载的libhelloworld.so不能在maps中显示。由于libhelloworld.so依赖了liblua.so,也需要加载这个so并且不能再maps显示。

思路

理解了源码中linker的实现,自己在实现一个dlopen就不难了。经过分析,maps中之所以会显示动态链接库的路径,是因为第二次map每一个segments的时候是将文件映射到内存,并非匿名映射,所以maps中会显示地址。我们可以参考源码中dlopen的实现,在load_segment的时候不采用文件映射的方法,而是读取文件内容并写入内存,这样这段内存仍然是匿名映射,就不会显示我们加载的动态链接库了。

实现时需要注意很多地方,最重要的一点应该是对于重定向地址的修复。修复时往往会忽略一些内容,我第一次就忽略了data段存放的重定向地址。注意考虑RELA和JMPREL中所有的类型。

第二点,如果我们加载的动态链接库也需要加载新的动态链接库,这些库如果原先没加载,我们也要加载它并隐藏,所以要用同样的自己实现的dlopen加载它。目前的方案是,如果在maps中没搜到这个库,统一用my_dlopen加载。