符号表在 c

问题描述 投票:0回答:1

我想编写一个代码来存储原始 .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.elf 代码的一些输出:

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.elf”命令并以相同部分的方式获取符号表时:

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

您可以看到第一个输出中缺少一些地址和名称。尤其是“酒吧”。是我的代码错误还是有其他问题?

c string header symbols elf
1个回答
1
投票

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

您应该知道,带有

.e_type
ET_DYN
ET_EXEC
的 ELF 文件可能有 两个 符号表——“常规”符号表和“动态”符号表:

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

最多

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
实际引用的部分。

例如,对于上面的可执行文件,您的代码将选择

.dynstr
而不是
.strtab
(这正是您的意图)。

找到

SYMTAB
部分后,您必须查看
symbol_table_header->sh_link
以找到您的
STRTAB
引用的正确
SYMTAB
部分(
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>
的系统上构建此系统,那么这样做 仍然 是一个非常糟糕的主意:

 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) {
...
© www.soinside.com 2019 - 2024. All rights reserved.