问题
我希望将一个目标文件注入现有的二进制文件中.作为一个具体的例子,考虑一个来源Hello.c:
#include <stdlib.h>
int main(void)
{
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
它可以编译为名为Hellothrough 的可执行文件gcc -std=gnu99 -Wall Hello.c -o Hello.此外,现在考虑Embed.c:
func1(void)
{
}
Run Code Online (Sandbox Code Playgroud)
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它不是一个目标文件.理由(可选阅读)
我正在制作一个静态可执行编辑器,其目的是允许将任意用户定义的例程检测到现有的二进制文件中.这将分两步进行:
如何使用GNU ld将(某些)符号链接到特定的固定地址,以便二进制文件仍可在Linux(x86)中正常执行?不会访问这些符号,但它们的地址很重要.
例如,我有以下结构:
struct FooBar {
Register32 field_1;
Register32 field_2;
//...
};
struct FooBar foobar;
Run Code Online (Sandbox Code Playgroud)
我想链接foobar到地址0x76543210,但通常链接标准库和应用程序的其余部分.然后,应用程序将使用foobar的地址,但不会引用它后面的(可能不存在的)内存.
这个请求的基本原理是这个相同的源可以在两个平台上使用:在本机平台上,Register32可以简单地是一个volatile uint32_t,但在Linux上Register32是一个C++对象,其大小与uint32_t定义的大小相同operator=,然后将使用该地址对象并向具有该地址(和数据)的通信框架发送请求以在远程硬件上执行实际访问.因此,链接器将确保Register32结构的字段引用正确的"地址".
这个问题是我之前提出的另一个问题.简而言之,这是我尝试将两个完全链接的可执行文件合并为一个完全链接的可执行文件的尝试之一.区别在于前一个问题涉及将目标文件合并到一个完整的链接可执行文件,这更难,因为这意味着我需要手动处理重定位.
我所拥有的是以下文件:
example-target.c:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
puts("1234");
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
example-embed.c:
#include <stdlib.h>
#include <stdio.h>
/*
* Fake main. Never used, just there so we can perform a full link.
*/
int main(void)
{
return EXIT_SUCCESS;
}
void func1(void)
{
puts("asdf");
}
Run Code Online (Sandbox Code Playgroud)
我的目标是合并这两个可执行文件以生成一个最终的可执行文件,它与之相同example-target,但另外还有另一个main和func1.
从BFD库的角度来看,每个二进制文件由一组部分组成(以及其他内容).我遇到的第一个问题之一是这些部分具有冲突的加载地址(这样,如果我要合并它们,这些部分将重叠).
我解决这个问题的方法是以example-target编程方式分析,以获取每个部分的加载地址和大小的列表.然后,我做了同样的事情,example-embed并使用此信息动态生成链接器命令,example-embed.c以确保其所有部分链接在不与任何部分重叠的地址example-target.因此example-embed,在这个过程中实际上完全链接了两次:一次确定它们有多少部分和大小,并再次与保证没有部分冲突相关联example-target.
在我的系统上,生成的链接器命令是:
-Wl,--section-start=.new.interp=0x1004238,--section-start=.new.note.ABI-tag=0x1004254,
--section-start=.new.note.gnu.build-id=0x1004274,--section-start=.new.gnu.hash=0x1004298,
--section-start=.new.dynsym=0x10042B8,--section-start=.new.dynstr=0x1004318,
--section-start=.new.gnu.version=0x1004356,--section-start=.new.gnu.version_r=0x1004360,
--section-start=.new.rela.dyn=0x1004380,--section-start=.new.rela.plt=0x1004398,
--section-start=.new.init=0x10043C8,--section-start=.new.plt=0x10043E0, …Run Code Online (Sandbox Code Playgroud)