Найти смещение начала функции в ELF

Предположим, у меня есть функция fn где-то в разделе .text исполняемого файла ELF64. Есть ли способ узнать, по какому смещению (в байтах) от начала файла ELF находится функция fn? Обратите внимание, что мне не нужно знать, в какую виртуальную машину он был перемещен во время компоновки, а нужно знать его положение в файле ELF.


person pr0gma    schedule 25.10.2016    source источник


Ответы (3)


Как правило, да, если вы можете напрямую анализировать файл ELF или комбинировать вывод таких инструментов, как objdump и readelf.

Более конкретно: вы можете получить смещение и виртуальный адрес вашего раздела .text с помощью «readelf -S file» — запишите их. Далее вы можете перечислить символы с помощью «readelf -s file», если ваш исполняемый файл не удален, а ваша функция видна (не статическая или в анонимном пространстве имен), тогда вы должны найти свою функцию и его виртуальный адрес.

Таким образом, вы можете рассчитать смещение через

смещение символа fn = символ fn VA - .text VA + смещение .text

Это при условии, что вы хотите сделать это «в автономном режиме» с помощью обычных инструментов. Это сложнее, если у вас нет доступа к нераспакованному файлу ELF, и поскольку в памяти остается только часть файла ELF, вероятно, это невозможно без добавления некоторой информации с помощью «автономных» трюков.

person Norbert Lange    schedule 25.10.2016

ответ Норберта Ланге работает для функций, перечисленных в таблице символов файла ELF. Но static функций там не будет, так что даже если, например. GDB может их найти (используя отладочную информацию DWARF), readelf -s нет.

В этом случае вы можете использовать GDB. Например, давайте найдем смещение xfce_displays_helper_normalize_crtc в /usr/bin/xfsettingsd (это был мой фактический вариант использования, поэтому этот неясный выбор примера).

$ 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...
$1 = (void (*)(XfceRRCrtc *, XfceDisplaysHelper *)) 0x11e80 <xfce_displays_helper_normalize_crtc>

Обратите внимание, что здесь мы загружаем файл только с GDB, не позволяем ему запускаться. А затем используйте команду p (print в полной форме), чтобы получить адрес. Итак, в моем случае функция находится по смещению 0x11e80.

В некоторых случаях GDB разрешает смещение в виртуальный адрес даже до того, как мы start или starti запустим программу. Это происходит, в частности, на 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 выдаст его вместо смещения.

person Ruslan    schedule 19.03.2020

просто используйте параметр 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):
person andreym    schedule 27.02.2021