【问题标题】:Function interposition in Linux without dlsym没有 dlsym 的 Linux 中的函数插入
【发布时间】:2009-06-15 21:22:02
【问题描述】:

我目前正在做一个项目,我需要跟踪几个系统调用和低级函数的使用情况,例如mmap、brk、sbrk。到目前为止,我一直在使用函数插入来执行此操作:我编写了一个与要替换的函数同名的包装函数(例如 mmap),然后通过设置 LD_PRELOAD 将其加载到程序中环境变量。我通过使用dlsym 加载的指针调用真正的函数。

不幸的是,我要包装的函数之一 sbrk 在内部由 dlsym 使用,因此当我尝试加载符号时程序崩溃。 sbrk在Linux中不是系统调用,所以不能简单地用syscall间接调用。

所以我的问题是,如何在不使用dlsym 的情况下从同名包装函数调用库函数?是否有任何编译器技巧(使用 gcc)可以让我引用原始函数?

【问题讨论】:

    标签: c linux function-interposition dlsym


    【解决方案1】:

    参见 ld 的选项--wrap symbol。从手册页:

    --wrap symbol 对符号使用包装函数。任何未定义的 对符号的引用将得到解决 到“__wrap_symbol”。任何未定义的 引用“__real_symbol”将 被解析为符号。

    这可以用来提供一个 系统函数的包装器。这 应该调用包装函数 “__wrap_symbol”。如果它想调用 系统函数,它应该调用 “__real_symbol”。

    这是一个简单的例子:

    void *
    __wrap_malloc (size_t c)
    {
        printf ("malloc called with %zu\n", c);
        return __real_malloc (c);
    }
    

    如果您将其他代码与此链接 使用 --wrap malloc 文件,然后全部 调用“malloc”将调用 改为函数“__wrap_malloc”。这 在
    中调用“__real_malloc” “__wrap_malloc”将调用真正的 “malloc”函数。

    您可能希望提供一个 "__real_malloc" 函数也是如此,所以 没有 --wrap 选项的链接 将会成功。如果你这样做,你 不应该把定义 “__real_malloc”在同一个文件中 "__wrap_malloc";如果你这样做, 汇编器可能会在之前解析调用 链接器有机会将其包装到 “malloc”。

    另一种选择可能是查看 ltrace 的来源,它或多或少做同样的事情:-P。

    这里有一个想法。您可以让您的 LD_PRELOAD'ed 库更改 PLT 条目以指向您的代码。从技术上讲,您仍然可以从您的代码中调用 sbrk() 函数。

    【讨论】:

    • 这很棒。我从未听说过 --wrap 选项,但这正是我所需要的。谢谢。
    • 澄清一下,在链接可执行文件或链接包含包装器的 LD_PRELOAD 库时是否需要传递 --wrap 标志?另外,您是否考虑提供有关修改可执行文件的 PLT 条目的更多信息?
    • 设计的用例是让你用 --wrap 链接 target 应用程序。也有可能使它适用于 LD_PRELOAD 情况,我不确定,我必须测试。
    【解决方案2】:

    您可以使用以下工具不显眼地检查函数调用:

    • gdb
    • ltrace
    • systemtap

    这些工具允许监控程序在调用函数时通知您,并允许您询问参数。

    主要区别在于:

    • gdb 是交互式的,但功能强大
    • ltrace 使用简单,但只能打印函数名
    • systemtap 不是交互式的,但速度非常快,而且功能强大。

    【讨论】:

      【解决方案3】:

      如果您使用 glibc 运行主机系统,那么 libc 有一些内部后端连接到我之前使用的运行时动态链接器。如果我没记错的话,我认为它被称为“__libc_dlsym”。 (要检查,“$ readelf -s /usr/lib/libc.a | grep dlsym”应该会有所帮助。)将其声明为具有与 dlsym 相同的参数和返回值的外部链接函数,并使用它来包装 dlsym 本身。

      【讨论】:

        【解决方案4】:

        truss 不能在您的系统上运行吗?它非常适合 Solaris 上的此类事情。

        【讨论】:

        • 这听起来很像 Linux 中的 strace。如果您只需要获取已拨打电话的列表,则此方法可以正常工作。在这个项目中,我需要为包装器添加一些功能,我认为插入是唯一的方法。
        猜你喜欢
        • 2022-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-17
        • 2017-06-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多