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

来源:AI教程网作者:广州网站建设头衔:草根站长
导读:本期聚焦于小伙伴创作的《c++如何读取和修改ELF二进制文件中的字符串表String Table内容》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《c++如何读取和修改ELF二进制文件中的字符串表String Table内容》有用,将其分享出去将是对创作者最好的鼓励。

ELF是Linux系统下可执行文件、目标文件、共享库的标准格式,字符串表是ELF中存储各类字符串的段,常见的包括存放段名的.shstrtab段和存放符号名的.strtab段,每个字符串以空字符结尾,字符串表开头第一个字节为0,用于标识空字符串。

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

ELF字符串表的结构基础

ELF文件的字符串表本质是一段连续的字节区域,内部没有复杂的头部结构,仅通过偏移量来定位不同的字符串。比如偏移量0对应空字符串,偏移量1对应从第一个非0字节开始到下一个空字符结束的字符串。

要操作字符串表,首先需要获取字符串表所在的段信息。ELF的段表头(Elf32_Shdr或Elf64_Shdr)中,sh_name字段存储的是段名在.shstrtab字符串表中的偏移,sh_offset是段在文件中的偏移,sh_size是段的大小。

用C++读取ELF字符串表内容

读取字符串表的核心步骤是:打开ELF文件、解析ELF头部、找到目标字符串表对应的段表项、根据段表项的偏移和大小读取字符串表数据、通过偏移量提取目标字符串。

以下是32位ELF读取.shstrtab字符串表的示例代码:

#include <iostream>
#include <fstream>
#include <vector>
#include <elf.h>

using namespace std;

// 读取ELF字符串表内容
vector<char> read_string_table(const char* file_path, Elf32_Off strtab_offset, Elf32_Word strtab_size) {
    ifstream file(file_path, ios::binary);
    if (!file.is_open()) {
        cerr << "无法打开文件" << endl;
        return {};
    }
    // 移动文件指针到字符串表起始位置
    file.seekg(strtab_offset, ios::beg);
    vector<char> strtab(strtab_size);
    file.read(strtab.data(), strtab_size);
    file.close();
    return strtab;
}

// 根据偏移从字符串表获取字符串
string get_string_from_strtab(const vector<char>& strtab, Elf32_Word offset) {
    if (offset >= strtab.size()) {
        return "";
    }
    // 从偏移位置开始读取直到遇到空字符
    const char* str_start = strtab.data() + offset;
    return string(str_start);
}

int main() {
    const char* elf_file = "test.o";
    ifstream file(elf_file, ios::binary);
    if (!file.is_open()) {
        cerr << "无法打开ELF文件" << endl;
        return 1;
    }

    // 读取ELF头部
    Elf32_Ehdr ehdr;
    file.read(reinterpret_cast<char*>(&ehdr), sizeof(ehdr));
    // 校验ELF魔数
    if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
        ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) {
        cerr << "不是有效的ELF文件" << endl;
        return 1;
    }

    // 读取段表头
    file.seekg(ehdr.e_shoff, ios::beg);
    vector<Elf32_Shdr> shdrs(ehdr.e_shnum);
    file.read(reinterpret_cast<char*>(shdrs.data()), sizeof(Elf32_Shdr) * ehdr.e_shnum);

    // 找到.shstrtab段(段表头的e_shstrndx索引对应的段)
    Elf32_Shdr& strtab_shdr = shdrs[ehdr.e_shstrndx];
    vector<char> strtab = read_string_table(elf_file, strtab_shdr.sh_offset, strtab_shdr.sh_size);

    // 打印所有段名
    cout << "所有段名:" << endl;
    for (int i = 0; i < ehdr.e_shnum; i++) {
        string sec_name = get_string_from_strtab(strtab, shdrs[i].sh_name);
        cout << "段" << i << ": " << sec_name << endl;
    }

    file.close();
    return 0;
}

修改ELF字符串表内容并写回文件

修改字符串表需要注意两个核心问题:一是新字符串的长度不能超过原字符串的长度,否则会覆盖后续内容破坏文件结构;二是如果必须修改长度,需要整体调整ELF文件的结构,重新计算所有相关段的偏移,操作复杂度较高。

以下是将字符串表中某个指定偏移的字符串替换为等长新字符串的示例代码:

#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
#include <elf.h>

using namespace std;

// 修改字符串表中指定偏移的字符串(要求新字符串长度不超过原字符串长度)
bool modify_string_in_strtab(const char* file_path, Elf32_Off strtab_offset, Elf32_Word target_offset, const char* new_str) {
    fstream file(file_path, ios::binary | ios::in | ios::out);
    if (!file.is_open()) {
        cerr << "无法打开文件" << endl;
        return false;
    }

    // 先读取原字符串,校验新字符串长度
    file.seekg(strtab_offset + target_offset, ios::beg);
    string old_str;
    char c;
    while (file.get(c) && c != '') {
        old_str.push_back(c);
    }
    if (strlen(new_str) > old_str.size()) {
        cerr << "新字符串长度超过原字符串,无法修改" << endl;
        return false;
    }

    // 移动指针到目标偏移位置,写入新字符串和结尾空字符
    file.seekp(strtab_offset + target_offset, ios::beg);
    file.write(new_str, strlen(new_str));
    file.put('');

    file.close();
    return true;
}

int main() {
    const char* elf_file = "test.o";
    // 假设我们已经知道要修改的字符串在.shstrtab中的偏移是5,原字符串是.text
    // 将其修改为.texa(长度相同)
    if (modify_string_in_strtab(elf_file, 0x1a8, 5, "texa")) {
        cout << "字符串修改成功" << endl;
    } else {
        cout << "字符串修改失败" << endl;
    }
    return 0;
}

操作注意事项

  • 操作前一定要备份原始ELF文件,避免修改错误导致文件损坏无法恢复。
  • 64位ELF的结构体和32位不同,需要将Elf32_前缀替换为Elf64_,同时注意字段类型的长度差异。
  • 如果要修改的字符串需要变长,必须重新调整ELF文件的所有段偏移,同时更新段表头、程序头中的相关偏移字段,否则文件会无法正常运行。
  • 修改字符串表后,如果字符串被符号表引用,需要同步检查符号表的内容是否需要调整,避免符号引用失效。

ELFString_TableC++修改时间:2026-07-03 15:39:49

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。