我想要编写一段代码来存储原始.elf文件中的符号表和字符串表.我的代码可以做到这一点,但它缺少地址和名称:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

// ELF header structure
typedef struct {
    uint8_t e_ident[16];
    uint16_t e_type;
    uint16_t e_machine;
    uint32_t e_version;
    uint64_t e_entry;
    uint64_t e_phoff;
    uint64_t e_shoff;
    uint32_t e_flags;
    uint16_t e_ehsize;
    uint16_t e_phentsize;
    uint16_t e_phnum;
    uint16_t e_shentsize;
    uint16_t e_shnum;
    uint16_t e_shstrndx;
} Elf64_Ehdr;

// Section header structure
typedef struct {
    uint32_t sh_name;
    uint32_t sh_type;
    uint64_t sh_flags;
    uint64_t sh_addr;
    uint64_t sh_offset;
    uint64_t sh_size;
    uint32_t sh_link;
    uint32_t sh_info;
    uint64_t sh_addralign;
    uint64_t sh_entsize;
} Elf64_Shdr;

// Symbol table entry structure
typedef struct {
    uint32_t st_name;
    uint8_t st_info;
    uint8_t st_other;
    uint16_t st_shndx;
    uint32_t st_value; // normally it was uint64_t
    uint64_t st_size;
    uint32_t st_name2; // Extended name field
} Elf64_Sym;

Elf64_Sym* symbol_table;
char* string_table;
uint64_t stringSize;
size_t num_symbols;

struct SymbolEntry {
    char name[256];
    unsigned long address;
};

// Comparison function for sorting symbols based on their addresses
int compare_symbols(const void* a, const void* b) {
    const Elf64_Sym* symbol_a = (const Elf64_Sym*)a;
    const Elf64_Sym* symbol_b = (const Elf64_Sym*)b;

    if (symbol_a->st_value < symbol_b->st_value) return -1;
    if (symbol_a->st_value > symbol_b->st_value) return 1;
    return 0;
}

int findTables(){
    
    FILE* file = fopen("trace.elf", "rb");
    if (!file) {
        printf("Error opening file\n");
        return 1;
    }

    // Read the ELF header
    Elf64_Ehdr elf_header;
    if (fread(&elf_header, sizeof(Elf64_Ehdr), 1, file) != 1) {
        printf("Error reading ELF header\n");
        fclose(file);
        return 1;
    }

    // Get the section header table offset from the ELF header
    fseek(file, elf_header.e_shoff, SEEK_SET);

    // Read the section header table
    Elf64_Shdr section_headers[elf_header.e_shnum];
    if (fread(section_headers, sizeof(Elf64_Shdr), elf_header.e_shnum, file) != elf_header.e_shnum) {
        printf("Error reading section headers\n");
        fclose(file);
        return 1;
    }

    // Find the symbol table and the associated string table (for symbol names)
    Elf64_Shdr* symbol_table_header = NULL;
    Elf64_Shdr* string_table_header = NULL;
    for (int i = 0; i < elf_header.e_shnum; i++) {
        if (section_headers[i].sh_type == 0x2) { // SHT_SYMTAB
            symbol_table_header = &section_headers[i];
        } else if (section_headers[i].sh_type == 0x3) { // SHT_STRTAB
            string_table_header = &section_headers[i];
        }

        if (symbol_table_header && string_table_header) {
            break; // Both tables found, exit the loop
        }
    }

    if (!symbol_table_header || !string_table_header) {
        printf("Symbol table or string table not found\n");
        fclose(file);
        return 1;
    }

    // Calculate the number of symbols in the symbol table
    num_symbols = symbol_table_header->sh_size / sizeof(Elf64_Sym);

    // Read the symbol table
    symbol_table = (Elf64_Sym*)malloc(symbol_table_header->sh_size);
    if (!symbol_table) {
        printf("Error allocating memory for symbol table\n");
        fclose(file);
        return 1;
    }
    fseek(file, symbol_table_header->sh_offset, SEEK_SET);
    if (fread(symbol_table, sizeof(Elf64_Sym), num_symbols, file) != num_symbols) {
        printf("Error reading symbol table\n");
        free(symbol_table);
        fclose(file);
        return 1;
    }

    // Read the string table
    string_table = (char*)malloc(string_table_header->sh_size);
    if (!string_table) {
        printf("Error allocating memory for string table\n");
        free(symbol_table);
        fclose(file);
        return 1;
    }
    fseek(file, string_table_header->sh_offset, SEEK_SET);
    if (fread(string_table, 1, string_table_header->sh_size, file) != string_table_header->sh_size) {
        printf("Error reading string table\n");
        free(symbol_table);
        free(string_table);
        fclose(file);
        return 1;
    }
    stringSize = string_table_header->sh_size;
    fclose(file);
}

