某些时候程序员为了不让其他人不小心或者恶意破坏掉你运行的程序,或者我们要做些“见不得光”的事情,就有隐藏进程的需求,目的是让小白或者初级运维无法通过ps或者top查找到你的程序,达到隐藏目的。前两天正好项目上需要用到隐藏进程的需求,所以分析了下个人觉得目前比较好的做法。
linux下查看进程的方法
ps命令
top命令
目前网上很多方法基本都是通过如下方式来达到进程隐藏:
1.根据分组权限来实现不同用户组查看不同的进程权限。
2.修改内核,将需要隐藏的进程的进程pid改为0(task->pid = 0),因为ps,top命令不会显示进程id为0的进程。
3.修改内核,hook掉系统调用,在hook函数中修改逻辑判断已达到隐藏进程。
第一种如果其他有管理员权限就没有办法隐藏了。第二三中需要懂内核编程,今天我们说下第四种办法:在用户态修改系统调用,从而隐藏进程。
PS/TOP显示进程原理
strace命令是一个常用的代码调试工具,它可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。因此对于调试程序出错是非常有用的。这里不过多展示strace的调试用法,具体可以查看详细的strace命令。
我们看下ps,top是如何显示进程信息的:
strace ps
strace top
通过strace命令可以看出 ps,top等查看进程的信息都是通过调用 readdir 方法遍历 /proc 目录来获取进程信息。每个动态创建的进程ID号下面详细的记录了关于该进程的fd,mem,io,cpuset等进程信息。
既然进程信息是proc目录下动态生成的,因此最显而易见和最彻底的方法就是不让proc下生成该进程信息。通过查找代码,定位到内核通过fs/proc/base.c中的proc_pid_lookup查找进程号,然后由proc_pid_instantiate来在proc下创建该进程号相关的进程信息。因此我们只需要在proc_pid_lookup中匹配要过滤的进程名,然后直接返回就行了,如下:
这种办法彻底上不创建该进程信息,但是要修改编译内核,实际上是不太可取的。而我们目的也只是隐藏,不必完全屏蔽进程信息。因此,有没有一种办法在用户态通过劫持系统调用而忽略掉我们的进程呢?
本着绝不重复造轮子的工匠精神,瓶子哥搜罗了下,还真有现成的,即通过劫持readdir系统调用实现ps,top无法查找到进程而达到隐藏进程。
我们先实战,在看其实现原理。
1 . 实现:
1) git clone https://github.com/gianlucaborello/libprocesshider.git
2) cd
libprocesshider/ && make
3) cp libprocesshider.so /usr/local/lib/
4)echo
/usr/local/lib/libprocesshider.so >> /etc/ld.so.preload
这一步也可以用export LD_PRELOAD=/usr/local/lib/libprocesshider.so来代替。
执行命令上述命令前,运行mtop进程,ps可以查看到mtop的进程。
执行上述命令后,ps 查看,可以发现已经找不到该进程了,而且 top,ls /proc/下面也不能找到该进程,完美达到隐藏进程。
2. 原理:
我们查看processhider.c源码可以发现,原理上就是重写了readdir的系统调用,因为无论ps,top,ls 都会调用readdir。我们只需要设置代码里面的process_to_filter为自己需要屏蔽的进程名就行了。
而思路就是利用 LD_PRELOAD 来实现系统函数的劫持,程序在执行外部库函数调用的时候,会根据动态库的优先级来加载库函数,linux下库的加载顺序为/etc/ld.so.preload( LD_PRELOAD)>/etc/ld.so.cache>/etc/ld.so.conf,当程序调用外部库的函数,如果LD_PRELOAD里面有自定义和其他系统库相同的库函数,则优先加载我们自定义的函数,这样就达到了劫持系统函数的目的。
由于ps,top,ls 等几乎所有的查看命令都基于readdir系统调用,所以能够完美的隐藏掉进程,对付一般的小白是完全够用了。如果为了避免分析人员查找 /etc/ld.so.preload而定位到进程,我们可以不建立ld.so.preload文件,而使用LD_PRELOAD宏来定义库的路径。例如将export LD_PRELOAD=/usr/local/lib/libprocesshider.so 放到linux系统启动过程中rc文件去加载,加大定位的难度。