ld wrap 和 LD_PRELOAD 都无法拦截系统调用
Neither ld wrap nor LD_PRELOAD working to intercept system call
我正在尝试在我的最终 g++ link 命令中使用 -Wl
、-wrap=sendto
-Wl
、-wrap
、sendto
link我的应用程序用我自己的函数替换标准 sendto
函数。
我编译以下源代码:
gcc -c -o wrap.o wrap.c
并在 link 应用程序的最终 g++ 命令中包含 wrap.o(应用程序的其余部分是 C++,因此使用 g++):
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
ssize_t __real_sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
ssize_t __wrap_sendto
(
int sockfd,
const void *buf,
size_t len,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen
)
{
printf("my wrap sendto ...\n");
return __real_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
当我在我自己的源代码中使用 sendto
时,包装器实际上可以正常使用,但我 link 在我最终的 g++ 命令中反对的所有第 3 方共享对象仍然使用 sendto系统发送到即不是我的包装器。我怎样才能让我的 sendto 包装器在整个过程中被使用?
我也尝试过 LD_PRELOAD
方法,里面有 sendto 和 dlsym(RTLD_NEXT)
,但也没有用。
我如何弄清楚为什么第 3 方库继续直接使用 libc sendto?
当我使用 ldd 查找我编译的应用程序的所有共享对象依赖项,然后 objdump -T
对它们中的每一个进行 grepping 以获取 sendto 时,我得到所有第 3 方共享对象的 UND(未定义)。然而,定义它的共享对象是:
/lib64/libpthread.so.0
000000000000ed80 w DF .text 0000000000000064 GLIBC_2.2.5 sendto
/lib64/libc.so.6
00000000000e98d0 w DF .text 0000000000000064 GLIBC_2.2.5 sendto
我在 git
上的 glibc sendto.c
中看到以下内容:
weak_alias (__libc_sendto, sendto)
weak_alias (__libc_sendto, __sendto)
--wrap sendto
选项没有在您的二进制文件中定义 sendto
符号。相反,它用 __wrap_sendto
替换对此符号的引用,并使 sendto
未定义。
换句话说,您的可执行文件不提供 sendto
,因此 运行 时间符号解析从 glibc 中选择一个。
要解决此问题,您需要在可执行文件中定义 sendto
。再次尝试 dlsym
,但这次没有 LD_PRELOAD
/shim 库:
ssize_t sendto
(
int sockfd,
const void *buf,
size_t len,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen
)
{
ssize_t (*libc_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t)
= dlsym(RTLD_NEXT, "sendto");
printf("my wrap sendto ...\n");
return libc_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
如果第三方库在此之后一直发现错误sendto
,那么我认为只有一种(不太可能)的可能性。共享库与 -Bsymbolic
/-Bsymbolic-functions
链接并提供自己的 sendto
.
此外,由于您已将此问题标记为 g++
,请确保您的符号名称不会被破坏 - 使用 extern "C"
.
我终于设法弄清楚这里发生了什么。即使正在调用 strace 状态 sendto:
[pid 17956] sendto(4, "abc"..., 2052, 0, NULL, 0) = 2052
实际上发生的事情是调用了 send(...)(可能是因为 0、null、0 最后三个参数)。在我为 send(...) 创建拦截器的那一刻,它起作用了。
我正在尝试在我的最终 g++ link 命令中使用 -Wl
、-wrap=sendto
-Wl
、-wrap
、sendto
link我的应用程序用我自己的函数替换标准 sendto
函数。
我编译以下源代码:
gcc -c -o wrap.o wrap.c
并在 link 应用程序的最终 g++ 命令中包含 wrap.o(应用程序的其余部分是 C++,因此使用 g++):
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
ssize_t __real_sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
ssize_t __wrap_sendto
(
int sockfd,
const void *buf,
size_t len,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen
)
{
printf("my wrap sendto ...\n");
return __real_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
当我在我自己的源代码中使用 sendto
时,包装器实际上可以正常使用,但我 link 在我最终的 g++ 命令中反对的所有第 3 方共享对象仍然使用 sendto系统发送到即不是我的包装器。我怎样才能让我的 sendto 包装器在整个过程中被使用?
我也尝试过 LD_PRELOAD
方法,里面有 sendto 和 dlsym(RTLD_NEXT)
,但也没有用。
我如何弄清楚为什么第 3 方库继续直接使用 libc sendto?
当我使用 ldd 查找我编译的应用程序的所有共享对象依赖项,然后 objdump -T
对它们中的每一个进行 grepping 以获取 sendto 时,我得到所有第 3 方共享对象的 UND(未定义)。然而,定义它的共享对象是:
/lib64/libpthread.so.0
000000000000ed80 w DF .text 0000000000000064 GLIBC_2.2.5 sendto
/lib64/libc.so.6
00000000000e98d0 w DF .text 0000000000000064 GLIBC_2.2.5 sendto
我在 git
上的 glibc sendto.c
中看到以下内容:
weak_alias (__libc_sendto, sendto)
weak_alias (__libc_sendto, __sendto)
--wrap sendto
选项没有在您的二进制文件中定义 sendto
符号。相反,它用 __wrap_sendto
替换对此符号的引用,并使 sendto
未定义。
换句话说,您的可执行文件不提供 sendto
,因此 运行 时间符号解析从 glibc 中选择一个。
要解决此问题,您需要在可执行文件中定义 sendto
。再次尝试 dlsym
,但这次没有 LD_PRELOAD
/shim 库:
ssize_t sendto
(
int sockfd,
const void *buf,
size_t len,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen
)
{
ssize_t (*libc_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t)
= dlsym(RTLD_NEXT, "sendto");
printf("my wrap sendto ...\n");
return libc_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
如果第三方库在此之后一直发现错误sendto
,那么我认为只有一种(不太可能)的可能性。共享库与 -Bsymbolic
/-Bsymbolic-functions
链接并提供自己的 sendto
.
此外,由于您已将此问题标记为 g++
,请确保您的符号名称不会被破坏 - 使用 extern "C"
.
我终于设法弄清楚这里发生了什么。即使正在调用 strace 状态 sendto:
[pid 17956] sendto(4, "abc"..., 2052, 0, NULL, 0) = 2052
实际上发生的事情是调用了 send(...)(可能是因为 0、null、0 最后三个参数)。在我为 send(...) 创建拦截器的那一刻,它起作用了。