如何在 Linux 上挂接 send() / recv() 函数?
How to hook send() / recv() functions on Linux?
我正在尝试在 Linux.
上挂接 C++ 中的 recv()
和 send()
函数
我知道how to hook functions (github: zeek/subhook)。
但我想要一些帮助来学习如何找到 recv()
或 send()
函数的地址(在运行时,或使用 版本独立解决方案 )。
我乐于接受任何类型的文档或建议,以帮助我理解此处涉及的机制。
[编辑] 澄清: 我不想使用 LD_PRELOAD=
因为我用这个工具注入了我的共享库:linux-inject.
如果目标程序不是为注入设计的
一个地方是通过gdb注入。 It's not trivial,虽然。但你已经知道了。
至于在运行时查找地址,您应该查看how gdb does it。您可能会发现一些库封装了这种确切的行为。
如果你能设计出hooking的目标程序
有更简单的方法可以实现这一点,例如 LD_PRELOAD
技巧和其他共享库技巧,可能还有无数其他技巧。但是要获取 recv
和 send
的地址,您可以按照
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
printf("pid %d\n", getpid());
printf("Address of recv: %p\n", recv);
printf("Address of send: %p\n", send);
for (;;) {
sleep(1);
}
}
运行 它在我的系统上,
$ ./a.out
pid 21266
Address of recv: 0x7fff86abedf3
Address of send: 0x7fff86abee03
用 gdb 仔细检查,
$ gdb -p 21266
(gdb) p (void*)recv
= (void *) 0x7fff86abedf3 <recv>
参见 What is the LD_PRELOAD trick?。
基本上,您编写的方法与您要挂钩的方法具有相同的签名。在这种情况下 send
和 recv
。然后您设置 LD_PRELOAD 指向您的新图书馆。加载程序将首先找到您的函数并调用它。
在你的库中,你可以包装原始代码,完全替换它,修改输入或输出,基本上任何东西。
有关示例代码,请参阅此教程
dlsym and ld preload
发送的一个例子是:
ssize_t (*original_send)(int sockfd, const void *buf, size_t len, int flags);
original_send = dlsym(RTLD_NEXT, "send");
return (*original_send)( /args/ );
考虑使用 plthook library. Fortunately there is example how to hook recv on the main page. The library iterates over all load time relocations 并替换给定模块的所有目标函数。
函数地址就是存放函数指令的地方。如果你想通过指针替换轻松地在 Linux (ELF) 上挂钩某些东西,你将必须更改调用此函数的所有位置,而不是函数本身。
如果您只想更改 recv
/send
代码,请考虑 trampolining 函数。
我正在尝试在 Linux.
上挂接 C++ 中的recv()
和 send()
函数
我知道how to hook functions (github: zeek/subhook)。
但我想要一些帮助来学习如何找到 recv()
或 send()
函数的地址(在运行时,或使用 版本独立解决方案 )。
我乐于接受任何类型的文档或建议,以帮助我理解此处涉及的机制。
[编辑] 澄清: 我不想使用 LD_PRELOAD=
因为我用这个工具注入了我的共享库:linux-inject.
如果目标程序不是为注入设计的
一个地方是通过gdb注入。 It's not trivial,虽然。但你已经知道了。
至于在运行时查找地址,您应该查看how gdb does it。您可能会发现一些库封装了这种确切的行为。
如果你能设计出hooking的目标程序
有更简单的方法可以实现这一点,例如 LD_PRELOAD
技巧和其他共享库技巧,可能还有无数其他技巧。但是要获取 recv
和 send
的地址,您可以按照
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
printf("pid %d\n", getpid());
printf("Address of recv: %p\n", recv);
printf("Address of send: %p\n", send);
for (;;) {
sleep(1);
}
}
运行 它在我的系统上,
$ ./a.out
pid 21266
Address of recv: 0x7fff86abedf3
Address of send: 0x7fff86abee03
用 gdb 仔细检查,
$ gdb -p 21266
(gdb) p (void*)recv
= (void *) 0x7fff86abedf3 <recv>
参见 What is the LD_PRELOAD trick?。
基本上,您编写的方法与您要挂钩的方法具有相同的签名。在这种情况下 send
和 recv
。然后您设置 LD_PRELOAD 指向您的新图书馆。加载程序将首先找到您的函数并调用它。
在你的库中,你可以包装原始代码,完全替换它,修改输入或输出,基本上任何东西。
有关示例代码,请参阅此教程 dlsym and ld preload
发送的一个例子是:
ssize_t (*original_send)(int sockfd, const void *buf, size_t len, int flags);
original_send = dlsym(RTLD_NEXT, "send");
return (*original_send)( /args/ );
考虑使用 plthook library. Fortunately there is example how to hook recv on the main page. The library iterates over all load time relocations 并替换给定模块的所有目标函数。
函数地址就是存放函数指令的地方。如果你想通过指针替换轻松地在 Linux (ELF) 上挂钩某些东西,你将必须更改调用此函数的所有位置,而不是函数本身。
如果您只想更改 recv
/send
代码,请考虑 trampolining 函数。