elf文件查找函数的过程

本文详细介绍了如何通过反编译工具objdump来逐步解析ELF格式程序的动态链接过程,包括定位printf函数调用、分析.got.plt和.plt段的内容,以及解释懒惰链接的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要反编译的程序:hello.c
#include<stdio.h>
int main()
{
   printf("Hello World!/n");
   return 0;
}
 
1.对hello进行反汇编,并查找包含"printf"的行;
可以看到它调用了地址0x80482b0的函数;
[root@localhost src]# objdump -d hello | grep printf
080482b0 <printf@plt>:
 804838c:       e8 1f ff ff ff          call   80482b0 <printf@plt>

2.对hello的.got.plt部分进行反汇编;
[root@localhost src]# objdump -d -j .got.plt hello                                  
                                                                                    
hello:     file format elf32-i386                                                   
                                                                                    
Disassembly of section .got.plt:                                                    
                                                                                    
08049570 <_GLOBAL_OFFSET_TABLE_>:                                                   
 8049570:       a4 94 04 08 00 00 00 00 00 00 00 00 a6 82 04 08     ................
 8049580:       b6 82 04 08  

3.对hello进行反汇编,并查找包含".rel.plt"的行;
[root@localhost src]# objdump -s hello | grep .rel.plt -A3
Contents of section .rel.plt:
 8048268 7c950408 07010000 80950408 07020000  |...............
Contents of section .init:
 8048278 5589e583 ec08e861 000000e8 b4000000  U......a........

4.显示所有的Section,并查找包含.got.plt 的行;
[root@localhost src]# readelf -S hello | grep .got.plt
  [21] .got.plt          PROGBITS        08049570 000570 000014 04  WA  0   0  4

5.对hello的plt部分进行反汇编,可以看到地址0x80482b0 处的汇编代码,
jmp    *0x8049580 语句的意思是跳转到got,从第二步可以看到,它跳到了got中;
got中的内容为b6 82 04 08 ,它的小字节序是08 04 82 b6;
地址0x080482b又是plt中的push   $0x8,0x8是在重定向表中的偏移量,可以从第三步看到;
jmp    8048290 <_init+0x18>  又跳到了plt的开头;
pushl  0x8049574  0x8049574位于got中;
jmp    *0x8049578      然后调用位于0x8049578 的东西,但是该位置是零。

[root@localhost src]# objdump -d -j .plt hello                     
                                                                   
hello:     file format elf32-i386                                  
                                                                   
Disassembly of section .plt:                                       
                                                                   
08048290 <__libc_start_main@plt-0x10>:                             
 8048290:       ff 35 74 95 04 08       pushl  0x8049574           
 8048296:       ff 25 78 95 04 08       jmp    *0x8049578          
 804829c:       00 00                   add    %al,(%eax)          
        ...                                                        
                                                                   
080482a0 <__libc_start_main@plt>:                                  
 80482a0:       ff 25 7c 95 04 08       jmp    *0x804957c          
 80482a6:       68 00 00 00 00          push   $0x0                
 80482ab:       e9 e0 ff ff ff          jmp    8048290 <_init+0x18>
                                                                   
080482b0 <printf@plt>:                                             
 80482b0:       ff 25 80 95 04 08       jmp    *0x8049580          
 80482b6:       68 08 00 00 00          push   $0x8                
 80482bb:       e9 d0 ff ff ff          jmp    8048290 <_init+0x18>
                                       ....            
这个过程叫做懒惰链接,因为重定向只发生在运行并且需要时,只要链接器完成了第一次查找,
链接器将会修改got表项,使得调用plt中的函数时,直接跳到got中,再跳到真正的函数哪里,而不是像
上面那样回到plt中,将重定向表中的偏移量入栈。   

参考1:http://em386.blogspot.com/2006/10/resolving-elf-relocation-name-symbols.html

### 解析ELF文件过程 #### 1. 文件头解析 ELF文件的起始部分是文件头(File Header),它提供了关于整个文件的关键元数据。通过读取文件头,可以获取到文件类型、目标机器架构、入口点地址以及其他重要信息。这些信息对于后续解析至关重要[^4]。 ```c typedef struct { unsigned char e_ident[EI_NIDENT]; // ELF 魔数和其他标识符 Elf32_Half e_type; // 文件类型 (可执行, 库等) Elf32_Half e_machine; // 目标硬件平台 Elf32_Word e_version; // 版本号 Elf32_Addr e_entry; // 程序入口点虚拟地址 Elf32_Off e_phoff; // 程序头表偏移量 Elf32_Off e_shoff; // 节头表偏移量 } Elf32_Ehdr; ``` 上述代码展示了ELF文件头的主要字段及其含义。其中 `e_ident` 是一个固定长度数组,用于存储魔数和版本信息;而其他字段则描述了文件的基本属性。 #### 2. 使用工具ELF文件内容 在Linux环境中,有多种命令行工具可以帮助快速浏览和分析ELF文件的内容。常用的工具有: - **readelf**: 显示ELF文件的各种信息,包括头部、节区、段等内容。 - **objdump**: 提供更详细的反汇编功能,能够展示二进制指令流。 - **hexdump/od/vim**: 这些工具允许以十六进制或其他形式直观地观察原始字节序列[^2]。 例如,运行以下命令即可看某个ELF文件的部分详情: ```bash $ readelf -h /path/to/binary ``` 此操作会打印出该二进制文件的全局概述,帮助开发者初步判断其特性。 #### 3. 符号表与重定位表的作用 符号表记录了函数名、变量名及其他命名实体的位置映射关系,便于调试器查找特定位置的数据项或者调用外部库中的方法。另一方面,当链接多个对象模块时,可能会涉及地址调整工作——这就是所谓的“重定位”。因此,重定位表用来指导加载器修改某些内存单元上的数值以便适应最终运行环境下的实际情况[^3]。 以下是符号表条目的一般结构示例: ```c typedef struct { Elf32_Word st_name; /* Symbol name index */ Elf32_Addr st_value; /* Value or address associated with the symbol */ Elf32_Word st_size; /* Size of the symbol */ unsigned char st_info; /* Type and binding attributes */ unsigned char st_other; /* Reserved field */ Elf32_Section st_shndx; /* Section table index where it resides */ } Elf32_Sym; ``` 这里列出了每个符号对应的名称索引、值域大小以及所属分区编号等参数。 --- ### 总结 综上所述,解析ELF文件通常遵循从整体框架入手逐步细化至局部特性的原则。先利用专门设计好的实用程序提取基本信息作为切入点,再深入研究内部组成部分如符号表和重定位机制等功能实现原理[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值