【问题标题】:Determine which shared lib calls into my shared确定哪些共享库调用了我的共享库
【发布时间】:2010-10-14 16:03:26
【问题描述】:

我试图找到一种方法来了解哪个共享库正在调用我的共享库函数。场景是这样的。

我已经使用 LD_PRELOAD 来覆盖 malloc。在我的 malloc 中,我将调用直接转发到真正的 malloc,但如果调用来自特定的共享库,我想在转发调用之前进行一些处理。

现在,我要处理的对 malloc 的调用的共享库由一种插件架构中的外部可执行文件加载和调用。我可以通过检查全局 program_invocation_short_name 变量来判断哪个可执行文件调用了我的 malloc,但我不想处理来自提供插件架构的可执行文件的 malloc 调用,而只处理来自插件共享库的调用。

我尝试使用 backtrace() 和 backtrace_symbols() 来查看是否可以从回溯中获取插件库名称或其中的一部分,但没有运气。我从来没有在那里得到名字。

有人可以建议如何做到这一点吗?

问候,

亚历克斯。

编辑:我忘了提。这是在 Linux 上。我的错,我以为 LD_PRELOAD 泄露了它。

【问题讨论】:

    标签: c shared-libraries


    【解决方案1】:

    没有简单的方法可以做到这一点,但这种方法可能会满足您的需求。

    我编写了 3 个小型应用程序,因此您可以按照我的说明进行操作。它们是:

    • app:将在您的系统上运行的二进制文件。从 libmiddleman.so 调用一个函数,尝试通过 malloc() 分配一些内存

    源代码:gcc app.c -o app -L. -lmiddle_man

    //File: app.c
    #include "libmiddle_man.h"    
    #include <stdio.h>
    
    int main()
    {
        do_something();
    
        return 0;
    }
    
    • libmiddle_man.so:导出一个简单调用 malloc() 的函数

    源代码:gcc libmiddle_man.c -o libmiddle_man.so -shared

    //File: libmiddle_man.c
    void do_something()
    {
        int* tmp = malloc(sizeof(int));
    }
    

    还有:

    //File: libmiddle_man.h
    void do_something();
    
    • libfake_malloc.so:实现并导出我们的 malloc() 版本,在终端上打印一些东西

    源代码:gcc lbfake_malloc.c -o libfake_malloc.so -shared

    //File: libfake_malloc.c
    #include <stdio.h>
    #include <unistd.h>
    
    void* malloc(size_t size)
    {
        printf("fake malloc()\n");
    
        printf("Process ID: %d\n", getpid());
    
        while(1)
        {
        }
    
        return NULL;
    }
    

    当您使用LD_PRELOAD=libfake_malloc.so ./app 执行应用程序时,它将输出以下内容:

    fake malloc()
    Process ID: 14230    (the PID will be different each time you run the application)
    

    并且应用程序将挂在那里,因为我们需要它。我们将检查进程内存映射并确保 app 都加载了我们的两个库。

    所以暂时把它放在那里,然后打开另一个终端。当您在进程列表中搜索此 PID 时,它将显示哪个应用程序正在使用 libfake_malloc.so。这不是我们的目标,但这是一个有趣的信息。

    ps -aux | grep 14230
    

    输出:

    karl     14230 97.3  0.0   1648   396 pts/9    R+   13:57  10:20 ./app
    

    请记住将 14230 更改为应用程序返回给您的任何号码。接下来,我们将检查进程内存并验证两个 out 库都已加载。

    cat /proc/14230/maps
    

    显示:

    00110000-00263000 r-xp 00000000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
    00263000-00264000 ---p 00153000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
    00264000-00266000 r--p 00153000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
    00266000-00267000 rw-p 00155000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
    00267000-0026a000 rw-p 00000000 00:00 0 
    00584000-00585000 r-xp 00000000 08:07 2921104    /home/karl/workspace/shared_libs/who_called_my_shared/libmiddle_man.so
    00585000-00586000 r--p 00000000 08:07 2921104    /home/karl/workspace/shared_libs/who_called_my_shared/libmiddle_man.so
    00586000-00587000 rw-p 00001000 08:07 2921104    /home/karl/workspace/shared_libs/who_called_my_shared/libmiddle_man.so
    00605000-00606000 r-xp 00000000 08:07 2921103    /home/karl/workspace/shared_libs/who_called_my_shared/libfake_malloc.so
    00606000-00607000 r--p 00000000 08:07 2921103    /home/karl/workspace/shared_libs/who_called_my_shared/libfake_malloc.so
    00607000-00608000 rw-p 00001000 08:07 2921103    /home/karl/workspace/shared_libs/who_called_my_shared/libfake_malloc.so
    007e6000-007e7000 r-xp 00000000 00:00 0          [vdso]
    0096a000-00985000 r-xp 00000000 08:06 2142529    /lib/ld-2.11.1.so
    00985000-00986000 r--p 0001a000 08:06 2142529    /lib/ld-2.11.1.so
    00986000-00987000 rw-p 0001b000 08:06 2142529    /lib/ld-2.11.1.so
    08048000-08049000 r-xp 00000000 08:07 2921106    /home/karl/workspace/shared_libs/who_called_my_shared/app
    08049000-0804a000 r--p 00000000 08:07 2921106    /home/karl/workspace/shared_libs/who_called_my_shared/app
    0804a000-0804b000 rw-p 00001000 08:07 2921106    /home/karl/workspace/shared_libs/who_called_my_shared/app
    b77b0000-b77b2000 rw-p 00000000 00:00 0 
    b77c9000-b77cc000 rw-p 00000000 00:00 0 
    bfb69000-bfb7e000 rw-p 00000000 00:00 0          [stack]
    

    你会注意到 libfake_malloc.so 的 inode 是 2921103 而加载它的库(即 libmiddle_man.so)的 inode 实际上是 2921103+1,即 2921104。

    我有机会在几台机器和一些也运行 Linux 的嵌入式设备上对此进行了测试。总而言之,通过解析 /proc/pid/maps 上的可用信息,似乎可以发现哪个库加载了您的库。

    【讨论】:

      【解决方案2】:

      在 Windows 上,您可以使用 CreateToolhelp32Snapshot()、Module32First() 等特殊 API 来获取进程中加载​​的所有共享库的列表。

      每个这样的库都将驻留在内存范围内,由结构 MODULEENTRY32 的 modBaseAddr 和 modBaseSize 成员指定。

      通过检查调用者的返回地址(可以通过一些简单的内联汇编来完成),您可以将其与可以准确识别调用者的范围进行比较。

      【讨论】:

      • 我希望在 linux 上使用相同的方法,但到目前为止找不到等效的系统调用。有什么想法吗?
      猜你喜欢
      • 1970-01-01
      • 2015-09-30
      • 2011-08-27
      • 1970-01-01
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多