当前位置: 首页 > news >正文

Linux逆向实战:用readelf和objdump亲手分析一个.o文件的.rela.text节

Linux逆向实战:用readelf和objdump亲手分析一个.o文件的.rela.text节

逆向工程的世界里,每个二进制文件都像一本加密的日记,而ELF格式则是这本日记的装订方式。今天我们要翻开其中一页——.rela.text节,这个看似晦涩的概念实际上是理解程序如何从分散的代码片段成长为完整可执行文件的关键。

当你用GCC编译一个C文件生成.o目标文件时,编译器会留下许多"填空题",这些题目就是.rela.text节中的重定位条目。想象一下,你写了一个调用printf的函数,但编译器并不知道printf最终会住在内存的哪个地址——这就是.rela.text存在的意义,它告诉链接器:"这里有个空需要填,填的内容是printf的地址"。

1. 实验环境准备

1.1 创建测试用例

我们先从一个简单的C程序开始,这样可以清晰地观察.rela.text的结构:

// reloc_test.c #include <stdio.h> extern int global_var; void foo() { printf("Hello, relocations!\n"); global_var = 42; }

编译这个文件但不链接:

gcc -c reloc_test.c -o reloc_test.o

1.2 工具检查

确保你的系统安装了以下工具:

  • readelf:ELF文件分析瑞士军刀
  • objdump:反汇编利器
  • hexdump:十六进制查看(可选)

可以用--version检查是否安装:

readelf --version | head -1 objdump --version | head -1

2. 初识.rela.text

2.1 查看重定位节

使用readelf查看重定位信息:

readelf -r reloc_test.o

典型输出如下:

Relocation section '.rela.text' at offset 0x2b8 contains 2 entries: Offset Info Type Sym. Value Sym. Name + Addend 00000000000a 000c00000002 R_X86_64_PC32 0000000000000000 .rodata - 4 000000000014 000d00000004 R_X86_64_PLT32 0000000000000000 puts - 4

2.2 关键字段解析

让我们拆解这个输出:

字段示例值说明
Offset00000000000a在.text节中需要修改的位置偏移量
Info000c00000002高32位是符号表索引(0xc),低32位是重定位类型(0x2=R_X86_64_PC32)
TypeR_X86_64_PC32重定位类型,表示32位PC相对地址
Sym. Value0000000000000000符号的预期值(通常为0,因为尚未链接)
Sym. Name.rodata符号名称,可能是节名或函数名
Addend-4重定位计算中要加的常数

3. 深入重定位条目

3.1 对应汇编代码

先用objdump查看.text节:

objdump -d reloc_test.o

输出片段:

0000000000000000 <foo>: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # b <foo+0xb> b: 48 89 c7 mov %rax,%rdi e: e8 00 00 00 00 call 13 <foo+0x13> 13: c7 05 00 00 00 00 2a movl $0x2a,0x0(%rip) # 1d <foo+0x1d> 1a: 00 00 00 1d: 90 nop 1e: 5d pop %rbp 1f: c3 ret

3.2 匹配重定位点

注意到地址b处的lea指令和e处的call指令都有00 00 00 00的占位符,这正是重定位要修改的位置。对照readelf的输出:

  1. 第一个重定位条目(Offset 0xa)对应mov %rax,%rdi之后的地址,即字符串地址的重定位
  2. 第二个重定位条目(Offset 0x14)对应call指令的操作数

4. 重定位类型详解

4.1 常见x86_64重定位类型

类型说明
R_X86_64_321032位绝对地址
R_X86_64_PC32232位PC相对地址(常用于函数调用)
R_X86_64_PLT32432位PLT相对地址(用于位置无关代码的函数调用)
R_X86_64_64164位绝对地址
R_X86_64_GOTPCREL932位GOT相对PC偏移(用于全局变量访问)

4.2 重定位计算示例

R_X86_64_PC32为例,其计算公式为:

重定位值 = (S + A - P)

其中:

  • S:符号的实际地址
  • A:加数(Addend)
  • P:被重定位的位置地址(r_offset)

