从 ELF 二进制文件中提取函数字节

Extract function bytes from ELF binary file

我想编写一个 python 脚本,它从知道其地址(例如 0x437310 和大小)的 elf 二进制文件中提取函数操作码。如何将此地址映射到二进制文件中的相应偏移量以开始从中读取?

使用十六进制编辑器,我可以找出 0x437310 处的函数从十六进制转储中的偏移量 0x37310 开始。

我怎样才能用通用的方式计算这个,因为二进制文件的 imagebase 并不总是相同的。

任何帮助将不胜感激

假设我想从 bash 中提取 maybe_make_export_env 的指令。

你要做的第一件事就是在符号 table:

中找到这个符号
$ readelf -s /bin/bash
   Num:    Value          Size Type    Bind   Vis      Ndx Name
[...]
   216: 000000000043ed80    18 FUNC    GLOBAL DEFAULT   14 maybe_make_export_env
[...]

这为我们提供了函数 在内存中的地址 (0x43ed80) 及其长度 (18)。

我们有内存中的地址(在过程映像中)。我们现在要在文件中找到相关地址。为此,我们需要查看程序头 table:

$ readelf -l /bin/bash
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000f3ad4 0x00000000000f3ad4  R E    200000
  LOAD           0x00000000000f3de0 0x00000000006f3de0 0x00000000006f3de0
                 0x0000000000008ea8 0x000000000000ea78  RW     200000
  DYNAMIC        0x00000000000f3df8 0x00000000006f3df8 0x00000000006f3df8
                 0x0000000000000200 0x0000000000000200  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000d8ab0 0x00000000004d8ab0 0x00000000004d8ab0
                 0x0000000000004094 0x0000000000004094  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x00000000000f3de0 0x00000000006f3de0 0x00000000006f3de0
                 0x0000000000000220 0x0000000000000220  R      1

我们想找到这个地址属于哪个 PT_LOAD 条目(基于 VirtAddrMemSize)。第一个 PT_LOAD 条目范围从 0x4000000x400000 + 0xf3ad4 = 0x4f3ad4(排除)因此该符号属于此 PT_LOAD 条目。

我们可以在文件中找到函数的位置:symbol_value - VirtAddr + Offset = 0x3ed80.

这是文件的相关部分:

0003ed80: 8b05 3260 2b00 85c0 7406 e911 feff ff90  ..2`+...t.......
0003ed90: f3c3 0f1f 4000 662e 0f1f 8400 0000 0000  ....@.f.........

我们确实拥有与 objdump -d /bin/bash:

给出的字节相同的字节
000000000043ed80 <maybe_make_export_env@@Base>:
  43ed80:       8b 05 32 60 2b 00       mov    0x2b6032(%rip),%eax        # 6f4db8 <array_needs_making@@Base>
  43ed86:       85 c0                   test   %eax,%eax
  43ed88:       74 06                   je     43ed90 <maybe_make_export_env@@Base+0x10>
  43ed8a:       e9 11 fe ff ff          jmpq   43eba0 <bind_global_variable@@Base+0x60>
  43ed8f:       90                      nop
  43ed90:       f3 c3                   repz retq 
  43ed92:       0f 1f 40 00             nopl   0x0(%rax)
  43ed96:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  43ed9d:       00 00 00