linux下监控shell脚本或可执行程序启动过的子进程

本文介绍使用auditd和strace工具监控子进程启动的方法。通过配置auditd规则或使用strace跟踪execve系统调用,可以获取make命令及shell脚本启动的子进程详情。

使用history命令可以查看在shell中直接执行过的命令,但是无法查看间接执行过的命令,或者说启动过的子进程。举个例子,shell脚本或者make命令都会启动一些子进程,这些子进程并不会显示在history命令的输出中,那么如何监控他们启动过哪些子进程呢?

首先需要明确的是,shell脚本靠得也是sh可执行程序加载执行,./foo.sh的效果一般等同于sh ./foo.sh,因此监控shell脚本启动过的子进程和监控其他可执行程序启动过的子进程是一样的。

假设我们有以下Makefile

all: main

main: main.cpp
	g++ -o main main.cpp

clean:
	rm main

现在我们来想办法监控当我们执行makemake clean时有哪些子进程被启动了。

auditd

如果你有root权限的话,那利用现成的auditd工具可以轻松的完成这项任务。auditd能监控的不只是单个进程启动过哪些子进程,它能监控整个系统中启动过哪些进程。除此之外,它还能监控哪些进程调用过我们指定监控的系统调用,以及哪些进程读/写/执行过我们指定监控的文件或目录,功能非常强大,有兴趣的可以参考一下auditd的文档。

安装好auditd后,按照如下方式配置监控规则:

auditctl -a task,always

然后执行makemake clean

最后执行以下命令查看监控日志:

ausearch -i -sc execve

对输出结果过滤一下,我们得到以下列表:

type=EXECVE msg=audit(2019年07月21日 10:40:45.562:213) : argc=1 a0=make 
type=EXECVE msg=audit(2019年07月21日 10:40:45.762:318) : argc=4 a0=g++ a1=-o a2=main a3=main.cpp 
type=EXECVE msg=audit(2019年07月21日 10:40:45.846:424) : argc=18 a0=/usr/lib/gcc/x86_64-linux-gnu/7/cc1plus a1=-quiet a2=-imultiarch a3=x86_64-linux-gnu a4=-D_GNU_SOURCE a5=main.cpp a6=-quiet a7=-dumpbase a8=main.cpp a9=-mtune=generic a10=-march=x86-64 a11=-auxbase a12=main a13=-fstack-protector-strong a14=-Wformat a15=-Wformat-security a16=-o a17=/tmp/ccgkuFBX.s 
type=EXECVE msg=audit(2019年07月21日 10:41:01.427:5798) : argc=5 a0=as a1=--64 a2=-o a3=/tmp/ccr9a4fi.o a4=/tmp/ccgkuFBX.s 
type=EXECVE msg=audit(2019年07月21日 10:41:02.671:6006) : argc=47 a0=/usr/lib/gcc/x86_64-linux-gnu/7/collect2 a1=-plugin a2=/usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so a3=-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper a4=-plugin-opt=-fresolution=/tmp/cccPuGlF.res a5=-plugin-opt=-pass-through=-lgcc_s a6=-plugin-opt=-pass-through=-lgcc a7=-plugin-opt=-pass-through=-lc a8=-plugin-opt=-pass-through=-lgcc_s a9=-plugin-opt=-pass-through=-lgcc a10=--sysroot=/ a11=--build-id a12=--eh-frame-hdr a13=-m a14=elf_x86_64 a15=--hash-style=gnu a16=--as-needed a17=-dynamic-linker a18=/lib64/ld-linux-x86-64.so.2 a19=-pie a20=-z a21=now a22=-z a23=relro a24=-o a25=main a26=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o a27=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o a28=/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o a29=-L/usr/lib/gcc/x86_64-linux-gnu/7 a30=-L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu a31=-L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib a32=-L/lib/x86_64-linux-gnu a33=-L/lib/../lib a34=-L/usr/lib/x86_64-linux-gnu a35=-L/usr/lib/../lib a36=-L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. a37=/tmp/ccr9a4fi.o a38=-lstdc++ a39=-lm a40=-lgcc_s a41=-lgcc a42=-lc a43=-lgcc_s a44=-lgcc a45=/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o a46=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o 
type=EXECVE msg=audit(2019年07月21日 10:41:03.107:6183) : argc=47 a0=/usr/bin/ld a1=-plugin a2=/usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so a3=-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper a4=-plugin-opt=-fresolution=/tmp/cccPuGlF.res a5=-plugin-opt=-pass-through=-lgcc_s a6=-plugin-opt=-pass-through=-lgcc a7=-plugin-opt=-pass-through=-lc a8=-plugin-opt=-pass-through=-lgcc_s a9=-plugin-opt=-pass-through=-lgcc a10=--sysroot=/ a11=--build-id a12=--eh-frame-hdr a13=-m a14=elf_x86_64 a15=--hash-style=gnu a16=--as-needed a17=-dynamic-linker a18=/lib64/ld-linux-x86-64.so.2 a19=-pie a20=-z a21=now a22=-z a23=relro a24=-o a25=main a26=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o a27=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o a28=/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o a29=-L/usr/lib/gcc/x86_64-linux-gnu/7 a30=-L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu a31=-L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib a32=-L/lib/x86_64-linux-gnu a33=-L/lib/../lib a34=-L/usr/lib/x86_64-linux-gnu a35=-L/usr/lib/../lib a36=-L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. a37=/tmp/ccr9a4fi.o a38=-lstdc++ a39=-lm a40=-lgcc_s a41=-lgcc a42=-lc a43=-lgcc_s a44=-lgcc a45=/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o a46=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o 
type=EXECVE msg=audit(2019年07月21日 10:41:15.275:8033) : argc=2 a0=make a1=clean 
type=EXECVE msg=audit(2019年07月21日 10:41:15.279:8138) : argc=2 a0=rm a1=main 
type=EXECVE msg=audit(2019年07月21日 10:41:28.632:8227) : argc=4 a0=ausearch a1=-i a2=-sc a3=execve 

