跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

c++如何读取和修改ELF二进制文件中的字符串表(String Table)内容【底层】

直接用 fread 修改 .strtab 会破坏 ELF 文件,因其字符串表被其他节区通过偏移量引用,长度变化或越界写入将导致偏移错位、数据覆盖及符号解析失败。 为什么直接用
fread
修改
.strtab
会破坏 ELF 文件 ELF 的字符串表(
.strtab
或
.dynstr
)不是独立文件块,它被其他节区(如
.symtab
、
.dynamic
)通过偏移量(
st_name
、
d_tag
等字段)引用。直接覆盖字符串内容会导致:长度变化 → 后续字符串偏移错位 → 符号解析失败;或者越界写入 → 覆盖相邻节区数据(比如把
.symtab
的第一个符号名写爆到下一个符号的
st_value
字段里)。这不是“改文本”,是动内存布局。 字符串表必须保持「所有字符串以
\0
结尾 + 整体连续 + 无空洞」,新增字符串只能追加到末尾 修改已有字符串只能等长替换(包括结尾
\0
),否则必须重写整个
.strtab
并更新所有引用它的节区头和字段
readelf -S
显示的
.strtab
sh_offset
和
sh_size
是磁盘映像位置,不是内存加载地址,操作时必须按文件 offset 计算,不能按
mmap
后的虚拟地址硬算 如何安全地在 ELF 中新增一个字符串并获取其偏移 新增字符串必须追加到
.strtab
末尾,并更新节头中
sh_size
,同时确保文件后续内容(如下一节区)不被覆盖。关键不是“写进去”,而是“让整个 ELF 结构还认得它”。 用
lseek
定位到原
.strtab
末尾(
sh_offset + sh_size
),再
write
新字符串(含结尾
\0
) 用
read
读取原始 ELF 头和节头表,找到
.strtab
对应的
Elf64_Shdr
,将其
sh_size
增加新字符串长度(含
\0
),再
pwrite
回原位置 如果新增后导致节头表本身被推移(例如文件末尾扩展触发重排),必须同步更新 ELF 头中
e_shoff
—— 这种情况极少见,但真实存在,尤其当原文件无足够 padding 时 不要用
ftruncate
扩展文件后再写:某些系统对只读 mmap 区域或签名验证过的二进制(如 Android 的 AVB)会拒绝加载已扩容的 ELF 修改符号名时,必须同步更新哪些字段 改符号名不只是动
.strtab
,符号表(
.symtab
)里的每个
Elf64_Sym
都有
st_name
字段,它是相对于
.strtab
起始的字节偏移。改名即改这个偏移值,而偏移值取决于你把新字符串放在
.strtab
的哪个位置。 先确定新字符串在
.strtab
中的绝对文件偏移:
old_strtab_offset + old_strtab_size
遍历
.symtab
中所有
Elf64_Sym
,找到要修改的符号(比如
st_name != 0 && strcmp(get_string_at(strtab, sym->st_name), "old_name") == 0
) 将该符号的
st_name
改为新字符串在
.strtab
中的偏移(不是索引,是文件内 byte offset) 注意:
.symtab
本身可能被
strip
掉,此时只能改
.dynsym
,逻辑相同,但需确认
.dynstr
是否可写(有些发行版设为
PROT_READ
) 用
libelf
时最容易忽略的三个细节
libelf
封装了大部分结构解析,但底层仍是文件操作,它不会自动帮你处理“改了字符串表就要重算所有引用”的逻辑,更不会保证你写的偏移合法。 C知道 CSDN推出的一款AI技术问答工具 下载 立即学习 “ C++免费学习笔记(深入) ”; 调用
elf_update(elf, ELF_C_WRITE)
前,必须手动调用
gelf_update_sym
更新每个改过的符号,否则
.symtab
内存缓存不变,写回文件还是旧的
elf_getdata
返回的
data->d_buf
指向的是内存副本,直接
memcpy
写字符串进去没用——得用
gelf_getsym
/
gelf_update_sym
操作符号,用
data->d_buf
+ 偏移操作字符串表原始字节
elf_begin(..., ELF_C_RDWR, ...)
不等于“可以随便写”:若原 ELF 文件以只读方式打开(
open(path, O_RDONLY)
),即使传
ELF_C_RDWR
,
elf_update
也会失败并返回
NULL
—— 必须用
O_RDWR
打开文件描述符 真正难的从来不是“怎么找到字符串表”,而是改完之后,所有依赖它的地方是否还指向有效位置。一个偏移算错,整个符号解析链就断了,loader 会静默跳过符号或直接报
Invalid ELF image
。

相关文章