【问题标题】:Intercepting Statically Linked Dependencies of a Dynamically Linked Library拦截动态链接库的静态链接依赖
【发布时间】:2021-09-06 07:32:04
【问题描述】:

我正在尝试调试第三方应用正在使用的 API。 第三方应用有一个我认为不可能的配置:

应用程序二进制文件包含其共享库依赖项之一所需的导出。也就是说,它们动态链接了它们的依赖关系,但该依赖关系的依赖关系是静态链接的。

这发生在具有古老内核的基于 MIPS 的 linux 上。

我已经使用 Ghidra 来反汇编可执行文件/共享库确认了这一点。

基本上我们有二进制文件和共享对象

file initApp
initApp: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

file libhyCoreSdk.so
libhyCoreSdk.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, stripped

objdump -T libhyCoreSdk.so | grep -i IMP_ISP_Open
00047900      DF *UND*  00000000 IMP_ISP_Open

initApp 在 libhyCoreSdk.so 中调用“coreAvInit”,然后 libhyCoreSdk.so 在 initApp 中调用 IMP_ISP_Open()。

您可能会想“这并不罕见,您可以通过回调、传递指针、调用 dlsym 等来做到这一点。”但这不是那些东西,这是符号的直接​​导入/导出,如果 libhyCoreSdk 依赖于另一个共享库,这正是您所期望的。

除此之外,我真正的问题是我试图弄清楚 IMP_ISP_Open 传递了哪些参数,而 LD_PRELOAD 无助于这种奇怪/独特的情况。我有另一个示例应用程序,它针对 API 的共享库版本调用相同的 API。当我针对该版本使用 LD_PRELOAD(加载我编写的一个小拦截器程序)时,效果很好。但是当我对这个链接回二进制文件的版本使用它时,它就不起作用了。

我希望有人知道如何拦截这些 API 调用。

部分解决方案:

Daniel Kleinstein 给了我一个良好的开端。我将目标函数从 IMP_... 重命名为 XMP_...(例如 IMP_ISP_DisableSensor-> XMP_ISP_DisableSensor)。现在,我的 LD_PRELOAD 中的 IMP_ISP_DisableSensor 已正确命中。不幸的是,我仍然遇到麻烦。调用 dlsym(RTLD_DEFAULT, "XMP_ISP_DisableSensor") 无缘无故返回 NULL...这意味着我无法重定向回原始函数。

尽管 objdump 显示了这一点:

objdump -T initApp_mod | grep -i XMP
0061fb5c g    DF .text  00000338  Base        XMP_FrameSource_CreateChn
00613c6c g    DF .text  00000204  Base        XMP_ISP_DisableSensor
006097f0 g    DF .text  00000eb0  Base        XMP_Encoder_CreateChn

【问题讨论】:

  • "但是那个依赖的依赖是静态链接的。"但是file libhyCoreSdk.so 表明它是动态链接的? objdump -T libhyCoreSdk.soIMP_ISP_Open 的导入显示什么?
  • @DanielKleinstein 我已经添加了它显示的内容。老实说,它并没有告诉我太多。查看 readelf 输出,我可以看到 IMP_ISP_Open 是一个动态符号,但 .dynamic 所需列表中没有“initApp”条目。 (这是有道理的,不知道他们怎么可能)
  • 您的共享库有一个未定义的符号,该符号由可执行文件解析,而不是由动态部分中列为 NEEDED 的任何共享库解析。这里没有什么不可能或不寻常的(或实际上是静态链接的)。 (这在 Windows 和 DLL 的世界中是不可能的,但共享库不是 DLL)。
  • @n.1.8e9-where's-my-sharem。情况确实如此,也许是我的 Windows 背景让这看起来如此疯狂。但是这个现实并不能解决我的 LD_PRELOAD 问题。对此有什么想法吗?为什么 LD_PRELOAD 符号不优先于可执行文件中的符号?
  • @wd40bomber27 LD_PRELOAD 在这里不起作用,因为它不优先于主可执行文件本身导出的符号 - 仅高于共享库导出的符号。我不确定你的情况到底是什么(二进制研究?生产代码?),但在你的情况下,我可能会尝试修补二进制文件本身以重命名导入的符号(或者更简单,重命名主可执行文件的导出符号)以允许 @987654327 @钩子。

标签: c linux mips


【解决方案1】:

您的动态依赖项与您的主可执行文件静态链接。加载动态依赖项时,会搜索其导入并通过可执行文件导出的符号解析 - 实际上,可执行文件的符号将始终在任何其他动态依赖项之前解析。


不幸的是,这也会阻止您使用LD_PRELOAD

LD_PRELOAD 不起作用,因为其注入的库优先于主可执行文件本身导出的符号 - 仅优先于共享库导出的符号。


如果您希望使用LD_PRELOAD 拦截调用,一个粗略但有效的解决方案是将主可执行文件的导出符号修补为不同的名称 - 这样在加载动态依赖项时它不会解析,并且您的注入库可以提供符号。

【讨论】:

  • 我遇到的另一个问题是,无论我做什么,我都无法解决原始(现已重命名)符号。由于某种原因,没有使用 DL API。这最初阻止了我在我的 LD_PRELOAD 符号之后重定向到原始函数。我对此的修复同样粗糙。我的(运行古老 linux 内核的 MIPS LE)平台的 ASLR 为零。通过查找我使用 objdump 替换的符号,我能够直接将 dl 调用替换为原始偏移量。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多