12

我正在写一个工具。该工具的一部分将是它能够记录系统调用的参数。好吧,我可以ptrace用于此目的,但ptrace速度很慢。我想到的一个更快的方法是修改 glibc。但这变得越来越困难,因为 gcc 神奇地插入了自己的内置函数作为系统调用包装器,而不是使用 glibc 中定义的代码。使用-fno-builtin也无济于事。

所以我想出了写一个共享库的想法,它包括每个系统调用包装器,例如mmap然后在调用实际的系统调用包装器函数之前执行日志记录。例如mmap下面给出了我的样子的伪代码。

int mmap(...)
{
 log_parameters(...);
 call_original_mmap(...);
 ...
}

然后我可以使用 LD_PRELOAD 首先加载这个库。你认为这个想法会奏效,还是我错过了什么?

4

4 回答 4

3

您在用户空间中想象的任何方法都无法与任何应用程序无缝协作。对您来说幸运的是,已经支持在内核中执行您想要执行的操作。Kprobes 和 Kretprobes 允许您检查机器在系统调用之前和之后的状态。

此处的文档: https ://www.kernel.org/doc/Documentation/kprobes.txt

于 2012-07-01T22:48:35.640 回答
1

正如其他人所提到的,如果二进制文件是静态链接的,则动态链接器将跳过任何使用 libdl 拦截函数的尝试。相反,您应该考虑自己启动该过程,并绕道您希望拦截的函数的入口点。

这意味着你自己启动进程,拦截它的执行,并重写它的内存,在内存中函数定义的开头放置一个跳转指令到你控制的新函数。

如果你想拦截实际的系统调用并且不能使用ptrace,你要么必须找到每个系统调用的执行站点并重写它,要么你可能需要覆盖内存中的系统调用表并过滤掉除你想控制的过程。

于 2012-05-22T02:32:09.353 回答
0

来自用户空间的所有系统调用都通过一个中断处理程序切换到内核模式,如果你找到这个处理程序,你可能可以在那里添加一些东西。

编辑我发现这个http://cateee.net/lkddb/web-lkddb/AUDITSYSCALL.html。Linux 内核:2.6.6–2.6.39、3.0–3.4 支持系统调用审计。这是一个必须启用的内核模块。如果不让人感到困惑,也许你可以查看这个模块的源代码。

于 2012-05-21T20:26:12.760 回答
0

如果您正在开发的代码与流程相关,有时您可以在不破坏现有代码的情况下开发替代实现。如果您正在重写一个重要的系统调用并且想要一个功能齐全的系统来调试它,这将很有帮助。

对于您的情况,您正在重写 mmap() 算法以利用令人兴奋的新功能(或使用新功能进行增强)。除非您在第一次尝试时一切都正确,否则调试系统并不容易:无功能的 mmap() 系统调用肯定会导致系统无功能。一如既往,有希望。

通常,保留剩余的算法并在旁边构建替代算法是安全的。您可以通过使用用户 ID (UID) 作为决定使用哪种算法的条件来实现这一点:

if (current->uid != 7777) {
/* old algorithm .. */
} else {
/* new algorithm .. */
}

除了 UID 7777 之外的所有用户都将使用旧算法。您可以使用 UID 7777 创建一个特殊用户来测试新算法。这使得测试与流程相关的关键代码变得更加容易。

于 2012-07-19T17:46:48.473 回答