C 在不修改内核的情况下拦截系统调用的最小开销方法

C 在不修改内核的情况下拦截系统调用的最小开销方法,c,linux,gcc,x86-64,system-calls,C,Linux,Gcc,X86 64,System Calls,我所知道的拦截系统调用的方法如下 使用,但这似乎有很高的开销。据我所知,像strace这样的工具在内部也使用ptrace 使用内核模块更改系统调用表,但据我所知,这种方法在以后的linux内核中不再可能 使用LD_预加载。但是,例如,如果您直接进行系统调用,而不为该系统调用使用一些包装器库函数,那么这将不起作用 所以你可以看到上面提到的所有方法都有缺陷。因此,我的问题是,在不修改内核的情况下,以最小的开销拦截系统调用的方法是什么。看看如何使用动态检测框架,例如or。您的平台应该有一个或两个可用。

我所知道的拦截系统调用的方法如下

  • 使用,但这似乎有很高的开销。据我所知,像strace这样的工具在内部也使用ptrace
  • 使用内核模块更改系统调用表,但据我所知,这种方法在以后的linux内核中不再可能
  • 使用LD_预加载。但是,例如,如果您直接进行系统调用,而不为该系统调用使用一些包装器库函数,那么这将不起作用

  • 所以你可以看到上面提到的所有方法都有缺陷。因此,我的问题是,在不修改内核的情况下,以最小的开销拦截系统调用的方法是什么。

    看看如何使用动态检测框架,例如or。您的平台应该有一个或两个可用。

    如果无法修改内核,则必须修改应用程序。您需要以某种方式拦截
    int
    /
    syscall
    /
    sysenter
    指令,或者在那里设置断点(如果您可以在Linux中的应用程序中处理它们;您可以在Windows中使用SEH/VEH)或者以更具侵入性的方式挂接指令(将其更改为
    jmp
    以获得保存系统调用号码和参数的代码,执行原始的
    int
    /
    syscall
    /
    syscenter
    jmp
    返回)

    编辑:哦,我忘了补充一点,查找这些指令可能是一项挑战。您可能无法在已编译的二进制文件中正确识别它们。您可能会错过一些指令(尤其是在运行时创建的指令),您可以为
    int
    /
    系统调用
    /
    系统输入
    (如果您的代码分析不完美)。OTOH,在运行时(通过在执行/模拟单个指令(或指令块)之前分析它们)查找它们将导致性能下降


    在任何情况下,性能问题都很可能与正在进行的系统调用的数量和记录/跟踪的信息量直接相关。如果您减少这一数量(即仅选择感兴趣的系统调用和参数)和/或只收集最近10000次系统调用的信息,并将数据保存在内存中,只保存一次(在应用程序结束时),您将有更好的性能。

    可能也会有帮助;它也适用于Linux。

    除了已经列出的那些,可能没有。为什么不能使用
    ptrace
    syscall?它的开销在实践中通常是可以接受的(因为大多数应用程序在用户模式下比在内核模式下进行系统调用花费更多的CPU时间)。我还会在这里放一段代码片段,说明如何使用ptrace。可能有一些方法可以优化它。