【问题标题】:finer-grained control than with LD_PRELOAD?比 LD_PRELOAD 更细粒度的控制?
【发布时间】:2020-02-19 16:19:37
【问题描述】:

我在 Linux 上有一个动态链接的 ELF 可执行文件,我想交换它链接的库中的一个函数。当然,使用 LD_PRELOAD 我可以提供一个小型库来替代我自己编译的函数。但是,如果在替换中我想调用原始库函数怎么办?例如,函数可能是 srand(),我想用我自己的种子选择劫持它,否则让 srand() 做它通常做的事情。

如果我要链接以使所说的可执行文件,我会使用链接器的 wrap 选项,但这里我只有编译的二进制文件。

我看到的一个简单的解决方案是将原始库函数的源代码剪切并粘贴到替换中 - 但我想在源不可用时处理更一般的情况。或者,我可以将所需的额外代码十六进制编辑到二进制文件中,但这是特定于二进制文件的,而且也很耗时。有没有比这两个更优雅的东西?比如加载器的一些魔法?

(抱歉,如果我没有准确使用术语......)

【问题讨论】:

    标签: shared-libraries elf ld-preload


    【解决方案1】:

    以下是包装 malloc 的示例:

    // LD_PRELOAD will cause the process to call this instead of malloc(3)
    // report malloc(size) calls
    void *malloc(size_t size)
        {
        // on first call, get a function pointer for malloc(3)
        static void *(*real_malloc)(size_t) = NULL;
        static int malloc_signal = 0;
        if(!real_malloc)
            {
            // real_malloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc");
            *(void **) (&real_malloc) = dlsym(RTLD_NEXT, "malloc");
            }
        assert(real_malloc);
        if (malloc_signal == 0)
            {
            char *string = getenv("MW_MALLOC_SIGNAL");
            if (string != NULL)
                {
                malloc_signal = 1;
                }
            }
    
        // call malloc(3)
        void *retval = real_malloc(size);
        fprintf(stderr, "MW! %f malloc size %zu, address %p\n", get_seconds(), size, retval);
        if (malloc_signal == 1)
            {
            send_signal(SIGUSR1);
            }
        return retval;
        }
    

    【讨论】:

    • 感谢你们两位提供了很好的解决方案。顺便说一句,当我们这样做的时候......还有一种方法可以编辑二进制文件中的待解析符号吗?例如,如果在上面的示例中我可以将“srand”更改为“sran0”,那么与现有库发生冲突的可能性极小,然后我可以通过 LD_PRELOAD 提供我自己的 sran0(然后调用通常的 srand) .
    【解决方案2】:

    规范的答案是使用dlsym(RTLD_NEXT, ...)

    来自man page

    RTLD_NEXT
              Find the next occurrence of the desired symbol in the search
              order after the current object.  This allows one to provide a
              wrapper around a function in another shared object, so that,
              for example, the definition of a function in a preloaded
              shared object (see LD_PRELOAD in ld.so(8)) can find and invoke
              the "real" function provided in another shared object (or for
              that matter, the "next" definition of the function in cases
              where there are multiple layers of preloading).
    

    另见this article

    【讨论】:

      【解决方案3】:

      为了完整起见,关于在二进制文件中编辑函数名称 - 我检查过它可以工作,但并非没有潜在的问题。例如,在我提到的示例中,可以找到“srand”的偏移量(例如,通过 strings -t x exefile | grep srand)并将字符串十六进制编辑为“sran0”。但是符号的名称可能会重叠(以节省空间),因此如果代码也调用 rand(),那么二进制文件中只有一个“srand”字符串用于两者。更改后,未解析的引用将指向 sran0 和 ran0。当然,这不是一个炫耀,但要记住一些事情。 dlsym() 解决方案当然更灵活。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-03
        • 1970-01-01
        • 1970-01-01
        • 2021-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-18
        相关资源
        最近更新 更多