Search code examples
linuxreverse-engineeringglibcdynamic-linking

Loaded glibc base address different for each function


I'm trying to calculate the base address of the library of a binary file. I have the address of printf, puts ecc and then I subtract it's offset to get the base address of the library. I was doing this for printf, puts and signal, but every time I got a different base address. I also tried to do the things in this post, but I couldn't get the right result either.

ASLR is disabled.

this is where I take the address of the library function:

gdb-peda$ x/20wx 0x804b018
0x804b018 <signal@got.plt>:     0xf7e05720      0xf7e97010      0x080484e6      0x080484f6
0x804b028 <puts@got.plt>:       0xf7e3fb40      0x08048516      0x08048526      0xf7df0d90
0x804b038 <memset@got.plt>:     0xf7f18730      0x08048556      0x08048566      0x00000000

then I have:

gdb-peda$ info proc mapping
process 114562
Mapped address spaces:

        Start Addr   End Addr       Size     Offset objfile
         0x8048000  0x804a000     0x2000        0x0 /home/ofey/CTF/Pwnable.tw/applestore/applestore
         0x804a000  0x804b000     0x1000     0x1000 /home/ofey/CTF/Pwnable.tw/applestore/applestore
         0x804b000  0x804c000     0x1000     0x2000 /home/ofey/CTF/Pwnable.tw/applestore/applestore
         0x804c000  0x806e000    0x22000        0x0 [heap]
        0xf7dd8000 0xf7fad000   0x1d5000        0x0 /lib/i386-linux-gnu/libc-2.27.so
        0xf7fad000 0xf7fae000     0x1000   0x1d5000 /lib/i386-linux-gnu/libc-2.27.so
        0xf7fae000 0xf7fb0000     0x2000   0x1d5000 /lib/i386-linux-gnu/libc-2.27.so
        0xf7fb0000 0xf7fb1000     0x1000   0x1d7000 /lib/i386-linux-gnu/libc-2.27.so
        0xf7fb1000 0xf7fb4000     0x3000        0x0
        0xf7fd0000 0xf7fd2000     0x2000        0x0
        0xf7fd2000 0xf7fd5000     0x3000        0x0 [vvar]
        0xf7fd5000 0xf7fd6000     0x1000        0x0 [vdso]
        0xf7fd6000 0xf7ffc000    0x26000        0x0 /lib/i386-linux-gnu/ld-2.27.so
        0xf7ffc000 0xf7ffd000     0x1000    0x25000 /lib/i386-linux-gnu/ld-2.27.so
        0xf7ffd000 0xf7ffe000     0x1000    0x26000 /lib/i386-linux-gnu/ld-2.27.so
        0xfffdd000 0xffffe000    0x21000        0x0 [stack]

and :

gdb-peda$ info sharedlibrary
From        To          Syms Read   Shared Object Library
0xf7fd6ab0  0xf7ff17fb  Yes         /lib/ld-linux.so.2
0xf7df0610  0xf7f3d386  Yes         /lib/i386-linux-gnu/libc.so.6

I then found the offset of signal and puts to calculate the base libc address.

base_with_signal_offset = 0xf7e05720 - 0x3eda0 =  0xf7dc6980
base_with_puts_offset = 0xf7e3fb40 - 0x809c0 = 0xf7dbf180

I was expecting base_with_signal_offset = base_with_puts_offset = 0xf7dd8000, but that's not the case. What I'm doing wrong? EDIT(To let you understand where I got those offset):

readelf -s /lib/x86_64-linux-gnu/libc-2.27.so  | grep puts

I get :

    191: 00000000000809c0   512 FUNC    GLOBAL DEFAULT   13 _IO_puts@@GLIBC_2.2.5
   422: 00000000000809c0   512 FUNC    WEAK   DEFAULT   13 puts@@GLIBC_2.2.5
   496: 00000000001266c0  1240 FUNC    GLOBAL DEFAULT   13 putspent@@GLIBC_2.2.5
   678: 00000000001285d0   750 FUNC    GLOBAL DEFAULT   13 putsgent@@GLIBC_2.10
  1141: 000000000007f1f0   396 FUNC    WEAK   DEFAULT   13 fputs@@GLIBC_2.2.5
  1677: 000000000007f1f0   396 FUNC    GLOBAL DEFAULT   13 _IO_fputs@@GLIBC_2.2.5
  2310: 000000000008a640   143 FUNC    WEAK   DEFAULT   13 fputs_unlocked@@GLIBC_2.2.5

Solution

  • I was expecting base_with_signal_offset = base_with_puts_offset = 0xf7dd8000

    There are 3 numbers in your calculation:

    &puts_at_runtime - symbol_value_from_readelf == &first_executable_pt_load_segment_libc.
    

    The readelf output shows that you got one of these almost correct: the value of puts in 64-bit /lib/x86_64-linux-gnu/libc-2.27.so is indeed 0x809c0, but that is not the library you are actually using. You need to repeat the same on the actually used 32-bit library: /lib/i386-linux-gnu/libc-2.27.so.

    For the first number -- &puts_at_runtime, you are using value from the puts@got.plt import stub. That value is only guaranteed to have been resolved (point to actual puts in libc.so) IFF you have LD_BIND_NOW=1 set in the environment, or you linked your executable with -z now linker flag, or you actually called puts already.

    It may be better to print &puts in GDB.

    The last number -- &first_executable_pt_load_segment_libc is correct (because info shared shows that libc.so.6 .text section starts at 0xf7df0610, which is between 0xf7dd8000 and 0xf7fad000.

    So putting it all together, the only error was that you used the wrong version of libc.so to extract the symbol_value_from_readelf.

    On my system:

    #include <signal.h>
    #include <stdio.h>
    int main() {
      puts("Hello");
      signal(SIGINT, SIG_IGN);
      return 0;
    }
    
    gcc -m32 t.c  -fno-pie -no-pie
    
    gdb -q a.out
    ... set breakpoint on exit from main
    Breakpoint 1, 0x080491ae in main ()
    (gdb) p &puts
    $1 = (<text variable, no debug info> *) 0xf7e31300 <puts>
    (gdb) p &signal
    $2 = (<text variable, no debug info> *) 0xf7df7d20 <ssignal>
    (gdb) info proc map
    process 114065
    Mapped address spaces:
    
        Start Addr   End Addr       Size     Offset objfile
         0x8048000  0x8049000     0x1000        0x0 /tmp/a.out
         ...
         0x804d000  0x806f000    0x22000        0x0 [heap]
        0xf7dc5000 0xf7de2000    0x1d000        0x0 /lib/i386-linux-gnu/libc-2.29.so
        ...
    (gdb) info shared
    From        To          Syms Read   Shared Object Library
    0xf7fd5090  0xf7ff0553  Yes (*)     /lib/ld-linux.so.2
    0xf7de20e0  0xf7f2b8d6  Yes (*)     /lib/i386-linux-gnu/libc.so.6
    

    Given above, we expect readelf -s to give us 0xf7e31300 - 0xf7dc5000 == 0x6c300 for puts and 0xf7df7d20 - 0xf7dc5000 == 0x32d20 for signal respectively.

    readelf -Ws /lib/i386-linux-gnu/libc-2.29.so | egrep ' (puts|signal)\W'
       452: 00032d20    68 FUNC    WEAK   DEFAULT   14 signal@@GLIBC_2.0
       458: 0006c300   400 FUNC    WEAK   DEFAULT   14 puts@@GLIBC_2.0
    

    QED.