void printTables(){
    printf("Address\t\tName\n");
    printf("-------\t\t----\n");

    // Print all symbols with their addresses and names
    for (size_t j = 0; j < num_symbols; j++) {
        // Check if the symbol name is valid (inside the string table)
        if (symbol_table[j].st_name < stringSize) {
            char* symbol_name = &string_table[symbol_table[j].st_name];
            printf("0x%08x\t%s\n", symbol_table[j].st_value, symbol_name);
        }
    }
}

void freeSpaces(){
    free(symbol_table);
    free(string_table);
}

int main() {

    if(findTables() == 1){
        printf("Exiting...");
        return 0;
    }
    // Sort the symbol table based on addresses
    qsort(symbol_table, num_symbols, sizeof(Elf64_Sym), compare_symbols);

    printTables();
    
    freeSpaces();

    return 0;
}

以下是trace.self的一些代码输出:

0x004016d0      __do_global_dtors_aux
0x00401ac1      trace_return_values
0x00401b0c      foo
0x00401b36      main
0x00401b50      handle_zhaoxin
0x00401fb0      get_common_indices.constprop.0
0x00402df0      __libc_start_main_impl

但是,当使用"nm-n trace.self"命令并以这种方式获取符号表时,相同的部分是:

00000000004016d0 t __do_global_dtors_aux
0000000000401710 t frame_dummy
0000000000401745 T get_address
0000000000401ac1 T trace_return_values
0000000000401b0c T foo
0000000000401b21 T bar
0000000000401b36 T main
0000000000401b50 t handle_zhaoxin
0000000000401d20 t handle_amd
0000000000401ed0 t call_fini
0000000000401f10 t __libc_start_call_main

如您所见,第一个输出中缺少一些地址和名称.尤其是"wine 吧".是我的代码错误还是有其他问题?

推荐答案

原始.elf文件中的符号表和字符串表.

您应该知道,包含ET_DYNET_EXEC.e_type的ELF文件可能有two个符号表--"常规"和"动态"符号表:

readelf -WS /tmp/a.out | egrep 'symtab|dynsym'
  [ 7] .dynsym           DYNSYM          0000000000000410 000410 000120 18   A  8   1  8
  [30] .symtab           SYMTAB          0000000000000000 003080 000468 18     31  21  8

和多达three SYMTAB个区段,例如

 readelf -WS /tmp/a.out | egrep 'STRTAB'
  [ 8] .dynstr           STRTAB          0000000000000530 000530 000139 00   A  0   0  1
  [31] .strtab           STRTAB          0000000000000000 0034e8 00035a 00      0   0  1
  [32] .shstrtab         STRTAB          0000000000000000 003842 00012c 00      0   0  1

您的代码是错误的,因为它选取了它找到的第一个STRTAB节,这可能不是SYMTAB实际引用的节.

例如,对于上面的可执行文件,您的代码将 Select .dynstr而不是.strtab(这正是您想要的).

找到SYMTAB节后,必须查看symbol_table_header->sh_link以找到SYMTAB引用的正确的STRTAB节(sh_link是上面的第9列;您可以看到.dynsym链接到第8节,.symtab链接到第31节).


附注:除非您的程序是在没有/usr/include/elf.h的系统上构建的,否则™这样做真的是个坏主意:

// ELF header structure
typedef struct {
    uint8_t e_ident[16];
    uint16_t e_type;
    uint16_t e_machine;
...

您应该使用系统提供的<elf.h>.

如果您是在没有<elf.h>的系统上构建此应用程序,则still是一个非常糟糕的主意:

 if (section_headers[i].sh_type == 0x2) { // SHT_SYMTAB

相反,编写如下代码:

#ifndef SHT_SYMTAB
#define SHT_SYMTAB 2
#endif
...

 if (section_headers[i].sh_type == SHT_SYMTAB) {
...

C++相关问答推荐

C中的ATONE会扰乱SEN/CLUTE GMS应用程序中的其他字符串

ATTiny1606定时器TCA 0中断未触发

为什么我得到更多的256假阳性在PKZIP解密密钥验证?

DPDK-DumpCap不捕获端口上的传入数据包

C:fopen是如何实现二进制模式和文本模式的?

为什么GCC在每次循环迭代时都会生成一个数组的mov&S使用[]访问数组?(-03,x86)

在传统操作系统上可以在虚拟0x0写入吗?

Win32API Wizzard97 PropSheet_SetWizButton不工作

在我的代码中,我需要在哪里编写输出函数?

为什么我会收到释放后堆使用错误?

getline()从c中的外部函数传递指针时输出null

C指针概念分段故障

当内存来自Malloc时,将char*转换为另一个指针类型是否违反了严格的别名规则?

是否定义了此函数的行为?

Caesar密码调试:输出文本末尾的问号和随机字符

收到不兼容的指针类型警告,因为函数的返回不是空*,而是 struct 指针

Go和C中的数据 struct 对齐差异

Realloc():中止的下一个大小无效(核心转储)

如何使用 VLA 语法使用 const 指针声明函数

C 中从 Unix 纪元时间转换的损坏