微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Ubuntu 和 CentOS 上通过 LD_PRELOAD 挂钩库函数时的行为差异

如何解决在 Ubuntu 和 CentOS 上通过 LD_PRELOAD 挂钩库函数时的行为差异

一个钩子函数socketHook.c可以拦截socket()调用

#include <stdio.h>
int socket(int domain,int type,int protocol)
{
    printf("socket() has been intercepted!\n");
    return 0;
}
gcc -c -fPIC socketHook.c
gcc -shared -o socketHook.so socketHook.o

还有一个简单的程序 getpwuid.c (1) 只调用 getpwuid() 函数

#include <pwd.h>

int main()
{
    getpwuid(0);
    return 0;
}
gcc getpwuid.c -o getpwuid

getpwuid() 在内部进行 socket() 调用。 在 CentOS 上:

$ strace -e trace=socket ./getpwuid
socket(AF_UNIX,SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,0) = 3
socket(AF_UNIX,SOCK_STREAM,0)         = 4

在 Ubuntu 上:

$ strace -e trace=socket ./getpwuid
socket(AF_UNIX,0) = 5
socket(AF_UNIX,0) = 5

运行(1)时,socket()在CentOS上被拦截,但在Ubuntu上没有。

CentOS. 来自 socketHook.cprintf() 存在:

$ uname -a
Linux centos-stream 4.18.0-301.1.el8.x86_64 #1 SMP Tue Apr 13 16:24:22 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

$ LD_PRELOAD=$(pwd)/socketHook.so ./getpwuid
socket() has been intercepted!

Ubuntu(Xubuntu 20.04)。 socketHook.c 中的 printf() 不存在:

$ uname -a
Linux ibse-VirtualBox 5.8.0-50-generic #56~20.04.1-Ubuntu SMP Mon Apr 12 21:46:35 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

$ LD_PRELOAD=$(pwd)/socketHook.so ./getpwuid
$

所以我的问题是:

  1. 它取决于什么?我认为这受到这样一个事实的影响:socket() 不是直接从可执行文件调用的,而是从 getpwuid() 调用的,如果我理解正确的话,它是从 libc.so 调用的立>
  2. 如何在 CentOS 中实现与在 Ubuntu 中相同的行为?我不想拦截来自 libc 的间接调用

解决方法

它取决于什么?

有两个问题要问:

  1. 哪个函数实际调用了 socket 系统调用?
  2. 该函数是如何被调用的。

您可以看到如何通过在 GDB 下运行您的程序并使用 socket 命令来调用 catch syscall socket 系统调用。在 Ubuntu 上:

(gdb) catch syscall socket    
Catchpoint 1 (syscall 'socket' [41])
(gdb) run 
Starting program: /tmp/a.out 

Catchpoint 1 (call to syscall socket),0x00007ffff7ed3477 in socket () at ../sysdeps/unix/syscall-template.S:120
120     ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt
#0  0x00007ffff7ed3477 in socket () at ../sysdeps/unix/syscall-template.S:120
#1  0x00007ffff7f08010 in open_socket (type=type@entry=GETFDPW,key=key@entry=0x7ffff7f612ca "passwd",keylen=keylen@entry=7) at nscd_helper.c:171
#2  0x00007ffff7f084fa in __nscd_get_mapping (type=type@entry=GETFDPW,mappedp=mappedp@entry=0x7ffff7f980c8 <map_handle+8>) at nscd_helper.c:269
#3  0x00007ffff7f0894f in __nscd_get_map_ref (type=type@entry=GETFDPW,name=name@entry=0x7ffff7f612ca "passwd",mapptr=mapptr@entry=0x7ffff7f980c0 <map_handle>,gc_cyclep=gc_cyclep@entry=0x7fffffffda0c) at nscd_helper.c:419
#4  0x00007ffff7f04fb7 in nscd_getpw_r (key=0x7fffffffdaa6 "0",keylen=2,type=type@entry=GETPWBYUID,resultbuf=resultbuf@entry=0x7ffff7f96520 <resbuf>,buffer=buffer@entry=0x5555555592a0 "",buflen=buflen@entry=1024,result=0x7fffffffdb60) at nscd_getpw_r.c:93
#5  0x00007ffff7f05412 in __nscd_getpwuid_r (uid=uid@entry=0,result=result@entry=0x7fffffffdb60) at nscd_getpw_r.c:62
#6  0x00007ffff7e9e95d in __getpwuid_r (uid=uid@entry=0,resbuf=resbuf@entry=0x7ffff7f96520 <resbuf>,buffer=0x5555555592a0 "",result=result@entry=0x7fffffffdb60) at ../nss/getXXbyYY_r.c:255
#7  0x00007ffff7e9dfd3 in getpwuid (uid=0) at ../nss/getXXbyYY.c:134
#8  0x0000555555555143 in main () at t.c:5

(gdb) info sym $pc
socket + 7 in section .text of /lib/x86_64-linux-gnu/libc.so.6
(gdb) up
#1  0x00007ffff7f08010 in open_socket (type=type@entry=GETFDPW,keylen=keylen@entry=7) at nscd_helper.c:171
171     nscd_helper.c: No such file or directory.
(gdb) x/i $pc-5
   0x7ffff7f0800b <open_socket+59>:     callq  0x7ffff7ed3470 <socket>

由此我们可以看出

  1. 函数 socket 被调用。使用 nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep ' socket' 我们可以确认该函数是从 libc.so.6 导出的,因此应该是可插入的。
  2. 调用方调用socket@plt(即不使用procedure linkage table),因此LD_PRELOAD将无效。

从 2004 年以来,从 open_socket()socket() 的调用一直是不可插入的,所以很可能 这个 调用也没有在 CentOS 上被拦截,但是一些other 电话是。可能是 strace 输出中的第三个。

使用上述方法,您应该能够判断那个调用来自哪里。


我不想拦截来自 libc 的间接调用

在这种情况下,LD_PRELOAD 可能是错误的使用机制。

如果您只想拦截来自您自己的代码的 socket() 调用,将它们重定向到例如mysocket() 不需要 LD_PRELOAD

您可以通过添加例如在源代码级别执行此操作

#define socket mysocket

到所有文件,或在编译时使用 -Dsocket=mysocket 参数。

或者,使用链接器 --wrap=socket 将无需重新编译即可进行重定向。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。