You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复objcopy输出二进制文件的ELF段地址问题

问题

尝试将编译后的代码注入ELF可执行文件,策略是在代码段末尾写入字节(选择该段因需执行载荷),当段间padding不足时用objcopy --update-section <name>=<file>扩展段。以.fini段为宿主,其后是.rodata段。执行objcopy后,代码段的文件大小和内存镜像大小正确,段和节偏移也已按需修补,代码存在于预期偏移(经objdump确认)。但所有段的虚拟地址未被修补,导致代码段与后续节/段重叠,在_dl_start期间触发段错误(代码被视为位于只读段)。

objcopy前的readelf输出片段

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [16] .fini             PROGBITS         00000000000a3e84  000a3e84
       0000000000000009  0000000000000000  AX       0     0     4
  [17] .rodata           PROGBITS         00000000000a4000  000a4000
       000000000003b488  0000000000000000   A       0     0     32

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000063000 0x0000000000063000 0x0000000000063000
                 0x0000000000040e8d 0x0000000000040e8d  R E    0x1000
  LOAD           0x00000000000a4000 0x00000000000a4000 0x00000000000a4000
                 0x0000000000043ccc 0x0000000000043ccc  R      0x1000

objcopy后的readelf输出片段

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [16] .fini             PROGBITS         00000000000a3e84  000a3e84
       00000000000002bd  0000000000000000  AX       0     0     4
  [17] .rodata           PROGBITS         00000000000a4000  000a5000
       000000000003b488  0000000000000000   A       0     0     32

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000063000 0x0000000000063000 0x0000000000063000
                 0x0000000000041141 0x0000000000041141  R E    0x1000
  LOAD           0x00000000000a5000 0x00000000000a4000 0x00000000000a4000
                 0x0000000000043ccc 0x0000000000043ccc  R      0x1000

系统环境:Linux 6.1.0-13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.55-1 (2023-09-29) x86_64 GNU/Linux

需要解决:如何进一步修补该二进制文件,使其能正常运行且保持有效的ELF格式?


解决方案

1. 修正后续LOAD段的虚拟地址

从输出可见,第二个LOAD段(只读段)的文件偏移已被调整为0x000a5000,但虚拟地址仍为原0x000a4000,导致与第一个LOAD段(可执行段)的内存范围重叠(第一个LOAD段内存结束地址为0x00063000 + 0x00041141 = 0x000a4141,与第二个LOAD段起始地址0x000a4000重叠)。

操作步骤:

  • 用readelf -l确认所有LOAD段的详细信息
  • 使用二进制编辑工具(如hexedit、bvi)或ELF处理脚本(基于pyelftools),将第二个LOAD段的VirtAddr和PhysAddr修改为0x000a5000,使其与文件偏移一致,避免内存范围重叠。

2. 同步修正后续节的虚拟地址

.rodata节的虚拟地址仍为0x000a4000,需同步修改为0x000a5000,与所属LOAD段的虚拟地址、文件偏移匹配。同时检查.rodata之后的所有节,将它们的Address字段增加对应的偏移量(此处为0x1000),确保所有节的内存地址落在所属LOAD段范围内。

3. 修复重定位条目(若存在)

如果是动态链接的可执行文件,需检查重定位表中指向.rodata或后续节的条目:

  • 用readelf -r查看重定位信息
  • 将相关条目的地址同步增加对应的偏移量,避免程序运行时访问错误地址。

4. 替代策略:新增可执行节

若不想手动修补,可换用更可控的方式注入代码:

  • 用objcopy --add-section .new_code=payload.bin --set-section-flags .new_code=alloc,exec,load添加新的可执行节
  • 确保新节被包含在第一个LOAD段内,再调整后续LOAD段和节的地址,或使用自定义链接脚本通过ld重新链接。

5. 验证修补结果

完成后用以下命令验证有效性:

  • readelf -S:检查所有节的Address和Offset是否匹配所属LOAD段范围
  • readelf -l:确认LOAD段无内存重叠,虚拟地址与文件偏移对应关系正确
  • objdump -d:确认注入代码位于正确的虚拟地址
  • 直接运行可执行文件,验证是否能正常启动并执行注入代码。

内容的提问来源于stack exchange,提问作者matteobu02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:17:29