gpt4 book ai didi

linux - 在 Ubuntu 和 CentOS 上通过 LD_PRELOAD Hook 库函数时的行为差异

转载 作者:行者123 更新时间:2023-12-04 18:39:01 24 4
gpt4 key购买 nike

有一个钩子(Hook)函数 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|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
socket(AF_UNIX, SOCK_STREAM, 0) = 4
在 Ubuntu 上:
$ strace -e trace=socket ./getpwuid
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
运行 (1) 时,socket() 在 CentOS 上被拦截,但在 Ubuntu 上不被拦截。
中央操作系统。 来自 socketHook.c 的 printf() 存在:
$ 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
$
所以我的问题是:
  • 它取决于什么?我认为这受到以下事实的影响:socket() 不是直接从可执行文件调用,而是从 getpwuid() 调用,如果我理解正确,它又从 libc.so
  • 调用。
  • 如何在 CentOS 中实现与 Ubuntu 中相同的行为?我不想拦截来自 libc
  • 的间接调用

    最佳答案

    What does it depend on?


    有两个问题要问:
  • 哪个函数实际调用 socket系统调用?
  • 该函数是如何被调用的。

  • 你可以看看 socket通过在 GDB 下运行程序并使用 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, key=key@entry=0x7ffff7f612ca "passwd", 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, resultbuf=resultbuf@entry=0x7ffff7f96520 <resbuf>, buffer=buffer@entry=0x5555555592a0 "", buflen=buflen@entry=1024,
    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 "", buflen=buflen@entry=1024,
    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, key=key@entry=0x7ffff7f612ca "passwd", 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>
    由此我们可以看出
  • 函数socket叫做。使用 nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep ' socket'我们可以确认该函数是从 libc.so.6 导出的。 ,因此应该是可插入的。
  • 来电者未调用socket@plt (即不使用 procedure linkage table ),所以 LD_PRELOAD不会有任何影响。

  • 来自 open_socket()的电话至 socket()自 2004 年以来一直是不可插入的,所以这个调用很可能在 CentOS 上也没有被拦截,但其他一些调用被拦截了。可能是您的 strace 中的第三个输出。
    使用上述方法,您应该能够知道该调用来自何处。

    I don't want intercept indirect calls from libc


    在这种情况下, LD_PRELOAD可能是使用错误的机制。
    如果只想截取 socket()从您自己的代码调用,将它们重定向到例如 mysocket()无需 LD_PRELOAD .
    您可以通过添加例如在源代码级别执行此操作
    #define socket mysocket
    到您的所有文件,或使用 -Dsocket=mysocket编译时的参数。
    或者,使用链接器 --wrap=socket将在不重新编译的情况下进行重定向。

    关于linux - 在 Ubuntu 和 CentOS 上通过 LD_PRELOAD Hook 库函数时的行为差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67398366/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com