c - 无法使用通过 LD_PRELOAD 加载的动态库中的函数

标签 c linux dynamic-library ld-preload

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

为了检查 preload.so 中的 sscanf() 是否被调用,我添加了额外的打印语句: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;
}

最佳答案

看看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 中,它不会用 __isoc99_sscanf 替换其中的 sscanf

在编译 foo 时,您可能没有使用 -D_GNU_SOURCE=1,因此符号名称之间不匹配。

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

关于c - 无法使用通过 LD_PRELOAD 加载的动态库中的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70458653/

相关文章:

c - 如何计算 C 中的大 nPr?

c - C中的recv()是否可能存在缓冲区溢出?

linux - pthread 互斥体解锁如何工作?线程是否同时出现?

c++ - 共享库的生命周期?

c - 函数指针和函数地址

从 C 调用汇编代码在多次调用后删除地址

linux - 将值从一个 shell 脚本传递到另一个 shell 脚本

python - ssh 命令需要交互式输入

c++ - 列出在 Linux 上使用 C/C++ 执行的程序中的共享库

带有框架的 iOS 应用程序在设备上崩溃,dyld : Library not loaded, Xcode 6 Beta