Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find function's start offset in ELF

Suppose I have function fn somewhere within the .text section of an ELF64 executable. Is there a way to know at which offset (in bytes) from the start of the ELF file the fn function is located? Note that I don't need to know at which VA it was relocated at linking time, but its position within the ELF file.

like image 289
pr0gma Avatar asked Oct 25 '16 10:10

pr0gma


3 Answers

simply use objdump -F option

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):
like image 94
andreym Avatar answered Nov 07 '22 09:11

andreym


Generally yes, if you can parse the ELF file directly or combine output from tools like objdump and readelf.

More specific: You can get the offset and virtual address of your .text section with 'readelf -S file' - write those down. Further you can list symbols with 'readelf -s file', as long your executable is not stripped, and your function is visible (not static or in an anonymous namespace) then you should find your function and the virtual address of it.

Thus you can calculate the offset via

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

Thats assuming you want to do it "offline" with common tools. Its more difficult if you dont have access to the unstripped ELF file, and since only a part of the ELF File remains in memory, probably not possible without adding some information with "offline" tricks.

like image 11
Norbert Lange Avatar answered Nov 07 '22 11:11

Norbert Lange


The answer by Norbert Lange works for the functions that are listed in the symbol table of the ELF file. But static functions will not be present there, so even if e.g. GDB could find them (by using DWARF debug info), readelf -s won't.

In this case, you can use GDB. For example, let's find the offset of xfce_displays_helper_normalize_crtc in /usr/bin/xfsettingsd (that was my actual use case, thus this obscure choice of an example).

$ 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>

Note that here we only load the file with GDB, don't let it start. And then use p command (print in full form) to get the address. So in my case, the function is at offset 0x11e80.

In some cases GDB will resolve the offset to virtual address even before we start or starti the program. This happens, in particular, on x86-32. In this case we can simply subtract the virtual address of the file image, given by 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

In the example above, the virtual address of the file image is 0x8048000, which would have to be subtracted from virtual address of the function if GDB happens to output it instead of the offset.

like image 1
Ruslan Avatar answered Nov 07 '22 09:11

Ruslan