在 mac 上记录 `open` 系统调用

recording `open` syscalls on mac

我想知道在 bash 脚本中对 open(2) 进行了哪些调用。

我编写了以下拦截系统调用的程序:

#include <fcntl.h>
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };

static
int
my_open(const char *filename, int oflag, mode_t mode)
{
    printf("$jason$ open: %s\n", filename);
    return open(filename, oflag, mode);
}
DYLD_INTERPOSE(my_open, open)

然后我 运行 使用:

clang -dynamiclib libfile.c -o libfile.dylib
export DYLD_INSERT_LIBRARIES=libfile.dylib
touch /tmp/testingtesting

没用。

我用自己编译的程序试了一下,效果很好。我用 brew 编译的程序试了一下,效果很好。我阅读了 touch.c 的源代码。它调用 open(2).

然后我禁用了 SIP,它工作正常。因此,我得出结论,是 SIP 导致了问题。不过我不想禁用 SIP。

我该怎么办?我正在考虑只允许 dtrace:csrutil enable --without dtrace。因为我认为 dtrace 可以跟踪系统调用,但我不确定这是否是一个安全的选择。

您所做的称为库注入,Apple 正在努力从他们的系统中删除此功能。

由于他们的努力,在启用 SIP 的情况下,您可以只对未加固(或加固但有几个特定例外)的应用程序执行 DYLD_INSERT 魔法,我想这些应用程序是您建造和酿造船只。 Apple 二进制文件,其中之一是 touch,通常以其他方式加固或保护。

这里没有太多选择:

  1. 禁用 SIP 并注入你想要的东西
  2. 部分禁用 SIP,您可能会实现一些目标(dtrace 可能会有所帮助)
  3. 编写一个内核扩展进行注入,并以某种方式从 Apple 获得 kext 签名——它可以在启用 SIP 的情况下工作。

所有这些选项都是针对 Intel-based macs,对于 m1 可能更难。

关于安全性:关闭 machine 并从外部数据源(Internet,USB-drives 等)禁用 SIP,进行研究,然后重新启用 SIP 并连接 mac 再次走向世界。

最近版本的 macOS 基本上不再支持通用库注入。

但是您确实可以像您怀疑的那样使用 dtrace 执行此操作,特别是 dtruss 脚本。不幸的是,macOS 附带的这个脚本版本相当陈旧,所以我建议使用 my updated version of dtruss¹,因为这可以让你追踪所有 sub-processes,如果你追踪 shell 脚本。它还避免了必须 运行 您尝试使用 sudo 跟踪的命令,这可能会使它的行为有所不同。

这个命令…

path/to/dtruss -d -e -f -t open touch /tmp/testingtesting

…链接版本应该可以正常工作。命令行解释:

  • -d-e 显示调用时间。 (可选)
  • -f 启用“跟随”模式以跟踪生成的 sub-processes - 这对于 touch 命令来说并不是很有趣,但您可能需要它来跟踪一个bash 脚本。
  • -t open 限制对 open 系统调用的跟踪。 (将其关闭以跟踪 all 系统调用。注意:这可能会产生大量输出。)

使用原版 dtruss,您可以退回到:

  • sudo dtruss -d -e -t open touch /tmp/testingtesting - 但请注意,在这种情况下,touch 将作为 root 用户 运行,并且不支持跟踪 sub-processes。
  • sudo dtruss -d -e -t open -n touch,然后在另一个终端中 运行 touch /tmp/testingtesting。这避免了 运行ning touch 作为 root,但它会跟踪 all 个名为 touch.
  • 的进程

当使用 dtruss 的原始版本时,跟踪系统调用的输出也可能不太清楚,因为更新版本在格式化系统调用参数(尤其是字符串)方面做得更好。 (对于 open() 具体而言,the updated version prints the 'mode' argument for created file permisions as octal,这通常是您想要的。)

是的,您需要禁用 SIP 的 dtrace 部分才能使 dtrace 的所有功能正常工作,这可能会带来一个小的安全风险,但我还没有听说过任何试图利用的恶意软件这个。

脚注:

¹ 我不是要 self-promote 我的代码。我根本不知道更好的解决方案 - 我遇到了与提问者非常相似的问题,并且 built-in 工具不够好,所以我修复了它。