【问题标题】:Convert a statically linked elf binary to dynamically linked将静态链接的精灵二进制文件转换为动态链接的
【发布时间】:2012-12-08 05:44:36
【问题描述】:

我有一个静态链接到 libc 的 elf 二进制文件。 我无权访问它的 C 代码。 我想使用 OpenOnload 库,它在用户空间中实现了套接字,因此与标准 libc 版本相比提供了更低的延迟。 OpenOnload 实现标准套接字 api,并使用 LD_PRELOAD 覆盖 libc 版本。 但是,由于这个 elf 二进制文件是静态链接的,它不能使用 OpenOnload 版本的套接字 API。

我相信可以通过以下步骤将此二进制文件转换为与 OpenOnload 动态链接:

  1. 添加新的程序头:PT_INTERP、PT_DYNAMIC 和 PT_LOAD。
  2. 在 PT_DYNAMIC 中添加条目以列出与 libc 的依赖关系。
  3. 在新的 PT_LOAD 部分中为所需的 libc 函数添加 PLT 存根。
  4. 修改现有的 libc 函数二进制代码以跳转到相应的 PLT 存根。

作为第一次剪辑,我尝试只添加 3 个 PT_LOAD 段。在现有的 PT_LOAD 段标头之后添加了新的段标头。此外,未修改现有段的 vm_addr。基于 p_align 将现有段的文件偏移量移至下一个对齐地址。 在文件末尾添加了新的 PT_LOAD 段。

重写文件后,当我运行它时,它被内核正确加载,但立即出现seg-faulted。

我的问题是:

  1. 如果我只是移动 elf 二进制文件中的文件偏移量,而不修改 vm_addresses,它会在运行二进制文件时导致任何错误吗?
  2. 是否可以做我正在尝试的事情?有人尝试过吗?

【问题讨论】:

  • 理论上这可以工作,但我认为你几乎肯定会看到无限数量的错误——你甚至还没有遇到的大问题是,glibc 预计会有在任何给定的地址空间中只有一个自身的副本,如果违反该期望,重要的事情(如malloc)将无法预测地崩溃。您最好通过反汇编程序运行整个二进制文件,手动删除所有 libc,然后重新组装和重新链接它。
  • 我可能只是为库写一个薄包装器..
  • 我同意扎克的观点。你会花费不合理的时间来做这件事,而且它可能不会像你想要的那样工作(魔鬼在细节中)。所以不要那样做!
  • 扎克,glibc 是希望只加载一份副本还是只使用一份副本?我的意思是,如果我将所有对 glibc 函数的调用从静态链接的 glibc 重定向到动态加载的调用,它可以工作吗?
  • Zack,你能详细说明一下反汇编程序吗?我该怎么做呢?我的意思是我可以在 Linux 上使用哪个反汇编程序?

标签: c linux elf openonload


【解决方案1】:

OpenOnload ... 使用 LD_PRELOAD 覆盖 libc 版本。但是,由于这个精灵二进制文件是静态链接的......

也回复intercept system calls of statically linked executable

【讨论】:

    【解决方案2】:

    您正在尝试的事情不可能以任何自动化方式进行。在静态链接时,所有将 libc 调用标识为 libc 调用的重定位信息都已解析并删除。如果二进制中存在调试符号,则可以识别“文本段中的此字节范围对应于某某libc函数”,但无法识别该函数的引用 ,它将嵌入在指令字节流中,没有标记来识别它们。您可以使用基于反汇编的启发式方法,但它们会不完整且不可靠(可能同时存在误报和误报)。

    就偏移偏移而言,您绝对不能更改静态链接二进制文件的加载地址。如果您需要在加载段之前插入标题,则必须插入整个页面,并更新程序头表中的文件偏移量(向它们添加 1 页),同时保持虚拟地址加载偏移量相同。但是,由于您尝试做的事情总体上是不可能的,因此偏移转移问题是您最不必担心的问题。

    也许,如果程序不需要高性能,您可以在 qemu 应用程序级仿真下运行它,让 qemu 通过套接字仿真/包装器。

    【讨论】:

    • "如果二进制文件中存在调试符号" -- 在 Linux 上,您不需要调试符号,只需要常规符号就足够了。 “没有标记来识别它们。”我不相信那是真的。如果二进制文件没有被剥离,objdump -d 将显示CALL socketCALL accept 等。
    • 这仍然需要拆卸。发生的情况是,在反汇编过程中,objdump 正在查看call 指令,然后查找目标地址以查看它是否与符号匹配。但是,没有任何标记连接到 call 指令的地址来标记它。
    • 嗯,二进制文件确实有符号。正如您所描述的,objdump 还能够显示对 libc 函数的调用位置,因此,我可以手动将此调用重定向到其他地方(手动添加 PLT 条目)。
    • 我不确定 qemu 是如何工作的,但是由于目标是实现低延迟,并且添加一层进一步的抽象只会增加它,我认为它不会有帮助。
    • WRT,为了进行实验,我将文件偏移量移动了一页大小(4096),但生成的二进制文件出现了段错误,我无法理解它为什么会出错?
    猜你喜欢
    • 2013-06-02
    • 2014-01-11
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 2015-04-02
    • 1970-01-01
    相关资源
    最近更新 更多