为什么libc.so符号table中没有main_arena,而glibc2.23的malloc.c中有?

Why there isn't main_arena in libc.so symbol table, while there is one in malloc.c of glibc2.23?

正在研究glibc的heap

libc.so 中没有 main_arena 符号,即使我尝试使用 pwntool 转储它。但是,当我调试测试程序时,我可以打印 main_arena 结构。

gdb-peda$ p main_arena
 = {
    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
}

另外,我用-m32编译测试程序时,也找不到main_arena

libc.so.6 被剥离。 它的调试版本不是。 这就是 readelf 不显示 main_arena.

的原因

我仍然想知道 gdb 是如何知道符号名称的,即使在库被剥离时也是如此。

main_arena 是本地符号,具体 不导出 。导出符号列表通过 glibc 源代码树中的 Version 文件控制。这是为了防止人们 link 反对 glibc 内部使用的随机符号(以免污染 POSIX 和其他标准所要求的命名空间)。

gdb 可以找到它,因为您有可用的调试符号……C lib 没有被剥离,或者您在 /usr/lib/debug/ 中有拆分调试符号,gdb 正在找到它们。当你启动 gdb 时,它会告诉你类似 Reading symbols from /usr/lib/debug/xxxxx.

的信息

能够 link 反对该符号的唯一方法是从源代码重建 glibc 并修改导出列表。

或者,您可以在您的应用程序中编写一些代码,使其表现得像 gdb。即,打开调试文件,处理其中的 ELF/DWARF 信息,使用活动加载的库信息应用重定位(参见 dl_iterate_phdr),然后直接开始戳内存。

如果工作量太大,一个 hackery 解决方案可能是 fork()+popen() gdb 针对您自己的进程,然后 运行 它以批处理模式转储符号信息。

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);