CRUX下实现进程隐藏(2)
前面我们介绍了如何修改/proc目录读取函数的方法实现进程隐藏。这篇博文将介绍另一种方法——
劫持系统调用实现进程隐藏。
其基本原理是:加载一个内核模块(LKM),通过劫持系统调用sys_getdents()来针对进程文件进行适当的过滤,从而达到隐藏进程文件的目的。
由于实验方法一时,已经修改过了proc_pid_readdir函数,这会影响方法二的实现,因此必须把方法一中所做的修改恢复。打开proc_pid_readdir所在的源文件fs/proc/base.c
在其中加入DEBUG_PROC,表示采用方法一,这里我注释掉了,表示这时使用方法二。
把该函数中对进程hide字段的判断加入宏定义中即可。之后重新编译内核,编译后执行测试程序,已经无法隐藏进程。
下面开始介绍第二种方法:
① 分析读取proc文件系统时所执行的系统调用:
在linux下,我们可以使用strace命令来跟踪一个用户程序在执行过程中所使用的系统调用。
在linux终端命令行输入:strace ps aux 2>out.txt
可以查询ps命令所执行的系统调用,结果如下:
......
open("/proc/meminfo", O_RDONLY) = 4
lseek(4, 0, SEEK_SET) = 0
read(4, "MemTotal: 495788 kB\nMemF"..., 2047) = 1114
stat("/proc/self/task", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 5
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5330b72000
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5330b51000
getdents(5, /* 140 entries */, 32768) = 3696
stat("/proc/1", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/1/stat", O_RDONLY) = 6
read(6, "1 (init) S 0 1 1 0 -1 4202752 22"..., 4095) = 326
close(6)
......
其中,我们看到ps命令执行过程中调用了getdents这个函数,而ps命令正是使
用这个函数来读取/proc目录下的进程文件的。其对应的系统调用是sys_getdents(),其函数原型如下:
int sys_getdents(unsigned int fd, struct linux_dirent64 __user *dirp, unsigned int count)
其中,fd为指向目录文件的文件描述符,该函数根据fd所指向的目录文件读取相应dirent结构,并放入dirp中,其中count为dirp中返回的数据量,正确时该函数返回值为填充到dirp的字节数。
而我们要做的就是代替原先的系统调用,使用自己定义的系统调用hacked_getdents(),加上我们自己的判断语句就能实现对进程文件的过滤。Linux中,替换系统调用有两种方法:一是直接修改原先的系统调用;二是编写一个内核模块(LKM),通过获得系统调用表的地址来替换原先的系统调用。
因为前者需要重新编译内核,比较费时。内核模块是一些可以让操作系统内核在需要时载入和执行的代码,这同样意味着它可以在不需要时由操作系统卸载。它们扩展了操作系统内核的功能却不需要重新编译内核,因此内核模块机制的好处是:既避免了内核的臃肿不堪,又极大程度地提高了内核的可扩展性。所以这里我采用了内核模块的方法。
一个内核模块应该至少包含两个函数:初始化函数(init)和清理函数(cleanup)。初始函数负责完成一些初始化的工作,在内核模块被insmod装载时调用;而清理函数则负责干一些收尾清理的工作,在内核模块被rmmod卸载时被执行。
模块初始化流程如下:
模块清理流程如下:
③ 获得系统调用表地址
系统调用表(sys_call_table)是用来存放内核中各个系统调用处理函数入口地址的一个数组,因此只要获得系统调用表的地址,我们就可以修改系统调用函数,甚至替换原先的系统调用函数。在这一节,我们要做的事就是找到sys_getdents()的入口地址,并用hacked_getdents()的地址进行替换。
出于安全方面的考虑,Linux从2.4.18内核以后就不再导出系统调用表,因此要修改系统调用,必须从软件上获取系统调用表的地址。由于不同CPU架构的系统获取系统调用表的方式不一样,这里以我自己的系统(x86_64)为例,系统调用表地址获取流程如下:
说明:
a)由于内核的页标记为只读,尝试用函数去写这个区域的内存,会产生一个内核oops。这种保护可以很简单的被规避,可通过设置cr0寄存器的WP位为0,禁止写保护CPU。
b)Linux x86_64有两套调用模式:Long模式和兼容模式,分别对应有两套调用表:sys_call_table,ia32_sys_call_table。实验中采用Long模式的系统调用表。
使用grep命令从系统映射表中获取sys_call_table的地址,其中红框中标出的是系统调用表的地址,可以看到,系统调用表的地址是ffffffff81a00180。
c)Long方式使用syscall,MSR寄存器地址为0xc0000082,宏MSR_LSTAR来代表. 使用rdmsrl指令获取system_call的代码段起始地址,再通过system_call获取sys_call_table特征码。x86_64下获取sys_call_table与x86特征码不同,是"\xff\x14\xc5"。
④ 劫持系统调用
在获得系统调用表的地址后,我们就可以对原先的系统调用进行替换了。系统调用
sys_getdents()的入口地址保存在数组sys_call_table以__NR_getdents为偏移的位置上。我们定义一个函数指针orig_getdents,用于存放原始的sys_getdents()系统调用,其定义如下:
asmlinkage long (*orig_getdents)(unsigned int, struct linux_dirent64 __user *, unsigned int);
替换过程如下:
/* 保存原始系统调用 */
orig_getdents = sys_call_table[__NR_getdents];
/* 替换原始系统调用 */
sys_call_table[__NR_getdents] = hacked_getdents;
恢复系统调用的代码如下:
/* 恢复原始系统调用 */
sys_call_table[__NR_getdents] = orig_getdents ;
编写完内核模块后,建立Makefile:
接着编译、链接:
使用insmod hook.ko挂载模块,rmmod hook卸载模块
测试结果:
将写好的内核模块加载入内核,可以看到,内核模块获得的系统调用表地址与使用grep命令获得的系统调用表地址一致。
编译好内核模块后,运行我们的测试程序(测试程序与方法一所用相同),所得结果如下:
CRUX下实现进程隐藏(2)的更多相关文章
- CRUX下实现进程隐藏(1)
想必能找到这里的都是被吴一民的操作系统大作业坑过的学弟学妹了,当初我也是千辛万苦才把这个作业完成了,本着服务后辈的宗旨,尽量让学弟学妹少走弯路,我会把实现的大概思路记录下来.本系列一共三篇文章,分别实 ...
- CRUX下实现进程隐藏(3)
通过一个内核模块拦截文件系统的回调函数来实现进程隐藏. VFS(Virtual File System)是Linux在实际文件系统(如ext3,ext4,vfat等)上抽象出的一个文件系统模型,简单来 ...
- Linux下进程隐藏的方法及其对抗
零.背景 在应急响应中,经常碰到ps命令和top命令查不到恶意进程(异常进程)的情况,会对应急响应造成很大的影响.轻则浪费时间,重则排查不出问题,让黑客逍遥法外.所以这篇博客研究学习如何对抗linux ...
- SSDT Hook实现简单的进程隐藏和保护【转载】
原文链接:http://www.blogfshare.com/ssdthook-hide-protect.html 原文作者:AloneMonkey SSDT Hook实现简单的进程隐藏和保护 Alo ...
- 进程隐藏与进程保护(SSDT Hook 实现)(二)
文章目录: 1. 引子 – Demo 实现效果: 2. 进程隐藏与进程保护概念: 3. SSDT Hook 框架搭建: 4. Ring0 实现进程隐藏: 5. Ri ...
- 在CMD命令行下关闭进程的命令
转载: [重要]在CMD命令行下关闭进程的命令━━━━━━━━━━━━━━━━━━━━━━━━━━ 方法一: 在"运行"中输入:ntsd -c q -pn 程序名字(在MS-Dos ...
- Windows2003 内核级进程隐藏、侦测技术
论文关键字: 内核 拦截 活动进程链表 系统服务派遣表 线程调度链 驱动程序简介 论文摘要:信息对抗是目前计算机发展的一个重要的方向,为了更好的防御,必须去深入的了解敌人进攻的招式.信息对抗促使 ...
- Driver 01 进程隐藏
大二时候的代码以及笔记,当时暂时记录在QQ上在,现在发出来分享一下. 为了写驱动装一大堆的软件插件啥的,还常常失败. 这里就顺带总结下SDK下载和WinDbg symbol路径设置正确WinDbg却总 ...
- 进程隐藏与进程保护(SSDT Hook 实现)(三)
文章目录: 1. 引子: 2. 获取当前系统下所有进程: 3. 服务管理(安装,启动,停止,卸载): 4. 应用程序和内核程序通信: 5. 小结: 1. 引子: 关于这个 SSDT Hook 实现进程 ...
随机推荐
- UVA 11468 AC自动机入门题 记忆化概率dp+ac自动机
/** 链接:https://vjudge.net/problem/UVA-11468 详见lrj训练指南P218 我的是反向求存在模板串的概率. dp[i][j]表示当前i位置选择字符,前面i-1个 ...
- SGU 120 Archipelago (简单几何)
120. Archipelago time limit per test: 0.25 sec. memory limit per test: 4096 KB Archipelago Ber-Isla ...
- iOS错误整理--自定义按钮,给按钮内部赋值出现的错误
一.练习中为了实现自定义按钮,按钮中的imageView和titleLabel默认是左右排列的.在练习中自定义为上下排列. *在以下方法中重新布局按钮中的子控件 - (void)layoutSubvi ...
- python + opencv: kalman 跟踪
之前博文中讲解过kalman滤波的原理和应用,这里用一个跟踪鼠标的例程来演示怎么在opencv里用自带的kalman函数进行目标跟踪,文章的内容对做图像跟踪有借鉴意义.文章主要是网络资源进行整理和简单 ...
- 【F12】修改 DevTools的主题
1.点击setting
- 在Terminal中的光标的使用技巧
如何简单操作? 在 Terminal(终端) 中,有许多操作技巧,这里就介绍几个简单的. 光标 up(方向键上) 可以调出输入历史执行记录,快速执行命令 down(方向键下) 配合 up 选择历史执行 ...
- struts2将数据通过Json格式显示于EasyUI-datagrid数据表格
1.搭建ssh开发环境 2.写好Dao.service等方法 3.建立DTO数据传输对象: package com.beichende.sshwork.user.web.dto; import jav ...
- HTML5的表单所有type类型
1.button:定义可点击的按钮(通常与 JavaScript 一起使用来启动脚本).<br /> <input id="" type="button ...
- vc 获取 硬盘序列号 和 cpu
vc 获取 硬盘序列号 和 cpu 唯一iD的方法?如题---------网上找来很多资料 也没找到, 要支持xp win7 32/64 系统下都能获取 硬盘序列号 和cpu ID 哪位朋友帮帮忙: ...
- 第五章 使用 SqlSession(MyBatis)
在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession.一旦你获得一个 session 之后,你可以使用它来执行映射语句,提交或回滚连接,最后,当不再需要 ...