Linux几种检测rootkit隐藏进程的方法

Rootkit通常会隐藏进程,隐藏文件和网络连接。这里主要记录几种对隐藏进程的检测方法

一. 隐藏进程的方法

1.1 用户级Rootkit 通过LD_PRELOAD来hook libc库,从而过滤/proc/pid目录

1.2 内核级rootkit 通过hook系统调用getdents/getdents64或者hook 文件file_operation的iterate

1.3 内核级rootkit把task_struct 从相关链表摘除(init_task,pidlist)

二 检测进程的方法

2.1 前两种隐藏检测方法

因为进程还在内核链表中,可以通过pid找到task_struct .

第一步:读/proc/pid目录,收集系统所有进程

第二步: 给0到pid_max进程发送任意信号,信号发送成功,表示进程存在,从而收集系统所有进程
for(pid=0;pid<PID_MAX;pid++)
        kill   -20 pid

第三步:对比第一步和第二步收集进程的差异,即可确认隐藏进程(要排除已经退出的进程)


2.2 第三种隐藏方法的检测
因为在链表中找不到,所以不能通过PID找到task_struct.这里可以基于task_strcut的特征,在内存中查找task_struct结构体

直接上代码:
 

/*通过PID获取task_struct检测进程是否存在,也可以读/proc/确认 */
static struct task_struct *get_task(pid_t nr)

{

    struct task_struct *task = NULL;
    struct pid *pid_group = NULL;
    pid_group = find_get_pid(nr);
    task = get_pid_task(pid_group,PIDTYPE_PID);
    if(IS_ERR_OR_NULL(pid_group)||IS_ERR_OR_NULL(task)){
        //printk("Can't Get pid =%d,pid=%px,task=%px\n",nr,pid_group,task);
        return NULL;
    }
	return task;
}

/*这里假设隐藏进程使用CFS调度,其他调度类也可采用类似方法比较 */

static int scan_task(struct page *page)

{
	struct task_struct *task = NULL ;
	unsigned long start = page_to_virt(page);
	unsigned long end = start+PAGE_SIZE;
	while(start<end){

		task = (struct task_struct *)start;
            /*找到task_struct结构体,当然也可以用其他task_struct特征值
        进程再怎么隐藏和篡改,也不会修改sched_class的值,因为还需要运行。
 */
		if(task->sched_class==current->sched_class&&(task->state!=TASK_DEAD)){

			get_task_struct(task);
                        /*如果get_task找不到,而扫描内存能找到,证明进程隐藏了 */
			if(!get_task(task->pid))
				printk("We get Hide task %s,pid=%d\n",task->comm,task->pid);
			start += sizeof(*task);
			put_task_struct(task);
			continue ;
		}

		start++;
	}

	return 0;
}

static void scan_memory(void)

{
	int i = 0;
        /*遍历系统所有内存 */
	for_each_online_node(i) {
		unsigned long start_pfn = node_start_pfn(i);
		unsigned long end_pfn = node_end_pfn(i);
		unsigned long pfn;

		for (pfn = start_pfn; pfn < end_pfn; pfn++) {
			struct page *page = pfn_to_online_page(pfn);

			if (!page)
				continue;
			/* only scan pages belonging to this node */
			if (page_to_nid(page) != i)
				continue;
			/* only scan if page is in use */
			if (page_count(page) == 0)
				continue;
			/*因为task_struct是通过slab机制分配 */
			if(!PageSlab(page))
				continue ;
			scan_task(page);
			if (!(pfn & 63))
				cond_resched();
		}
	}
	

}

效果:
把firefox进程3126从内核链表中摘除,从/proc/看不到
ls: cannot access '/proc/3126': No such file or directory
加载内存扫描模块:

[ 2452.997816] We get Hide task firefox,pid=3126

可以看到能够找到被隐藏的进程.
通过task_struct的特征值来扫描内存时,一定要选取不能轻易篡改的值,否则很容易被木马对抗.

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值