Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何拦截linux sys调用?_C_Linux_Redirect_Hook_System Calls - Fatal编程技术网

C 如何拦截linux sys调用?

C 如何拦截linux sys调用?,c,linux,redirect,hook,system-calls,C,Linux,Redirect,Hook,System Calls,除了LD_预加载技巧和用您提供的系统调用替换某个系统调用的Linux内核模块之外,是否有可能拦截系统调用(例如open),以便它在到达实际open之前首先通过您的函数?为什么您/不想使用 此处的示例代码: /* * 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 so

除了LD_预加载技巧和用您提供的系统调用替换某个系统调用的Linux内核模块之外,是否有可能拦截系统调用(例如open),以便它在到达实际open之前首先通过您的函数?

为什么您/不想使用

此处的示例代码:

/*
 * 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 <sys/types.h>
#include <bits/fcntl.h>
#include <stddef.h>

extern int errorno;

int __thread (*_open)(const char * pathname, int flags, ...) = NULL;
int __thread (*_open64)(const char * pathname, int flags, ...) = NULL;

int open(const char * pathname, int flags, mode_t mode)
{
    if (NULL == _open) {
        _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)
{
    if (NULL == _open64) {
        _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);
}
/*
*文件:soft_atimes.c
*作者:D.J.卡佩利斯
*
*汇编:
*gcc-fPIC-c-o soft_atimes.o soft_atimes.c
*gcc-shared-o soft_-atimes.so soft_-atimes.o-ldl
*
*使用:
*LD_PRELOAD=“/soft_atimes.so”命令
*
加利福尼亚大学版权所有2007人
*/
#定义GNU源
#包括
#定义
#包括
#包括
#包括
外部国际错误;
int _线程(*_open)(常量字符*路径名,int标志,…)=NULL;
int _u线程(*open64)(常量字符*路径名,int标志,…)=NULL;
int open(常量字符*路径名、int标志、模式)
{
如果(空==\u打开){
_open=(int(*)(const char*路径名,int标志,…)dlsym(RTLD_NEXT,“open”);
}
if(标志和O_创建)
返回打开(路径名、标志、时间、模式);
其他的
返回_open(路径名,标志| O_NOATIME,0);
}
int open64(常量字符*路径名、int标志、模式)
{
如果(空==_open64){
_open64=(int(*)(const char*路径名,int标志,…)dlsym(RTLD_NEXT,“open64”);
}
if(标志和O_创建)
返回open64(路径名、标志、时间、模式);
其他的
返回_open64(路径名,标志| O_NOATIME,0);
}
据我所知。。。这几乎就是LD_预加载技巧或内核模块。除非你想在模拟器下运行它,它可以捕获到你的函数,或者在实际的二进制文件上重新编写代码来捕获到你的函数,否则没有太多的中间地带


假设您不能修改程序,也不能(或不想)修改内核,LD_PRELOAD方法是最好的方法,假设您的应用程序是相当标准的,并且实际上不是恶意试图通过拦截的应用程序。(在这种情况下,您将需要其他技术之一。)

如果您真的需要一个解决方案,您可能会对实现这一点的DR rootkit感兴趣,关于它的文章就在这里

我不知道如何用LKM轻松优雅地完成这一点,但这篇文章很好地概述了您需要做什么:

您也可以只修补sys_open函数。从linux-2.6.26开始,它从文件/open.c的第1084行开始

您还可能会看到,如果您不必构建新系统,就无法使用inotify、systemtap或SELinux来完成所有这些日志记录。

可用于拦截任何函数调用。如果您需要在成品中拦截系统调用,那么这将是没有用的。然而,如果您试图在开发过程中拦截,那么它可能非常有用。我经常使用这种技术截取散列函数,以便出于测试目的控制返回的散列

如果您不知道,Valgrind主要用于查找内存泄漏和其他内存相关错误。但底层技术基本上是x86仿真器。它模拟您的程序并拦截对malloc/free等的调用。好处是,您不需要重新编译即可使用它


Valgrind有一个特性,它们称为函数包装,用于控制函数的拦截。有关详细信息,请参见第3.2节。您可以为任何喜欢的函数设置函数包装。一旦调用被拦截,您提供的替代函数就会被调用

如果您只想查看打开的内容,您需要查看ptrace()函数或命令行strace实用程序的源代码。如果你真的想拦截这个调用,或者让它做些别的事情,我认为你列出的选项——LD_PRELOAD或内核模块——是你唯一的选择。

如果你只是为了调试的目的而这样做,看看strace,它内置在ptrace(2)的顶部系统调用,允许您在完成系统调用时连接代码。请参阅手册页的PTRACE\u SYSCALL部分。

一些应用程序可能会欺骗strace/PTRACE不运行,因此我唯一的实际选择是使用systemtap

如果由于通配符匹配,Systemtap可以拦截大量系统调用。Systemtap不是C语言,而是一种独立的语言。在基本模式下,systemtap应该可以防止你做一些愚蠢的事情,但它也可以在“专家模式”下运行,如果需要的话,可以让开发人员使用C

它不需要您修补内核(或者至少不应该),并且一旦编译了模块,您就可以从测试/开发框中复制它并(通过insmod)将其插入到生产系统中


我还没有找到一个linux应用程序,它能够找到一种方法来解决/避免被systemtap抓住。

听起来你需要auditd


Auditd允许通过日志记录对所有系统调用或文件访问进行全局跟踪。您可以为感兴趣的特定事件设置键。

使用SystemTap可能是一个选项

对于Ubuntu,请按照中的说明进行安装

然后执行以下命令,您将监听所有
openat
syscalls:

# 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)

当存在其他更为传统的替代方案时,为什么要提出一种模糊的方法?LD_PRELOAD是最常见的。因为他不是在寻找更传统的问题,或者至少这是我从他的原始问题中收集到的。这个问题需要澄清——它太模糊了。为什么LD_PRELOAD不够?@Arafangion-LD_PRELOAD可以让你拦截库调用。但是内核调用是不同的,程序完全可以选择确认LD_预加载。不是每个程序都与libc链接。@vipw您能详细说明一下吗?程序如何能够绕过LD_预加载?每一个没有链接的程序