可以看出来,除了显而易见的makeg++rm命令外,还有cc1plusascollect2ld命令被执行过。

阻挡我们使用auditd最大的不利因素在于它需要root权限,作为普通用户,有没有方法呢?

strace

strace在我之前的博客中已经提到过了,是一个用来跟踪程序系统调用的工具。如果我们跟踪的系统调用是execve,就能得知程序启动过哪些子进程。

执行以下命令,其中-e用来指定需要跟踪的系统调用,-f表示我们需要对子进程也发起跟踪:

strace -e execve -f make
strace -e execve -f make clean

将输出结果过滤后,有以下内容:

execve("/usr/bin/make", ["make"], 0x7ffc75c3baa8 /* 65 vars */) = 0
[pid  3523] execve("/usr/bin/g++", ["g++", "-o", "main", "main.cpp"], 0x561d6e982060 /* 70 vars */) = 0
[pid  3524] execve("/usr/lib/gcc/x86_64-linux-gnu/7/cc1plus", ["/usr/lib/gcc/x86_64-linux-gnu/7/"..., "-quiet", "-imultiarch", "x86_64-linux-gnu", "-D_GNU_SOURCE", "main.cpp", "-quiet", "-dumpbase", "main.cpp", "-mtune=generic", "-march=x86-64", "-auxbase", "main", "-fstack-protector-strong", "-Wformat", "-Wformat-security", "-o", "/tmp/ccr71lJH.s"], 0x14506d0 /* 75 vars */) = 0
[pid  3525] execve("/usr/bin/as", ["as", "--64", "-o", "/tmp/ccsBGiqv.o", "/tmp/ccr71lJH.s"], 0x14506d0 /* 75 vars */) = 0
[pid  3526] execve("/usr/lib/gcc/x86_64-linux-gnu/7/collect2", ["/usr/lib/gcc/x86_64-linux-gnu/7/"..., "-plugin", "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "-plugin-opt=/usr/lib/gcc/x86_64-"..., "-plugin-opt=-fresolution=/tmp/cc"..., "-plugin-opt=-pass-through=-lgcc_"..., "-plugin-opt=-pass-through=-lgcc", "-plugin-opt=-pass-through=-lc", "-plugin-opt=-pass-through=-lgcc_"..., "-plugin-opt=-pass-through=-lgcc", "--sysroot=/", "--build-id", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=gnu", "--as-needed", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-pie", "-z", "now", "-z", "relro", "-o", "main", "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., ...], 0x1450be0 /* 77 vars */) = 0
[pid  3527] execve("/usr/bin/ld", ["/usr/bin/ld", "-plugin", "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "-plugin-opt=/usr/lib/gcc/x86_64-"..., "-plugin-opt=-fresolution=/tmp/cc"..., "-plugin-opt=-pass-through=-lgcc_"..., "-plugin-opt=-pass-through=-lgcc", "-plugin-opt=-pass-through=-lc", "-plugin-opt=-pass-through=-lgcc_"..., "-plugin-opt=-pass-through=-lgcc", "--sysroot=/", "--build-id", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=gnu", "--as-needed", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-pie", "-z", "now", "-z", "relro", "-o", "main", "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "/usr/lib/gcc/x86_64-linux-gnu/7/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., ...], 0x7ffe13bbc388 /* 77 vars */) = 0
execve("/usr/bin/make", ["make", "clean"], 0x7ffc66153780 /* 65 vars */) = 0
[pid  3533] execve("/bin/rm", ["rm", "main"], 0x56437f262a90 /* 70 vars */) = 0

结果和使用auditd是一样的。

使用strace不需要root权限,这点非常好。

修改内核

可以在内核中forkexecve实现的函数中插入一些printk语句,也算是一种方法,不过实施起来条件比较苛刻。如果没有auditd可用,而你又监控系统范围内启动的所有进程,可以试一试这种方法。

上面就是我能想到的几种监控启动的子进程的方法,不知道各位读者还有什么高招,可以分享一下。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值