我想要翻译:
"a b c syscall=257 success=yes"
改为:
"a b c syscall=openat success=yes"
我喜欢使用sed组捕获正则表达式和替换,并结合使用 ausyscall 应用于正则表达式组提取的数字。
我在 Linux/bash 下尝试了以下操作:
echo "a b c syscall=257 success=yes" |
sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall 257)":"
它打印:a b c SYSCALL=openat success=yes
正如预期的那样。
然后我尝试使用捕获组 #1 作为 的参数ausyscall
。像这样:
echo "a b c syscall=257 success=yes" |
sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \1)":"
这将调用ausyscall 1
which 打印write
。这不是捕获的组 #1(其值为 257)。
因此我尝试使用\\1
,但也失败了:
echo "a b c syscall=257 success=yes" |
sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \\1)":"
这将调用失败,在 stderr( )ausyscall \1
上打印错误并在 stdout 上打印。Unknown syscall \1 using x86_64 lookup table
a b c SYSCALL= success=yes
无法将捕获的值传递给 ausyscall。我尝试使用单引号,但无法调用 ausyscall。
可以这样使用sed吗?
- 我只想知道是否能够用sed来做到这一点。
- 我知道可以通过其他方式(perl、python 脚本、gawk 等)来完成,但我想看看是否可以用 sed 来完成,以及问题是否与引用或类似的东西有关。
使用sed可以实现吗?如果可以,我遗漏了什么?
预计 不会
sed
执行此操作。它不能!命令的实际运行是您的 shell 执行的,而不是sed
,因此这不是 的功能sed
,而是另一个程序,即 shell您已经以这种方式开始操作了!您正在使用脚本语言解释器作为替换引擎,并在其中执行
sed
一些基本操作。您的 shell(无论是 bash、ash、zsh、csh、cmd 等)与 python 解释器没有什么不同。如果您愿意使用GNU sed扩展命令, GNU sed可以做到这一点:
e
s
扩展
e
派生s
一个 shell 并评估s
的结果模式空间,并用执行命令的结果替换模式空间。为了减轻任何潜在的代码注入问题,提取系统调用号的正则表达式非常小心,只匹配数字。[0-9]
不使用,因为它可以匹配各种语言环境中的其他内容。然后将结果数字传递给构造的ausyscall
命令并执行。其余命令
sed
是为了确保如果输入行不包含系统调用号,则它们将保持不变。附注-Ubuntu 用户可以通过安装软件包来安装
ausyscall
命令auditd
:还要注意 - 每当您看到 这个词时
evaluate
,请将其视为可能存在代码注入错误的重大警告。 不要对未经审查的用户输入使用此类命令。 由于这种情况适用于严格的数字数据,因此很容易验证,但对于更一般的情况,必须更加小心。我不认为
sed
可以做到这一点,但是 perl 可以,而且只是稍微复杂一些:不过,这很可能会在那里添加一个你不想要的额外换行符。因此,你可能需要这样做:
Perl
s
运算符的工作方式与 sed 运算符基本相同。这里唯一的区别是,通过e
在末尾使用标志 (s:old:new:e
),我们可以在替换端运行 perl 代码,并使用代码的结果。所讨论的代码是:`ausyscall $1`
:运行ausyscall
并传递它$1
(这相当于 sed 的 \1 — 尽管 Perl 也可以使用 \1,只是不能使用e
标志 — 因此它是第一组括号捕获的内容)作为参数。请注意,该命令在系统的默认 shell 中运行(通常是sh
)。chomp($v=`...`)
:删除尾随换行符。这将删除命令返回的换行符ausyscall
。结果存储在变量中$v
。"SYSCALL=$v"
:这将返回所需的输出。请注意,这是一种有风险的方法。在这种特定情况下,这种方法是可行的,因为您明确只捕获数字,但一般来说,您不想将任意输入作为命令执行,因为这会使您容易受到代码注入攻击。
您可以轻松地使用
sed
将输入行转换为 shell 命令,然后该命令将能够产生所需的输出。shell 的eval
命令与命令替换相结合,应该可以一次处理一行,如您的示例所示。例如,像这样:但是正如其他人所回答的那样,考虑到您的应用程序的具体情况,并且取决于您需要执行多少次(即,您想在任何给定时间处理多少行输入),使用
ausyscall
可能是效率最低、最不有效的方法。这就是
-i
选项的ausearch
作用(以及更多):查看系统调用号是如何转换的,还有时间戳¹、arch、模式、uids、gids,以及系统调用的一些参数...
对输入中
ausyscall
出现的每次运行都会非常低效,尤其是考虑到 GNU和(如在其他一些答案中所使用的)也运行或可能运行 shell 来解释命令。 GNU的命令和命令标志实际上也不可能安全使用,我强烈建议永远不要使用它。syscall=<numbers>
sed
perl
sed
e
e
s
在这里,如果您只想翻译系统调用号而不是其他 ID
ausearch
,那么最好使用ausyscall --dump
(运行一次)的输出,它会给您完整的映射:这假设您使用的是单架构系统,因为系统调用编号与架构有关。例如,在现代 PC 上,您可以让应用程序以 x86 或 amd64(又名 x86_64)模式运行,但如果 x86 应用程序进行系统调用,则无法正常工作,因为系统会
ausyscall
为您提供 amd64 系统调用的转换。ausearch -i
可以正确地完成此操作,但要做同样的事情,您需要构建两个映射,一个用于 x86,一个用于 amd64,并从审计记录中提取体系结构。例如,此处使用 x86 busybox 的静态构建:
这是 2 个
openat
系统调用,第一个是 amd64 系统调用cat
,第二个是 busybox-x86 系统调用。ausearch -i
正确翻译如下:但是
perl
上面的代码是错误的(你的尝试也是如此):因为 295 是 amd64 系统调用的编号
preadv
,也是openat
x86 系统调用的编号。因此,在那个多架构系统上,我需要类似这样的东西:
这正确地给了我:
如果
ausyscall
不支持--dump
,您至少可以缓存结果,以避免对相同的值运行多次:(这里还处理 amd64 和 x86 架构)。
¹ 使用当地时间(用于
TZ=UTC0
UTC 时间)并格式化为strftime("%x %T")
,依赖于语言环境;使用诸如 csb_PL de_AT de_BE de_LU en_CA en_DK eo fr_CA hu_HU kv_RU lt_LT se_NO si_LK sv_SE wae_CH 之类的语言环境来获取不太模糊的 ISO8601 类时间戳:sudo TZ=UTC0 LC_ALL= LC_TIME=en_DK.UTF-8 ausearch -i ...
;确保您的系统上可以使用该语言环境,否则您将从 C 语言环境获得美国风格的时间戳%m/%d/%y %H:%M:%S
格式。