除了LD_PRELOAD技巧,以及用你提供的系统调用取代某个系统调用的Linux内核模块,是否有可能拦截一个系统调用(例如打开),以便它首先通过你的函数,然后到达实际开放?
答案 0 :(得分:17)
为什么不能/不想使用LD_PRELOAD trick?
此处的示例代码:
/*
* File: soft_atimes.c
* Author: D.J. Capelis
*
* Compile:
* gcc -fPIC -c -o soft_atimes.o soft_atimes.c
* gcc -shared -o soft_atimes.so soft_atimes.o -ldl
*
* Use:
* LD_PRELOAD="./soft_atimes.so" command
*
* Copyright 2007 Regents of the University of California
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <bits/fcntl.h>
extern int errorno;
int (*_open)(const char * pathname, int flags, ...);
int (*_open64)(const char * pathname, int flags, ...);
int open(const char * pathname, int flags, mode_t mode)
{
_open = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open");
if(flags & O_CREAT)
return _open(pathname, flags | O_NOATIME, mode);
else
return _open(pathname, flags | O_NOATIME, 0);
}
int open64(const char * pathname, int flags, mode_t mode)
{
_open64 = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64");
if(flags & O_CREAT)
return _open64(pathname, flags | O_NOATIME, mode);
else
return _open64(pathname, flags | O_NOATIME, 0);
}
根据我的理解......它几乎是LD_PRELOAD技巧或内核模块。除非你想在一个模拟器下运行它,它可能会陷入你的函数或者在实际的二进制文件上重写代码以捕获你的函数,所以没有很多中间地带。
假设你无法修改程序而不能(或者不想)修改内核,LD_PRELOAD方法是最好的方法,假设你的应用程序是相当标准的,实际上并不是那个恶意尝试的方法超越你的拦截。 (在这种情况下,您将需要其他技术之一。)
答案 1 :(得分:7)
Valgrind可用于拦截任何函数调用。如果您需要拦截成品中的系统调用,那么这将是没有用的。但是,如果您在开发期间尝试拦截,那么它可能非常有用。我经常使用这种技术来拦截散列函数,这样我就可以控制返回的散列用于测试目的。
如果您不知道,Valgrind主要用于查找内存泄漏和其他与内存相关的错误。但底层技术基本上是一个x86模拟器。它模拟你的程序并拦截对malloc / free等的调用。好的是,你不需要重新编译就可以使用它。
Valgrind有一个功能,他们称之为功能包装,用于控制功能的拦截。有关详细信息,请参阅Valgrind manual的第3.2节。您可以为任何您喜欢的功能设置功能包装。拦截调用后,将调用您提供的替代函数。
答案 2 :(得分:5)
有些应用程序可以欺骗strace / ptrace不运行,所以我唯一真正的选择是使用systemtap
如果由于其通配符匹配需要,Systemtap可以拦截一堆系统调用。 Systemtap不是C,而是一种单独的语言。在基本模式下,systemtap应该阻止你做愚蠢的事情,但它也可以在“专家模式”下运行,如果需要的话允许开发人员使用C语言。
它不需要你修补你的内核(或者至少不应该),并且一旦编译了一个模块,你就可以从测试/开发盒中复制它并在生产系统上插入它(通过insmod)
我还没有找到一个已经找到解决方法的linux应用程序/避免被systemtap捕获。
答案 3 :(得分:3)
如果您只想观看打开的内容,您需要查看ptrace()函数或命令行strace实用程序的源代码。如果你真的想要拦截这个电话,或者让它做其他事情,我认为你列出的选项 - LD_PRELOAD或内核模块 - 是你唯一的选择。
答案 4 :(得分:2)
我没有使用LKM优雅地执行此操作的语法,但本文概述了您需要执行的操作:http://www.linuxjournal.com/article/4378
您也可以修补sys_open函数。从linux-2.6.26开始,它从file / open.c的第1084行开始。
您可能还会看到无法使用inotify,systemtap或SELinux为您执行所有此类日志记录,而无需构建新系统。
答案 5 :(得分:2)
如果您只是想进行调试,请查看strace,它是在ptrace(2)系统调用之上构建的,它允许您在系统调用完成时连接代码。请参见手册页的PTRACE_SYSCALL部分。
答案 6 :(得分:2)
听起来你需要审计。
Auditd允许通过日志记录全局跟踪所有系统调用或文件访问。您可以为您感兴趣的特定事件设置密钥。
答案 7 :(得分:1)
如果你真的需要一个解决方案,你可能会对完成这个的DR rootkit感兴趣,http://www.immunityinc.com/downloads/linux_rootkit_source.tbz2关于它的文章就在这里http://www.theregister.co.uk/2008/09/04/linux_rootkit_released/
答案 8 :(得分:0)
可以选择使用SystemTap。
对于Ubuntu,请按照https://wiki.ubuntu.com/Kernel/Systemtap中的说明进行安装。
然后只需执行以下命令,您将监听所有openat
的系统调用:
# stap -e 'probe syscall.openat { printf("%s(%s)\n", name, argstr) }'
openat(AT_FDCWD, "/dev/fb0", O_RDWR)
openat(AT_FDCWD, "/sys/devices/virtual/tty/tty0/active", O_RDONLY)
openat(AT_FDCWD, "/sys/devices/virtual/tty/tty0/active", O_RDONLY)
openat(AT_FDCWD, "/dev/tty1", O_RDONLY)