【发布时间】:2024-01-16 11:19:01
【问题描述】:
问题
我希望将目标文件注入到现有的二进制文件中。作为一个具体的例子,考虑一个来源Hello.c:
#include <stdlib.h>
int main(void)
{
return EXIT_SUCCESS;
}
它可以编译成一个名为Hello 到gcc -std=gnu99 -Wall Hello.c -o Hello 的可执行文件。此外,现在考虑Embed.c:
func1(void)
{
}
一个目标文件Embed.o可以通过gcc -c Embed.c创建。我的问题是如何将Embed.o 插入到Hello 中,以便执行必要的重定位,并正确修补适当的 ELF 内部表(例如符号表、PLT 等)?
假设
可以假设要嵌入的目标文件已经静态链接了它的依赖关系。可以假定任何动态依赖项(例如 C 运行时)也存在于目标可执行文件中。
目前的尝试/想法
- 使用
libbfd将目标文件中的部分复制到二进制文件中。我在这方面取得的进展是我可以使用原始二进制文件中的部分和目标文件中的部分创建一个新对象。问题在于,由于目标文件是可重定位的,因此如果不先执行重定位,就无法将其部分正确复制到输出中。 - 将二进制文件转换回目标文件并使用
ld重新链接。到目前为止,我尝试使用objcopy执行转换objcopy --input elf64-x86-64 --output elf64-x86-64 Hello Hello.o。显然这并不像我想要的那样工作,因为ld -o Hello2 Embed.o Hello.o将导致ld: error: Hello.o: unsupported ELF file type 2。我想这应该是可以预料的,因为Hello不是目标文件。 - 找到执行这种插入的现有工具?
基本原理(可选阅读)
我正在制作一个静态可执行编辑器,其愿景是允许将任意用户定义的例程检测到现有二进制文件中。这将分两步进行:
- 将目标文件(包含用户定义的例程)注入二进制文件。 这是一个强制性步骤,不能通过注入共享对象等替代方法来解决。
- 对新的二进制文件执行静态分析,并使用它静态地将例程从原始代码绕道到新添加的代码。
在大多数情况下,我已经完成了第 2 步所需的工作,但是我在注入目标文件时遇到了问题。考虑到其他工具使用相同的对象注入方法(例如EEL),这个问题肯定是可以解决的。
【问题讨论】:
-
对问题的快速阅读留下了不理解运行时链接器和普通链接器之间的概念的感觉。运行时链接器/程序加载器仅在易于快速修复的格式上运行。 .o 不是其中之一 :-) 如果它具有最小的依赖项,例如编解码器,则使用最少的代码链接以使其成为 .so 听起来像逻辑路由
-
@MarcovandeVoort:感谢您的评论 :) 我松散地使用了“链接”一词,因为有人可能会使用“注入”,这就是我将其放在引号中的原因。我无法将其设为
.so的原因之一是应用程序可以破坏诸如LD_PRELOAD之类的注入技巧。不仅如此,它还需要分发一个形成新环境的附加库。静态迂回还有其他各种优点(特别是出于本项目的目的),但正如我在问题和 cmets 中已经说过的那样,这不是我可以改变的设计决策 :) -
您是否尝试在 AIX(以及我所知道的其他任何地方)上执行类似 ld 的功能来重新链接只有一个目标文件已更改的可执行文件?
-
@evilotto:我想添加一个以前从未出现过的新目标文件。
-
您是否介意分享一下 Rationale 下的 #2 如何成为可能?如果您现在知道 OP 的答案,我也会对此感到非常好奇。