我很好奇调用main()之前发生的事情,比如将可执行文件加载到内存中,动态加载共享库.您是否有任何建议如何通过实践练习来理解这些事情?
工具和我所知道的,现在使用,包括:
注意:我知道伟大的书籍链接者和装载者,但动手练习可能比教我读书更好.
是否有用于修改ELF二进制文件的动态部分中的共享库条目的工具?我想显式修改二进制文件中的共享库依赖项(即用自定义路径替换现有库的路径)
我一直在阅读ELF规范,无法确定程序入口点和_start地址从何而来。
似乎它们应该在一个相当一致的位置,但是我编写了一些琐碎的程序,而_start始终在另一个位置。
谁能澄清?
我在我的linux机器上的几个二进制文件上使用了readelf,并在程序头中看到了令我惊讶的东西.这个示例来自'ld'实用程序,但它也出现在我使用gcc编译的任何内容中.
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 RE 0x4
该段跨越整个程序头.为什么被标记为可执行文件?它不包含机器代码.但是,为什么甚至在标题中出现?我真的不想在我的程序图像中.
我想在ELF文件中添加一些信息,但理想情况下,它需要以一种方式完成,即程序可以在不了解ELF或使用普通标准语言库之外的工具的情况下轻松读取此信息.我想把这些数据简单地附加到ELF文件的末尾(用某种哨兵来指示数据的开始,这样读取程序就可以向后寻找哨兵了),但我想确保这样做不会首先违反ELF规范.我对使用这样的附加数据是否能够正常运行特定加载器感兴趣; 我想知道ELF规范本身是否保证什么,以便我可以知道不同的ELF兼容的加载器会很满意.
我之前已经问过这样的问题,但要么假设这个附加是好的,要么没有直接反应:
据我所知,ELF规范在这里:
我无法通过几次搜索确定该规范是否明确允许我想要的属性.
我需要使可执行ELF的.text段可写.我需要修改的程序是用C编写的,我可以编译它.有任何想法吗?
非常感谢.
我想读取ELF二进制文件的.plt部分并获取外部函数的所有虚拟地址.
Disassembly of section .plt:
0000000000400400 <puts@plt-0x10>:
400400: ff 35 02 0c 20 00 pushq 0x200c02(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
400406: ff 25 04 0c 20 00 jmpq *0x200c04(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
40040c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400410 <puts@plt>:
400410: ff 25 02 0c 20 00 jmpq *0x200c02(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
400416: 68 00 00 00 00 pushq $0x0
40041b: e9 e0 ff ff ff jmpq 400400 <_init+0x20>
0000000000400420 <__libc_start_main@plt>:
400420: ff 25 fa 0b 20 00 jmpq *0x200bfa(%rip) …Run Code Online (Sandbox Code Playgroud) 看来,用gcc 4.9.2在Linux上创建的二进制文件(Ubuntu的15.04,32位)有部分之间有几千未使用的字节.eh_frame和.init_array.objdump -h简单可执行文件的输出示例:
Sections:
Idx Name Size VMA LMA File off Algn
[...]
16 .eh_frame 000000c0 080484ac 080484ac 000004ac 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .init_array 00000004 08049f08 08049f08 00000f08 2**2
CONTENTS, ALLOC, LOAD, DATA
[...]
Run Code Online (Sandbox Code Playgroud)
.eh_frame在文件偏移量0x56c结束但从0xf08 .init_array开始,留下一个0x99c = 2460字节的漏洞.所有其他部分在上一部分结束后立即开始.
未使用空间的大小会有所不同,因此很难观察到某些更改如何影响代码大小.
这个洞来自哪里?有没有办法避免它?
更新:输出ld --verbose:
$ cat so.c
int main() {
return 0;
}
$ gcc so.c -Wl,--verbose -o so
GNU ld (GNU Binutils for Ubuntu) 2.25
Supported emulations: …Run Code Online (Sandbox Code Playgroud) 使用时组装对象时nasm,我发现所有标签都包含在结果.o文件中的符号中,以及最终的二进制文件中.
这对于我已经声明的函数入口点GLOBAL和段开始部分(例如,对于该.text部分)是有意义的,但是标签简单地用作循环入口点并且所有这些都接近出现在输出文件中似乎很奇怪.除了泄漏内部实现细节之外,它还浪费了符号表中的空间.
例如,鉴于这个简短的装配程序:
GLOBAL _start
_start:
xor eax, eax
normal_label:
xor eax, eax
.local_label:
xor eax, eax
xor edi, edi
mov eax, 231 ; exit(0)
syscall
Run Code Online (Sandbox Code Playgroud)
...建造使用:
nasm -f elf64 label-test.s
ld label-test.o -o label-test
Run Code Online (Sandbox Code Playgroud)
在l对象文件和链接的可执行文件中生成(即本地)符号:
objdump --syms label-test.o
label-test.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 label-test.s
0000000000000000 l d .text 0000000000000000 .text
0000000000000002 l .text 0000000000000000 normal_label
0000000000000004 l .text 0000000000000000 normal_label.local_label
0000000000000000 g .text …Run Code Online (Sandbox Code Playgroud) 我目前正在编写一个动态链接器,但有一些问题困扰着我。为什么ld.so(系统的动态链接器)是共享对象?为什么它不能只是静态可执行文件(ET_EXEC)?
我尝试在Linux内核的binfmt_elf.c中寻找答案,但据我所知,它清楚地表明您的ELF解释器可以是静态可执行文件。
编辑:我认为我的想法可以总结为:动态链接器可以是简单的ELF可执行文件(ET_EXEC)吗?
/* First of all, some simple consistency checks */
if (interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN)
goto out;
Run Code Online (Sandbox Code Playgroud)
PS:我希望这是正确的地方,我不知道该把它放在这里还是在Unix堆栈交换上。我也很抱歉,如果我的问题很愚蠢,但是没有答案,这会让我发疯。