枚举通过dlopen加载的共享库(RTLD_GLOBAL)

时间:2017-10-11 13:21:31

标签: linux shared-libraries glibc dlopen

有没有办法在运行时确定哪些共享库已加载到当前进程的全局符号命名空间中?我主要对因使用translate(0,y)标记的dlopen()调用而加载的任何内容感兴趣。

我希望这样做是为了审计目的 - 对于我处理动态加载的共享库的应用程序而言,这一点非常重要RTLD_GLOBAL' s {{ 1}}尽可能不与第三方代码冲突;任何加载到全局符号命名空间的内容都需要严格控制。

我查看了dl_iterate_phdr() API,但它似乎并未包含此信息。

2 个答案:

答案 0 :(得分:1)

您可以尝试使用

#define _GNU_SOURCE
#include <dlfcn.h>

typedef void *(*orig_dl)(const char *file, int mode);
void *dlopen(const char *file, int mode)
{
    orig_dl o_dlopen;
    o_dlopen = (orig_dl)dlsym(RTLD_NEXT, "dlopen");
    return o_dlopen(file, mode);
}

使用gcc -shared -fPIC dlo.c -o dlo.so -ldl进行编译 添加LD_PRELOAD=dlo.so,然后就可以了。您可以使用特定模式记录/跟踪/打印任何dlopen用法

答案 1 :(得分:0)

我认为使用dlopen()替换LD_PRELOAD的建议只是部分解决方案 - 您不会捕获加载了dlopen()的库的依赖项那样。

最后,在没有抓取动态链接器本身的内部状态的情况下,我无法看到任何方法。它发现从_rtld_global导出的ld.so符号包含信息,但您必须使用私有Glibc标头来解释它。

以下是一个Python片段(假设我对Glibc源的读取是正确的)将按照它们将被搜索的顺序打印全局命名空间中的所有共享库。加载RTLD_LOCAL的库将不会被打印。

它依赖于Glibc的实现细节这一事实意味着这种方法充满了危险,但对于我的测试/审计目的,我认为它会做得很好。

import ctypes

# Abridged type declarations pillaged from Glibc. See:
# - https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/generic/ldsodefs.h
# - https://sourceware.org/git/?p=glibc.git;a=blob;f=include/link.h

class link_map(ctypes.Structure):
    _fields_ = [
        ("l_addr", ctypes.c_size_t),
        ("l_name", ctypes.c_char_p),
    ]


class r_scope_elem(ctypes.Structure):
    _fields_ = [
        ("r_list", ctypes.POINTER(ctypes.POINTER(link_map))),
        ("r_nlist", ctypes.c_uint),
    ]


class rtld_global(ctypes.Structure):
    _fields_ = [
        ("_ns_loaded", ctypes.POINTER(link_map)),
        ("_ns_nloaded", ctypes.c_uint),
        ("_ns_main_searchlist", ctypes.POINTER(r_scope_elem)),
    ]

_rtld_global = rtld_global.in_dll(ctypes.CDLL(None), "_rtld_global")
searchlist = _rtld_global._ns_main_searchlist[0]

print [searchlist.r_list[n][0].l_name for n in xrange(searchlist.r_nlist)]

在我的CentOS 7系统上,打印:

['', '/lib64/libpython2.7.so.1.0', '/lib64/libpthread.so.0', '/lib64/libdl.so.2',
 '/lib64/libutil.so.1', '/lib64/libm.so.6', '/lib64/libc.so.6',
 '/lib64/ld-linux-x86-64.so.2']