【问题标题】:Native library load breakpoint in AndroidAndroid中的本机库加载断点
【发布时间】:2012-06-28 06:48:14
【问题描述】:

如何在 Android 中为原生库加载事件设置断点?

我认为在 dlopen() 上设置断点是一个很好的起点,但是,即使 libc.so 的符号,gdb 也无法找到 dlopen 函数strong> 和 /system/bin/linker 已加载。

看起来 Android 正在使用一些特殊格式的 .so 文件,因为 nm 工具也不报告 dlopen() 位置。

是否有任何解决该问题的方法或 Android 特定的 .so 转储工具可以帮助通过名称定位函数地址,以便我可以手动设置断点?

编辑:

我要做的是设置一个断点,该断点应在加载任何本机库时触发,即当任何代码(甚至不在我的库中)调用 dlopen() 函数时。

问题在于 Android GDB 不支持挂起的断点。我的场景是这样的:

  1. 我启动我的应用程序并停止它。
  2. 应用程序已恢复并加载我的原生库。
  3. 我的函数是从库中调用的(仅在应用加载时调用一次)。

如果我在 #1 之后设置断点,它将无法工作,因为库仍然不存在并且 android-gdb 将无法重新绑定它。如果我让程序运行,然后再次停止它并设置断点,我已经过了#3,所以断点将无用。

我试图通过在 #1 处将断点设置为 dlopen() 来解决它,然后当它命中并加载库(即 #2)时,我将设置实际断点。

使用正常的 ARM nm 和 objdump 没有任何帮助。对 libc.so 进行 NM 显示 dlopen() 未定义:

00016188 T dlmemalign
         U dlopen
00016338 T dlpvalloc

/system/bin/linker 二进制文件物理上包含 dlopen 文本(.rodata 部分的第一个字节),但是 nm 显示以下文本:

arm-linux-androideabi-nm.exe: linker: No symbols

用 objdump 反汇编它不会给出符号名称。

通过谷歌搜索 android 源代码发现了这个源文件:

http://dexandroid.googlecode.com/svn/trunk/bionic/linker/dlfcn.c

看起来 dlopen() 确实是在 /system/bin/linker 中定义的,但它使用了一些非标准的符号解析机制(至少,基于第一条评论):

/* This file hijacks the symbols stubbed out in libdl.so. */

那么,回到问题上来,如何在 dlopen() 中设置断点,以便在加载库时设置实际断点?

【问题讨论】:

    标签: android c++ android-ndk gdb


    【解决方案1】:

    通常任何 arm objdump 都可以工作,但在您的 ndk 目录中会有一个。 即使是非手臂阅读器也可以工作。

    我不确定您为什么希望在库中找到 dlopen(),除非它明确使用它来打开另一个库 - 通常,人们会认为它会从 libdvm.so 中调用,无论如何我相信实现在 libdl.so 中(拥有为 android 构建的 grep 版本非常有用 - 您可以在 lib 目录中找到字符串,但如果您想查找它们是导入还是导出,您可能需要 adb pull 和 objdump感兴趣的文件)。

    如果您尝试对正在加载的库文件设置断点,您可以尝试实现静态初始化函数之一(C 级或加载时的 jni)并在此处设置断点。

    编辑:

    事实证明,用于 arm 的 objdump 不会通过用于从共享库导入的符号的 plt 来解码链接,尽管它适用于 x86 等其他一些平台。这使得很难理解去除了调试符号的二进制文件,正如您对设备上的系统库所期望的那样。我能够修补 binutils 源来为 arm 执行此操作。最终我希望在某个地方提交它,但与此同时,补丁版本的源代码可以在 https://github.com/cstratton/binutils-android-decodeplt 获得

    我将一个 objdump 二进制文件放在 prebuilt-linux-x86/ 目录中,但我不知道它的可移植性如何。

    【讨论】:

    • 不幸的是,objdump 没有。更新了问题。
    • 正如我之前所说,它在 libdl.so 中,如果使用正确,objdump 工作得很好(从 android 设备发布,所以现在无法为你制定语法)
    • 它确实在 libdl.so 中,但是当应用程序运行时,libdl.so 不在库列表中(信息共享)。
    • 是的,libdl.so 被链接器劫持了。您可能想尝试在 libdvm.so 中对 dlopen 的使用进行断点,诀窍是它可能是通过 .plt 中的一些 arm 代码间接调用的,该代码跳转到链接器实际解析的内容,但 objdump 无法解决这个问题,所以你不会将 dlopen() 视为反汇编中的符号,而是将其隐藏为对文件中第一个函数名称的引用减去一些偏移量,即指向 .plt。一年前,我有一些东西可以为一个项目解码,试图找出它的去向。
    • 我认为您可以做的最实际的想法是将 _init() 函数放入您的本机库中,该函数记录一些内容然后进入无限循环。这将使您有机会使用 gdb 手动中断程序并继续执行(或者可能引发未处理的信号)。
    猜你喜欢
    • 2013-05-08
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    相关资源
    最近更新 更多