Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Locating the Global Offset Table in an ELF file

Tags:

c++

linux

elf

How can I find the offset of the .got section in an ELF file that I'm parsing?

I don't want to search the section by name, because I don't want to depend on it. When I change the section names with something else, the binaries still work.

like image 835
kubuzetto Avatar asked Jan 07 '23 10:01

kubuzetto


1 Answers

Short answer: in the general case, you can't.

GOT in the linking view

The linking view of the process is given by the section header table. The GOT can be located by:

$ readelf -S $elf
[...]
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [29] .got              PROGBITS         00000000003a2d80  001a2d80
       0000000000000278  0000000000000008  WA       0     0     8
  [30] .got.plt          PROGBITS         00000000003a3000  001a3000
       0000000000000078  0000000000000008  WA       0     0     8

You can only recognise the GOT because of the section name (which could really be anything). The GOT entries are using SHT_PROGBITS (like many other bits of the ELF file) so you cannot use the section type to recognize them.

Moreover, the section header table is not neeeded at runtime and needs not be present in the ELF file.

Execution view

Can we use the execution view instead?

The execution view is given by the program header table. However, in the program header table, there is no real notion of (non-PLT) GOT. The runtime does not care where the GOT entries are located. They could just as well be scattered anywhere in the data segment*. All that matters is that the correct relocations are present in the (runtime) relocation table.

Using the dynamic section

The dynamic linker needs to be told where are the PLT GOT entries (.got.plt). This is given by the DT_PLTGOT entry of the dynamic section. However, it only gives the (runtime, virtual memory) location of the beginning of the GOT PLT table: you do not have the size of it.

Using the relocation table

You might try to inspect the relocation tables:

  • you should be able to infer the size of the PLT GOT by looking at the PLT relocations;

  • you might be able to infer the location and size of the non-PLT GOT by looking at the non-PLT relocations.

If I'm looking at the non PLT relocation table of libc (on x86_64), I get a bunch of R_X86_64_GLOB_DAT entries:

$ readelf -r $elf
[...]
0000003a2da0  052c00000006 R_X86_64_GLOB_DAT 00000000003a4708 stderr + 0
0000003a2da8  061400000006 R_X86_64_GLOB_DAT 00000000003a85d0 error_one_per_line + 0
0000003a2db0  06eb00000006 R_X86_64_GLOB_DAT 00000000003a57d0 __malloc_initialize_ho + 0
0000003a2db8  07f300000006 R_X86_64_GLOB_DAT 00000000003a4720 __morecore + 0
0000003a2dc8  02a400000006 R_X86_64_GLOB_DAT 00000000003a8998 __key_encryptsession_p + 0
0000003a2dd0  061000000006 R_X86_64_GLOB_DAT 00000000003a3ec8 __progname_full + 0
0000003a2dd8  049c00000006 R_X86_64_GLOB_DAT 00000000003a4010 __ctype32_tolower + 0
0000003a2de0  011900000006 R_X86_64_GLOB_DAT 00000000003a5fb8 _environ + 0
0000003a2de8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 _rtld_global + 0
0000003a2df0  011000000006 R_X86_64_GLOB_DAT 00000000003a3ec0 __progname + 0
0000003a2df8  04ff00000006 R_X86_64_GLOB_DAT 00000000003a32c4 argp_err_exit_status + 0
0000003a2e08  04ce00000006 R_X86_64_GLOB_DAT 00000000003a8538 mallwatch + 0
0000003a2e10  00bc00000006 R_X86_64_GLOB_DAT 00000000003a87d8 __rcmd_errstr + 0
0000003a2e18  056400000006 R_X86_64_GLOB_DAT 00000000003a48e0 __vdso_clock_gettime + 0
[...]

We nearly find the address of the non-PLT GOT:

$ readelf -S $elf
[...]
  [29] .got              PROGBITS         00000000003a2d80  001a2d80
       0000000000000278  0000000000000008  WA       0     0     8

There are 4 missing GOT entries (I don't know why…).

Note

(*): This means that there might not even be any (non-PLT) GOT.

like image 124
ysdx Avatar answered Jan 09 '23 23:01

ysdx