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的特徵值來掃描內存時,一定要選取不能輕易篡改的值,否則很容易被木馬對抗.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章