我正在尝试使用 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/