我正在编写一个小工具来试验ELF-64目标代码,该代码旨在解析和加载ELF-64目标代码,以便在父进程中执行。我相信我现在正走在正确的轨道上,但我需要为最后几步提供一些指示。
第1步:我解析目标文件并提取所有必要信息。我已使用readelf
工具验证了这一点。
第2步:我使用SHF_ALLOC
- 位设置和mmap
内存遍历所有节标题。
第3步:这个看似简单无用的对象只包含一个main
- 例程和一个return语句,据我所知,我不需要重新定位符号(我已经加倍了)用readelf
检查。我已经使用TinyCC编译,以避免.eh_frame
及其重定位条目被发出。
但是在这一点上我需要加载SHF_ALLOC
- 位设置到内存中的部分,这是我怀疑我做错的地方。
offset = 0
foreach section in sections
if section.flags & SHF_ALLOC
memcpy(memory_address + offset, object_code + section.offset, section.size)
offset += section_size
第4步:我不确定的最后一步。我需要调用已标记为可执行文件的已分配内存。
typedef int (main_t)(int argc, char* argv[]);
((main_t)object->address)(0, NULL);
我非常感谢对此的一些意见。我认为归结为缺乏理解.text
- 究竟是什么 - 片段包含以及它们如何存储在内存中。
一些想法:
main
位于0x0
- 段的偏移.text
处吗?任何指向正确方向的东西都会有很大的帮助!谢谢!
PS。我打算很快学会重新定位符号。一步一步来。 : - )
答案 0 :(得分:1)
您应该使用程序头,而不是节标题。节头用于链接器,程序头用于加载器。
分配的段旨在转到他们首选的VirtAddr
,如果它们有一个(非预链接库可能有一个基本虚拟地址为0,这意味着加载器将为它们分配随机地址)。
ELF标题有一个入口点字段。这不是main
,它通常是一些libc初始化代码......进行初始化...然后调用main
。在将控制权传递给入口点之前,您应该设置符合ELF ABI的所有内容(将argc
,argv
,envp
,auxv
放在堆栈上,清除一些寄存器,我认为就是这样。)
答案 1 :(得分:0)
在一夜好眠之后,我设法把它拉了下来。
我首先使用生成的objdump
反汇编目标文件:
/tmp/test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 81 ec 10 00 00 00 sub $0x10,%rsp
b: 48 89 7d f8 mov %rdi,-0x8(%rbp)
f: 48 89 75 f0 mov %rsi,-0x10(%rbp)
13: b8 c8 00 00 00 mov $0xc8,%eax
18: e9 00 00 00 00 jmpq 1d <main+0x1d>
1d: c9 leaveq
1e: c3 retq
此输出确保了main
位于0x0
的位置,这意味着如果我将.text
- 段正确复制到mmap
返回的地址的内存中,我应该可以用问题中找到的片段(我不确定)来调用它。它将使用调用线程的堆栈。
然后我将部分复制到内存时发现了一个小错误,section.offset
是文件开头的偏移量,我错误地认为这是从开头的偏移量节标题条目。
当我了解基础工作时,实验会更简单。 : - )