I'm studying the heap of glibc.
There's no main_arena symbol in libc.so, even if I try to dump it with pwntool. However, when I debug a test program, I can print the main_arena structure.
gdb-peda$ p main_arena
$1 = {
mutex = 0x0,
flags = 0x0,
fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
top = 0x0,
last_remainder = 0x0,
bins = {0x0 <repeats 254 times>},
binmap = {0x0, 0x0, 0x0, 0x0},
next = 0x7ffff7dd1b20 <main_arena>,
next_free = 0x0,
attached_threads = 0x1,
system_mem = 0x0,
max_system_mem = 0x0
}
And besides, when I compile test program with -m32, main_arena can't be found, too.
main_arena
is a local symbol and is specifically not exported. the list of exported symbols is controlled via the Version
files in the glibc source tree. this is, by design, to keep people from being able to link against random symbols that glibc uses internally (so as to not pollute the namespace as is required by POSIX and other standards).
gdb can find it because you have debug symbols available ... either the C lib is not stripped, or you have the split debug symbols in /usr/lib/debug/
and gdb is finding those. when you launch gdb, it will tell you things like Reading symbols from /usr/lib/debug/xxxxx
.
the only way to be able to link against the symbol is to rebuild glibc from source and modify the export list.
alternatively, you could write some code in your app to behave like gdb. namely, open the debug file, process the ELF/DWARF information in it, apply relocations using the active loaded library info (see dl_iterate_phdr
), and then just start poking memory directly.
if that's too much work, a hackery solution might be to fork()
+popen()
gdb against your own process and run it in batch mode to dump symbol info.
char *cmd;
FILE *fp;
asprintf(&cmd, "gdb -q -p %i -batch -ex 'p &main_arena'", getpid());
fp = popen(cmd, "r");
// parse the output of |fp| here looking for the address.
free(cmd);
fclose(fp);