You need to enable JavaScript to run this app. ELF解析中读取.symtab段符号时所有st_name字段均为0的问题
优惠活动
大模型
产品
解决方案
定价
更多

ELF解析中读取.symtab段符号时所有st_name字段均为0的问题

异常原因定位

核心错误1:数组长度计算完全错误

你定义段头表数组时,混淆了「总字节数」和「数组元素个数」:

  • 你计算的shdr_tab_size是段头表的总字节数(每个段头大小 × 段数量)
  • 但Elf64_Shdr shdr_tab[shdr_tab_size]要求的参数是元素个数,也就是段数量本身e_shnum
  • 这会导致栈上分配的数组大小是预期的sizeof(Elf64_Shdr)倍,轻则内存浪费,重则直接栈溢出,后续所有段头、符号表的读取结果都是内存垃圾,直接导致st_name全为0。

核心错误2:变量类型选择溢出

你用16位无符号类型Elf64_Half存储段头表总大小,一旦总大小超过65535(普通ELF文件很容易达到),就会发生截断,得到错误的数组长度,进一步破坏内存布局。

其他次要错误

  • 所有fread调用未检查返回值,无法确认是否真的读取到了预期数量的字节
  • 符号表条目数写死为10,未通过规范要求的sh_size / sh_entsize计算
  • 除shdr_names外,其余malloc分配的内存未做空指针检查,分配失败时会直接访问非法内存
  • 段头表用栈上可变长度数组(VLA)分配,栈空间通常仅几MB,极易触发栈溢出
修正后的代码实现
// 前置要求:已正确读取并校验ELF头ehdr的合法性
Elf64_Xword shdr_total_size = (Elf64_Xword)ehdr->e_shentsize * ehdr->e_shnum;
// 用堆分配替代栈VLA,避免栈溢出
Elf64_Shdr *shdr_tab = malloc(shdr_total_size);
if (!shdr_tab) {
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}

// 读取段头表
rewind(infos.fp);
fseek(infos.fp, ehdr->e_shoff, SEEK_SET);
size_t read_cnt = fread(shdr_tab, 1, shdr_total_size, infos.fp);
if (read_cnt != shdr_total_size) {
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}

// 读取段字符串表(兼容段数超限的边缘规范场景)
Elf64_Word shstrtab_idx = ehdr->e_shstrndx;
if (shstrtab_idx == SHN_XINDEX) {
    shstrtab_idx = shdr_tab[0].sh_link;
}
Elf64_Shdr *shstrtab_shdr = &shdr_tab[shstrtab_idx];
char *shdr_names = malloc(shstrtab_shdr->sh_size);
if (!shdr_names) {
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}
fseek(infos.fp, shstrtab_shdr->sh_offset, SEEK_SET);
read_cnt = fread(shdr_names, 1, shstrtab_shdr->sh_size, infos.fp);
if (read_cnt != shstrtab_shdr->sh_size) {
    free(shdr_names);
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}

// 定位符号表段及关联的字符串表
Elf64_Shdr *shdr_symtab = NULL, *shdr_strtab = NULL;
for (Elf64_Word i = 0; i < ehdr->e_shnum; i++) {
    if (shdr_tab[i].sh_type == SHT_SYMTAB) {
        shdr_symtab = &shdr_tab[i];
        // 直接通过sh_link获取关联strtab,避免多strtab场景下查找错误
        shdr_strtab = &shdr_tab[shdr_symtab->sh_link];
        break;
    }
}
if (!shdr_symtab || shdr_symtab->sh_size == 0) {
    free(shdr_names);
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_SUCCESS);
}

// 读取符号表
Elf64_Sym *symtab = malloc(shdr_symtab->sh_size);
if (!symtab) {
    free(shdr_names);
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}
fseek(infos.fp, shdr_symtab->sh_offset, SEEK_SET);
read_cnt = fread(symtab, 1, shdr_symtab->sh_size, infos.fp);
if (read_cnt != shdr_symtab->sh_size) {
    free(symtab);
    free(shdr_names);
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}

// 读取关联的字符串表
char *strtab = malloc(shdr_strtab->sh_size);
if (!strtab) {
    free(symtab);
    free(shdr_names);
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}
fseek(infos.fp, shdr_strtab->sh_offset, SEEK_SET);
read_cnt = fread(strtab, 1, shdr_strtab->sh_size, infos.fp);
if (read_cnt != shdr_strtab->sh_size) {
    free(strtab);
    free(symtab);
    free(shdr_names);
    free(shdr_tab);
    fclose(infos.fp);
    exit(EXIT_FAILURE);
}

// 按规范计算符号条目数,替代硬编码的10
size_t sym_count = shdr_symtab->sh_size / shdr_symtab->sh_entsize;
for (size_t i = 0; i < sym_count; i++) {
    // st_name为0对应空符号,直接跳过
    if (symtab[i].st_name == 0) continue;
    printf("%s\n", strtab + symtab[i].st_name);
}

// 释放所有资源
free(strtab);
free(symtab);
free(shdr_names);
free(shdr_tab);
fclose(infos.fp);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 15:15:04