在 ELF 中查找函数的起始偏移量

Find function's start offset in ELF

假设我在 ELF64 可执行文件的 .text 部分的某处有函数 fn。有没有办法知道 fn 函数位于 ELF 文件开头的哪个偏移量(以字节为单位)?请注意,我不需要知道它在链接时被重新定位在哪个 VA,而是它在 ELF 文件中的位置。

通常是的,如果您可以直接解析 ELF 文件或结合 objdump 和 readelf 等工具的输出。

更具体:您可以使用 'readelf -S file' 获取 .text 部分的偏移量和虚拟地址 - 将它们写下来。 此外,您可以使用 'readelf -s file' 列出符号,只要您的可执行文件未被剥离,并且您的函数可见(不是静态的或在匿名名称空间中),那么您应该找到您的函数及其虚拟地址。

因此您可以通过

计算偏移量

fn symbol offset = fn symbol VA - .text VA + .text offset

那是假设您想 "offline" 使用常用工具来完成。如果您无法访问未剥离的 ELF 文件,这将更加困难,并且由于只有一部分 ELF 文件保留在内存中,如果不使用 "offline" 技巧添加一些信息,可能是不可能的。

适用于 ELF 文件的符号 table 中列出的函数。但是 static 功能不会出现在那里,所以即使例如GDB 可以找到它们(通过使用 DWARF 调试信息),readelf -s 不会。

在这种情况下,您可以使用GDB。例如,让我们在 /usr/bin/xfsettingsd 中找到 xfce_displays_helper_normalize_crtc 的偏移量(那是我的实际用例,因此这个示例的模糊选择)。

$ gdb -q -ex 'p &xfce_displays_helper_normalize_crtc' -ex q xfsettingsd
Reading symbols from xfsettingsd...
Reading symbols from /usr/lib/debug/.build-id/b2/2ad9713642253d4d7a6f94acf0174ccfe3d487.debug...
 = (void (*)(XfceRRCrtc *, XfceDisplaysHelper *)) 0x11e80 <xfce_displays_helper_normalize_crtc>

注意这里我们只用GDB加载文件,不要让它启动。然后使用 p 命令(print 的完整形式)获取地址。所以在我的例子中,函数位于偏移量 0x11e80.

在某些情况下,GDB 会在我们 startstarti 程序之前将偏移量解析为 虚拟 地址。这种情况尤其发生在 x86-32 上。在这种情况下,我们可以简单地减去文件映像的虚拟地址,由 readelf -l:

给出
$ readelf -l /bin/sleep | grep ' VirtAddr \|\<LOAD *0x[0-9a-f]\+\>'
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x05230 0x05230 R E 0x1000

在上面的例子中,文件映像的虚拟地址是0x8048000,如果GDB恰好输出它而不是偏移量,则必须从函数的虚拟地址中减去它。

只需使用objdump -F选项

user@phoenix-amd64:~$ objdump -D -F /opt/phoenix/i486/heap-xxx -D | grep main
08048630 <__libc_start_main@plt> (File Offset: 0x630):
8048679:       e8 b2 ff ff ff          call   8048630 <__libc_start_main@plt> (File 
Offset: 0x630)
080487d5 <main> (File Offset: 0x7d5):