【问题标题】:Segfault when reading ELF Shdr of own executable读取自己的可执行文件的 ELF Shdr 时出现段错误
【发布时间】:2022-10-23 02:31:45
【问题描述】:

我正在尝试读取程序自己的 ELF 二进制文件的符号表作为符号器的一部分。其中一部分涉及找到 ELF 开始,然后是 ELF shdr 等。不过,我一定是做错了什么,因为尽管 e_shoff 与我看到的 readelf 手动匹配二进制文件并且开始地址看起来合理,但我不能阅读 shdr。

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <assert.h>
#include <dlfcn.h>
#include <elf.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>

static int findELFStartCallback(struct dl_phdr_info *info, size_t size,
                                void *data) {
  static_cast<void>(size);
  static int address_found = 0;
  if (address_found) {
    return 0;
  }
  address_found = 1;
  fprintf(stderr, "relocation: 0x%lx\n", (long)info->dlpi_addr);
  for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++) {
    if (info->dlpi_phdr[i].p_type == PT_LOAD) {
      auto result = reinterpret_cast<void *>(info->dlpi_addr +
                                             info->dlpi_phdr[i].p_vaddr);
      fprintf(stderr, "a.out loaded at %p\n", result);
      *reinterpret_cast<void **>(data) = result;
      break;
    }
  }
  return 0;
}

static void *findELFStart() {
  void *result = nullptr;
  dl_iterate_phdr(findELFStartCallback, &result);
  return result;
}

static void checkELF(ElfW(Ehdr) * ehdr) {
  assert(ehdr->e_ident[EI_MAG0] == ELFMAG0 && "bad magic number");
  assert(ehdr->e_ident[EI_MAG1] == ELFMAG1 && "bad magic number");
  assert(ehdr->e_ident[EI_MAG2] == ELFMAG2 && "bad magic number");
  assert(ehdr->e_ident[EI_MAG3] == ELFMAG3 && "bad magic number");
}

int main(int argc, char *argv[]) {
  char *exe_ = nullptr;
  exe_ = reinterpret_cast<char *>(findELFStart());
  assert(exe_ != nullptr && "could not find ELF header");
  checkELF(reinterpret_cast<ElfW(Ehdr) *>(exe_));
  auto elf = reinterpret_cast<ElfW(Ehdr) *>(exe_);
  fprintf(stderr, "e_shoff is %ld (0x%lx)\n", elf->e_shoff, elf->e_shoff);
  auto shdr = reinterpret_cast<ElfW(Shdr) *>(exe_ + elf->e_shoff);
  fprintf(stderr, "shdr is %ld (%p)\n", (size_t)shdr, (void*)shdr);
  const char *str = exe_ + shdr[elf->e_shstrndx].sh_offset;  // boom
}

我得到一个段错误。当我在 GDB 中加载它时,看起来 shdr 确实是一个坏指针。我在这里想念什么?

样本输出:

computer% ./p/dladdr                                                 
relocation: 0x0
a.out loaded at 0x400000
e_shoff is 24528 (0x5fd0)
shdr is 4218832 (0x405fd0)
zsh: segmentation fault (core dumped)  ./p/dladdr
computer%

编辑:在看到Reading ELF header of loaded shared object during runtime 之后,这些部分可能没有加载到内存中......

编辑:我完成了符号器,它可用here

【问题讨论】:

    标签: c++ elf


    【解决方案1】:

    也许这些部分只是没有加载到内存中......

    这是完全正确的。这是我系统上的readelf -WS /bin/date

    Section Headers:
      [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
      [ 1] .interp           PROGBITS        0000000000000318 000318 00001c 00   A  0   0  1
      [ 2] .note.gnu.property NOTE            0000000000000338 000338 000050 00   A  0   0  8
      [ 3] .note.gnu.build-id NOTE            0000000000000388 000388 000024 00   A  0   0  4
      [ 4] .note.ABI-tag     NOTE            00000000000003ac 0003ac 000020 00   A  0   0  4
    ...
      [26] .bss              NOBITS          000000000001a0a0 019098 000130 00  WA  0   0 32
      [27] .gnu.build.attributes NOTE            000000000001c1d0 019098 000248 00      0   0  4
      [28] .gnu_debuglink    PROGBITS        0000000000000000 0192e0 000024 00      0   0  4
      [29] .gnu_debugdata    PROGBITS        0000000000000000 019304 0005a0 00      0   0  1
      [30] .shstrtab         STRTAB          0000000000000000 0198a4 00013e 00      0   0  1
    

    请注意,.shstrtab 没有 A(已分配)标志。本节内容在运行时不使用,所以有没理由将它加载到内存中,所以它不是。

    如果要访问.shstrtab,则需要从磁盘上的文件中访问read,或者mmap整个文件(内核仅mmapsPT_LOAD段覆盖的部分,而不是整个文件)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 2020-08-14
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多