Bionic 和 libc 的存根实现

Bionic and libc’s stub implementations

我想要 运行 我从非 android linux 机器上的 apk 抓取的 x86 共享库。

它链接到 android libc,所以我从 android ndk 中获取了 libc.so。 在调试了一段时间的段错误后,我认为 libc.so 是“作弊”并且仅包含许多库函数的 nop 实现:

$ objdump -d libc.so | grep memalign -A 8
0000bf82 <memalign>:
    bf82:       55                      push   %ebp
    bf83:       89 e5                   mov    %esp,%ebp
    bf85:       5d                      pop    %ebp
    bf86:       c3                      ret    

现在 ndk 还包含一个 libc.a,其中包含这些函数的实际实现,但是如何让我的进程加载这些函数并覆盖 libc.so 的 nop 函数? 也会对更多关于 android 为何使用此技巧以及覆盖如何在那里工作的上下文感兴趣。

如您所见,取自 NDK 的 libc.so 仅包含存根,因为它的目的是在创建您自己的共享库或可执行文件期间向链接器提供必要的信息。 nice explanation 为什么我们需要存根库。

因此,如果您需要真正的 libc.so 二进制文件 - 有两种选择:

  1. 直接从Android设备上抓取:

    $ adb pull /system/lib/libc.so <local_destination>
    
  2. 为您的设备下载出厂 ROM 映像,解压缩,安装 system.img 到您的本地文件系统,然后再次从该安装分区的 /system/lib 复制它。

但是,即使您获得了正确的二进制文件,要让它在您的桌面上运行也是一件非常痛苦的事情 Linux。至少有两个原因:

  1. Android 和桌面 Linux ELF 需要不同的解释器。您可以使用 readelf:

    检查
    $ readelf --all <android_binary> | grep interpreter
    [Requesting program interpreter: /system/bin/linker]
    $ readelf --all <linux_x64_binary> | grep interpreter
    [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
    

    (解释器是一个小程序,它执行实际加载您的二进制文件并由内核加载)显然您的 Linux 系统没有 /system/bin/linker 并且内核将拒绝加载此类二进制文件。因此,您必须以某种方式正确加载部分并自行解决所有依赖项。

  2. Android 内核与桌面内核不同,它有一些 libc.so 依赖的额外功能,所以即使你以某种方式加载 ELF,它仍然不兼容你的内核,你肯定会在某个时候遇到问题。

最重要的是:几乎不可能在桌面 GNU/Linux 上重用 android 二进制文件,即使它们针对相同的硬件架构也是如此。