在我们的例子中:

  • 对于call puts的重定位:

    • S = puts函数的实际地址
    • A = -4
    • P = 调用指令的下一条指令地址(0x13)

    所以最终填充的偏移量是(puts_addr - 4) - 0x13

5. 手动解析重定位条目

5.1 使用hexdump查看原始数据

hexdump -C -s 0x2b8 -n 32 reloc_test.o

输出类似:

000002b0 0a 00 00 00 00 00 00 00 0c 00 00 00 02 00 00 00 |................| 000002c0 fc ff ff ff ff ff ff ff 14 00 00 00 00 00 00 00 |................|

5.2 解析Elf64_Rela结构

按照Elf64_Rela结构体:

typedef struct { Elf64_Addr r_offset; // 8字节 Elf64_Xword r_info; // 8字节 Elf64_Sxword r_addend; // 8字节 } Elf64_Rela;

第一个条目:

  • r_offset: 0x000000000000000a
  • r_info: 0x0000000c00000002
    • 符号索引: 0xc (ELF64_R_SYM)
    • 类型: 0x2 (ELF64_R_TYPE)
  • r_addend: 0xfffffffffffffffc (-4的补码表示)

6. 动态链接与静态链接的差异

6.1 静态链接后的变化

尝试链接我们的目标文件:

gcc reloc_test.o -o reloc_test

再用readelf查看:

readelf -r reloc_test

你会发现.rela.text节消失了——因为所有重定位已在链接时完成。

6.2 动态库中的重定位

对于共享库,部分重定位会保留到加载时:

gcc -shared -fPIC reloc_test.o -o libreloc.so readelf -r libreloc.so

这时你会看到.rela.plt等节,它们用于动态链接时的延迟绑定。

7. 逆向分析实战技巧

7.1 识别未解析符号

通过重定位表可以快速发现外部依赖:

readelf -r reloc_test.o | awk '/R_/ {print $NF}' | sort -u

输出可能包括:

.rodata puts global_var

7.2 重定位与漏洞挖掘

某些安全漏洞与重定位处理不当有关:

  • 重定位条目被篡改可能导致控制流劫持
  • .rela.plt的修改可以实现GOT表注入
  • 缺少重定位条目可能暗示隐藏的函数调用

7.3 使用pwntools解析

Python的pwntools库可以方便地解析重定位:

from pwn import * elf = ELF('reloc_test.o') for section in elf.sections: if isinstance(section, RelocationSection): print(f"{section.name}:") for reloc in section.relocations: print(f" {hex(reloc.offset)} -> {reloc.symbol.name}")

8. 高级话题:自定义重定位

8.1 链接器脚本控制

通过链接器脚本可以自定义重定位行为:

SECTIONS { .text : { *(.text) _custom_start = .; *(.custom) _custom_end = .; } .rela.custom : { *(.rela.custom) } }

8.2 手动添加重定位

使用汇编可以创建自定义重定位:

.section .text .globl _start _start: call unknown_function # 故意创建未解析引用 .section .data .globl global_ref global_ref: .quad external_variable

编译后会生成额外的重定位条目。

9. 性能与优化考量

9.1 重定位对性能的影响

  • 过多的重定位会减慢链接过程
  • 动态重定位会增加程序启动时间
  • PIC代码通常有更多PC相对重定位,但更利于共享库

9.2 减少重定位的技巧

  • 使用-fvisibility=hidden限制符号导出
  • 合并相似的小函数
  • 避免大量小的全局变量
  • 使用节组(section groups)优化局部符号

10. 跨平台注意事项

10.1 ARM架构的差异

ARM使用不同的重定位类型,例如:

  • R_AARCH64_CALL26:26位函数调用偏移
  • R_AARCH64_ADR_PREL_LO21:21位PC相对地址

10.2 32位与64位区别

特性32位系统64位系统
结构体Elf32_Rel/Elf32_RelaElf64_Rel/Elf64_Rela
典型大小8字节(Rel)/12字节(Rela)16字节(Rela)
常见类型R_386_PC32R_X86_64_PC32
加数处理通常隐含在指令中显式存储在r_addend

11. 调试技巧与常见问题

11.1 调试链接错误

当遇到relocation truncated to fit错误时:

  1. 检查重定位类型是否匹配目标架构
  2. 确认符号是否正确定义
  3. 查看是否有地址溢出(如尝试将64位地址存入32位字段)

11.2 readelf高级用法

组合使用readelf选项获取更全面信息:

readelf -WSrl reloc_test.o
  • -W:不截断长行
  • -S:节头
  • -r:重定位
  • -l:程序头(可执行文件)

12. 工具链集成

12.1 在构建系统中检查重定位

CMake示例:

add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/reloc_report.txt" COMMAND readelf -r $<TARGET_OBJECTS:my_target> > ${CMAKE_CURRENT_BINARY_DIR}/reloc_report.txt DEPENDS my_target )

12.2 自动化分析脚本

Python脚本示例,统计重定位类型:

import collections from elftools.elf.elffile import ELFFile def analyze_relocations(filename): with open(filename, 'rb') as f: elf = ELFFile(f) reloc_counts = collections.Counter() for section in elf.iter_sections(): if isinstance(section, RelocationSection): for reloc in section.iter_relocations(): reloc_type = reloc['r_info_type'] reloc_counts[reloc_type] += 1 print("Relocation type frequency:") for typ, count in reloc_counts.most_common(): print(f" {typ}: {count}")

13. 扩展阅读与资源

13.1 官方文档

  • ELF规范:man elf
  • binutils文档:info binutils
  • System V ABI补充说明(包含各平台重定位定义)

13.2 实用工具

  • objdump -dr:显示反汇编与重定位
  • nm -C:查看符号表(带demangle)
  • llvm-readelf:LLVM版本的增强readelf

14. 真实案例分析

14.1 Linux内核模块重定位

内核模块需要特殊重定位处理:

readelf -r /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/example.ko

观察__this_module等特殊符号的重定位。

14.2 编译器优化影响

比较不同优化级别的重定位差异:

gcc -O0 -c reloc_test.c -o reloc_test_o0.o gcc -O2 -c reloc_test.c -o reloc_test_o2.o diff <(readelf -r reloc_test_o0.o) <(readelf -r reloc_test_o2.o)

15. 安全加固建议

15.1 重定位表保护

  • 使用-z now禁用延迟绑定,减少运行时重定位
  • 考虑-Wl,-z,relro保护GOT表
  • 静态链接关键组件减少动态重定位

15.2 审计要点

检查可疑重定位:

  • 非常规节的重定位
  • 指向动态生成代码的重定位
  • 修改后的重定位表哈希不匹配

16. 性能调优实战

16.1 重定位缓存优化

对于大型项目,可以:

  1. 预链接减少运行时重定位
  2. 使用LD_BIND_NOW强制立即绑定
  3. 调整页面对齐减少TLB失效

16.2 测量工具

使用perf观察重定位开销:

perf stat -e dTLB-load-misses ./program

17. 嵌入式系统特别考量

17.1 静态PIE的影响

位置无关可执行文件(PIE)即使静态链接也需要重定位:

gcc -static-pie reloc_test.c -o reloc_test_pie readelf -r reloc_test_pie

17.2 内存受限设备

优化策略:

  • 合并相似重定位
  • 使用更紧凑的重定位类型
  • 考虑部分链接减少重定位数据

18. 编译器内部实现

18.1 GCC重定位生成

GCC在编译时:

  1. 识别需要重定位的符号引用
  2. 根据目标架构选择适当的重定位类型
  3. 在汇编输出中生成.reloc伪指令

18.2 LLVM的不同处理

LLVM使用不同的中间表示:

  • 早期决定重定位策略
  • 更灵活的重定位类型选择
  • 支持更多架构特定的优化

19. 未来发展趋势

19.1 重定位压缩技术

新兴技术如:

  • 增量编码减少重定位表大小
  • 使用更紧凑的重定位表示
  • 按需加载重定位数据

19.2 安全增强

趋势包括:

  • 重定位表签名验证
  • 细粒度的重定位权限控制
  • 硬件辅助的重定位加速

20. 终极实验:手工修复重定位

作为终极挑战,尝试手动完成链接器的工作:

  1. 用dd提取.text节
  2. 根据.rela.text条目修改二进制
  3. 用hexedit手动填入计算好的地址
  4. 测试修改后的程序是否工作

这个练习会让你真正理解每个字节的意义。

http://www.jsqmd.com/news/664283/

相关文章:

  • 智能生成代码=自动埋雷?紧急预警:这4种AST语义漂移将绕过所有静态扫描器——附实时回滚决策树(已落地金融级生产环境)
  • 快手大模型二面:假如说要设计一个多轮对话Agent,你会怎么设计?
  • 降AI率工具排行榜前10名对比,最后发现只有3款靠谱
  • nli-distilroberta-base实操手册:企业级NLI服务部署与多场景API集成指南
  • 如何让ROS2编译完后自动source环境变量
  • 2026年3月撕碎机刀片直销厂家推荐,撕碎机/刀片撕碎机/轮胎圈口抽丝机/塑料破碎机,撕碎机刀片源头厂家哪家可靠 - 品牌推荐师
  • 2026年质量好的物流门封/月台门封/东台冷库门封优质厂家推荐榜 - 行业平台推荐
  • 全球仅存5份的AGI发展风险对齐时间轴(NSF/DoD/中科院机密评估版节选),2024Q3更新后3处重大修订预警
  • golang如何读写YAML配置文件_golang YAML配置文件读写解析
  • ARM AHB总线传输机制与优化策略详解
  • 为什么82%的团队停用Copilot?——代码熵值暴涨背后的度量盲区(含实时熵监控看板+生成策略调优SOP)
  • 跨平台流媒体下载终极指南:如何用N_m3u8DL-RE轻松获取加密视频内容
  • Pixel Aurora Engine多场景:像素字体生成、复古UI组件库AI设计
  • 2026年口碑好的化纤纸管/DTY纸管厂家推荐与选型指南 - 行业平台推荐
  • 别再用Rule-based工具扫LLM生成代码了,SITS2026验证:传统SAST对Copilot产出漏洞检出率仅31.4%,这3个信号必须立即升级
  • DCT-Net真实案例分享:从普通照片到精美卡通头像的蜕变
  • 终极解决方案:如何让Calibre完美保留中文路径,告别拼音目录困扰
  • 便宜的和贵的降AI率工具差在哪?排行榜前后对比告诉你
  • Youtu-Parsing入门必看:从零配置WebUI(7860端口)快速上手
  • 解锁金融数据宝藏:AKShare财经数据接口库完全指南
  • **发散创新:基于Python与SpeechRecognition库的实时语音识别系统设计与实现**在人工智能飞速发展的今天,语音
  • WorkshopDL深度指南:打破平台壁垒,解锁Steam创意工坊的终极钥匙
  • 仅限首批200家企业的文档同步治理沙盒计划启动:含VS Code插件、Git Hook拦截器及审计看板(限免至Q3末)
  • Qwen3-TTS新手入门:5步搭建语音合成环境,生成你的第一段AI语音
  • Nanbeige 4.1-3B WebUI实战案例:集成Stable Diffusion生成图文回复
  • 硅基的自我觉醒:当AI吃光人类最后一块知识蛋糕,那扇“枯竭之墙”背后藏着怎样的新世界?
  • GHelper终极指南:免费快速掌控你的华硕笔记本性能
  • 排行榜第一的降AI率工具怎么用?手把手教你3步搞定
  • AI热修复不是幻想,而是已上线:某头部云厂商实测数据——平均MTTR从18分钟降至2.3秒,
  • MySQL中如何利用ASCII码转换字符_MySQL ASCII函数应用