【问题标题】:Not able to use function from my dynamic library loaded via LD_PRELOAD无法使用通过 LD_PRELOAD 加载的动态库中的函数
【发布时间】:2022-01-24 05:52:18
【问题描述】:

我正在尝试使用 preload.so 中的sscanf(),它是从 preload.c 生成的。

为了检查我的sscanf() from preload.so 是否被调用,我添加了额外的打印语句:printf("test\n");

我有什么遗漏吗?

文件内容如下:

//preload.c
#include <stdarg.h>
#include <stdio.h>
__attribute__((force_align_arg_pointer)) int sscanf(const char *str, const char *format, ...)
{
  int ret;
  va_list ap;
  va_start(ap, format);
  printf("test\n");
  ret = vsscanf(str, format, ap);
  va_end(ap);
  return ret;
}
//foo.c
#include <stdio.h>

int main(void)
{
        int i;
        sscanf("42", "%d", &i);
        printf("%d\n", i);
        return 0;
}

我正在执行以下步骤:

# gcc -fPIC -shared preload.c -o preload.so -ldl -D_GNU_SOURCE=1
# export LD_PRELOAD=$PWD/preload.so
# gcc foo.c -o foo
test
test
test
test
test
test
test
test
test
test
test

O/p 我得到了:

# echo $LD_PRELOAD
/AMIT/sscanf_override/preload.so
# ./foo
42
# LD_PRELOAD=$PWD/preload.so ./foo
42

预期的输出是:

$ gcc foo.c -o foo
$ LD_PRELOAD=$PWD/preload.so ./foo
test
42

即使 ldd 输出指向 preload.so,如下所示,仍然在执行时优先考虑系统的 sscanf() 而不是 preload.so

root@***sscanf_override]# ldd foo
        linux-vdso.so.1 (0x00007fff4a5e0000)
        /AMIT/sscanf_override/preload.so (0x00007f1cf270a000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f1cf2345000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f1cf2141000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1cf290c000)
[root@***sscanf_override]#

这里的调整是,如果我删除 -D_GNU_SOURCE=1,它会起作用,gcc -fPIC -shared preload.c -o preload.so -ldl 但是如果不将 GNU_SOURCE 定义为将来使用的必要条件,我就无法继续。

正如@Rachid K 所建议的那样,当我重新定义我的 preload.c 时它起作用了:

#include <stdarg.h>
#include <stdio.h>
__attribute__((force_align_arg_pointer)) int sscanf(const char *str, const char *format, ...)
{
  int ret;
  va_list ap;
  va_start(ap, format);
  printf("test\n");
  ret = vsscanf(str, format, ap);
  va_end(ap);
  return ret;
}

__attribute__((force_align_arg_pointer)) int __isoc99_sscanf(const char *str, const char *format, ...)
{
  int ret;
  va_list ap;
  va_start(ap, format);
  printf("test\n");
  ret = vsscanf(str, format, ap);
  va_end(ap);
  return ret;
}

【问题讨论】:

    标签: c linux dynamic-library ld-preload


    【解决方案1】:

    看看readelf -s foo

    我认为您的可执行文件中可能没有对sscanf 的调用。假设您使用 GLIBC 作为 libc,我怀疑是调用 __isoc99_sscanf。这是库所做的重定向,显然是因为其原始 sscanf 变体使用与标准冲突的扩展,请参阅 this question

    如果您也查看readelf -s preload.so,它可能会显示sscanf 的定义。

    重定向是通过stdio.h 中的宏发生的,您在两者中都包含该宏,但我怀疑_GNU_SOURCE=1 会禁用重定向,因此即使stdio.h 包含在preload.c 中,它也不会将sscanf 替换为__isoc99_sscanf 那里。

    foo 的编译中,您可能不使用-D_GNU_SOURCE=1,因此您会得到符号名称之间的不匹配。

    LD_PRELOAD 的符号插入总是有点棘手。除了上述问题之外,还有很多情况下编译器会优化或转换标准库调用。例如printf -> puts 如果格式字符串不使用任何格式。

    【讨论】:

    • 这里的调整是,如果我删除 -D_GNU_SOURCE=1,它会起作用,gcc -fPIC -shared preload.c -o preload.so -ldl 但是如果不将 GNU_SOURCE 定义为必须的,我就无法继续.
    • @AmitMendhe 我认为-D_GNU_SOURCE=1 切换回带有扩展的原始sscanf 实现。如果您在编译可执行文件和 preload.so 之间不匹配该标志,您可能只会看到问题,因为重定向是通过 stdio.h 中的宏发生的,您在两者中都包含该宏。
    • 谢谢@user17732522。 : 对我的帖子有任何建议this
    【解决方案2】:

    sscanf() 可能是引用内部函数的宏。看看 。例如,在我的系统上,我有:

    extern int __isoc99_sscanf (const char *__restrict __s,
                                const char *__restrict __format, ...) __THROW;
    #  define fscanf __isoc99_fscanf
    #  define scanf __isoc99_scanf
    #  define sscanf __isoc99_sscanf
    

    因此,sscanf() 实际上是一个引用__isoc99_sscanf() 的宏。所以,如果你重新定义后者,你会得到你所期望的。

    #include <stdarg.h>
    #include <stdio.h>
    
    //__attribute__((force_align_arg_pointer)) int sscanf(const char *str, const char *format, ...)
    int __isoc99_sscanf(const char *str, const char *format, ...)
    {
      int ret;
      va_list ap;
      va_start(ap, format);
      printf("test\n");
      ret = vsscanf(str, format, ap);
      va_end(ap);
      return ret;
    }
    

    重建后,你会得到:

    $ gcc -fPIC -shared preload.c -o preload.so -ldl -D_GNU_SOURCE=1
    $ LD_PRELOAD=`pwd`/preload.so ./foo
    test
    42
    

    【讨论】:

    • K,让我试试这个,但这里的调整是,如果我删除 -D_GNU_SOURCE=1,它会起作用,gcc -fPIC -shared preload.c -o preload.so -ldl 但我不能继续前进,不要将 GNU_SOURCE 定义为必须
    • Rachid K:很好用。我根据您的建议使用我尝试过的解决方案编辑了我的问题。
    • K : 对我的帖子有任何建议this
    猜你喜欢
    • 2012-03-02
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 2021-08-11
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    相关资源
    最近更新 更多