Is there any way to find the address of a global variable in libc that hasn't been linked into the executable (therefore not in the got/plt)? I'd like to access the __environ global variable in my shell code.
Web searches have so far only turned up an approach where you first find the offset in the shared library from an entity that is in the plt, and add the offset to the runtime value in the plt to get the runtime address of the desired variable in the shared library. Is there another way that would not depend on the version of the shared library?
Thanks.
Is there another way that would not depend on the version of the shared library?
No.
The address of __environ
can be trivially found via many ways other than "first find the offset in the shared library from an entity that is in the plt, and add the offset to the runtime value in the plt to get the runtime address of the desired variable", but that address will depend on the exact build of libc.so.6
, and will vary from version to version (and for the exact same GLIBC version) from distribution to distribution (e.g. different compilers will produce different result).
So what other methods of finding this address exist?
You need two things:
libc.so.6
, printed by nm
and readelf
:nm -D /usr/lib64/libc.so.6 | grep __environ
0000000000202d00 B __environ@@GLIBC_2.2.5
libc.so.6
itself in a given process, discoverable via e.g. /proc/$pid/maps
. grep libc.so.6 /proc/37/maps
7f34d2865000-7f34d2891000 r--p 00000000 08:10 67606 /usr/lib64/libc.so.6
7f34d2891000-7f34d2a07000 r-xp 0002c000 08:10 67606 /usr/lib64/libc.so.6
...
Above output tells me that __environ
should be at 0x7f34d2865000+0x0000000000202d00
in process 37
.
gdb -q -p 37
...
(gdb) p/a 0x7f34d2865000+0x0000000000202d00
$1 = 0x7f34d2a67d00 <environ>
(gdb) p &__environ
$2 = (char ***) 0x7f34d2a67d00 <environ>
QED.
P.S. There are other ways of discovering (1) -- you could read .dynsym
directly without using nm
, and (2) -- you could use dladdr()
within the target process.