自学内容网 自学内容网

1简介和工作流程_Linux_Rootkit.md

Linux Rootkit 第 1 部分:简介和工作流程

2020-08-25 :: TheXcellerator

# linux # rootkit

了解 Linux rootkit 是了解更多内核工作原理的好方法。它的伟大之处在于,除非您真正了解内核在做什么,否则您的 rootkit 不太可能起作用,因此它可以作为一个神奇的验证器。

在 FreeBSD 世界中,您可以找到 Joseph Kong 的精彩著作Designing BSD Rootkits。它是 2009 年编写的,所以实际上已经相当过时了——这意味着您必须做大量的研究才能让示例程序在现代 FreeBSD 上运行。这种学习经验对于学习内核 rootkit 非常宝贵,但遗憾的是 Linux 内核并不像 FreeBSD 内核那样开放和无忧无虑。使用内核模块将运行代码放入内核的基本思想是相同的,并且是这些博客文章的重点。

当我尝试将我所学到的 FreeBSD 知识应用到 Linux 上时,我发现资源相当短缺,不得不将来自许多不同来源的许多不同的东西放在一起。这些博客文章希望能够向其他希望了解更多有关内核工作原理的人展示我所学到的有关 Linux 内核 rootkit 设计的知识!

我的想法是,我将从内核 rootkit 是什么以及我在开发过程中使用的工作流程开始。接下来,我将描述挂钩不同内核函数所涉及的主要技术 - Ftrace(它比看起来更容易 - 别担心!)。一旦解决了这个问题,我将介绍内核 Rootkit 使用的实际技术:对用户隐藏目录、端口和进程,授予 root 权限,甚至完全隐藏 Rootkit 的存在。

什么是内核模式 Rootkit?

那么,内核 rootkit 到底有什么作用呢?维基百科将 rootkit 定义为:

“Rootkit 是计算机软件的集合,通常是恶意的,旨在允许访问计算机或其软件的某个区域(例如,未经授权的用户),并且经常掩盖其存在或其他程序的存在。软件。”

当然,作为内核rootkit 意味着我们编写的代码将通过我们将编写的内核模块以内核级权限(ring 0)运行。这可能是一把双刃剑:我们所做的事情对于用户和用户空间工具来说是不可见的,但如果我们搞砸了一些事情,我们很可能会导致系统崩溃,因为内核无法将我们从自身手中拯救出来!这使得虚拟机中的开发成为一项相当困难的要求 - 幸运的是,我们将使用Vagrant将麻烦降到最低。

在非常高的层面上,内核 rootkit(以及用户空间 rookits,但那是另一篇文章)的主要技术是函数挂钩。本质上,我们在内存中使用一个函数来执行我们想要影响的一些操作(列出目录内容、向进程发送信号等)并编写我们自己的版本。此过程的一部分涉及保存原始函数的副本,我们仍然可以实现正常功能而无需重写它。然后我们必须找到一种方法将我们的新功能“注入”到内核中,以便内核继续“正常”运行(也就是没有任何外部迹象向用户表明出现问题 - 比如崩溃!)。

正如你可能想象的那样,在 Linux 中,剥猫皮的方法总是不止一种,函数挂钩也不例外。我将重点介绍的方法(如上所述)称为Ftrace ,是下一篇博客文章的主要主题。

Rootkit 开发工作流程

这一切都很好,但在我们继续学习修改内核内存的精确方法以及如何编写钩子函数之前,我们需要对工作流程进行排序。

如前所述,我们首先需要的是虚拟机。你可以自由地使用 VirtualBox 或其他你喜欢的东西,但在这个过程中我发现了Vagrant。如果您已经安装了 VirtualBox,那么 Vagrant 将自动使用它进行虚拟化,无需任何配置。

Vagrant 使用当前目录来存储当前虚拟机的配置。如果您需要另一个虚拟机,请创建一个新目录并再次运行 vagrant!让您了解 vagrant 是多么容易:

vagrant init generic/ubuntu2004
vagrant up
vagrant ssh

就这样,我正在 Ubuntu 20.04 VM 中查看 bash 提示符!然后vagrant upload ~/.sshvagrant upload ~/.vimrc我们的生活变得更轻松。

不管怎样,一旦进入虚拟机,您将需要一些东西。我将以 Ubuntu 20.04 为基础来编写本教程(如果您不使用 Ubuntu,那么我相信您可以找出要进行的更改)。确保您的系统已完全更新(包括任何内核更新!),然后进行常规操作apt update; apt install git build-essential linux-headers-$(uname -r)(git 是可选的,但强烈推荐!)。完成后,我们可以考虑构建一个简单的内核模块。

构建内核模块

让我们看一下下面的 C 代码(最好将其放入文件中,因为我们很快就要构建它!)。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("TheXcellerator");
MODULE_DESCRIPTION("Basic Kernel Module");
MODULE_VERSION("0.01");

static int __init example_init(void)
{
    printk(KERN_INFO "Hello, world!\n");
    return 0;
}

static void __exit example_exit(void)
{
    printk(KERN_INFO "Goodbye, world!\n");
}

module_init(example_init);
module_exit(example_exit);

复制

这与内核模块一样简单 - 我们将逐行进行介绍。

首先,我们有几个#include总是需要的,然后是一些宏,这些宏包含有关模块功能的一些细节。当我们稍后将模块加载到内存中时,内核将提供此信息。

接下来我们有两个非常重要的函数将始终存在。该example_init函数在模块加载和example_exit卸载后执行。最后两行向编译器声明example_initexample_exit所具有的角色。(您可以随意命名这两个函数,只要在它们的声明中保留__init__exit并更改最后两行即可)。

所有这些函数(目前!)都是将printk()字符串发送到内核缓冲区(您可以看到 using 的内容dmesg)。这个printk()函数很像更熟悉的printf(),除了我们总是KERN_*从定义消息的日志级别的宏开始(请参阅此处了解所有可能的日志级别)。我们几乎总是使用KERN_INFOKERN_DEBUG。请注意,该宏不像字符串的其余部分那样属于引号!我们也欢迎使用格式字符串,printk()就像printf()我们在调试时从内核中提取数据的主要方法一样。

好吧,这很简单,对吧?但我们如何编译它呢?我们使用以下 Makefile:

obj-m += example.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

复制

假设您已经命名了 C 源代码example.c(否则将example.o顶行更改为您所命名的任何其他名称),那么只需运行make就会为您提供一堆新的中间二进制文件,但最重要的是您将example.ko在其中获得一个闪亮的新文件。

example.ko是您新构建的内核模块(.ko用于内核对象)!要将其加载到正在运行的内核中(始终在虚拟机上执行此操作,直到确定一切正常!),只需运行# insmod example.ko. 现在,如果您检查dmesg,您应该会看到“Hello, world!” 线!要删除内核模块,只需运行(请注意,当我们卸载模块时# rmmod example没有),您将看到内核缓冲区中出现再见消息。.ko

您可以在我的 GitHub 存储库xcellerator/linux_kernel_hacking上找到所有这些内容以及更多内容的源代码。具体来说,这个基础模块就在这里

恭喜!您刚刚构建并加载了您的第一个 Linux 内核模块!当然,它实际上并没有做太多事情,但这就是接下来的几篇博客文章要做的事情。下次的计划是介绍 Ftrace,这是我们将用来挂钩内核函数的工具。

任何时候你构建一个 Linux 内核模块,它都是特定于它所构建的内核版本的。如果您尝试获取一个模块并将其加载到具有不同内核的系统上,它很可能会加载失败。

现在进入第 2 部分

直到下一次…

阅读其他帖子


系统上,它很可能会加载失败。

现在进入第 2 部分

直到下一次…

阅读其他帖子


←即将推出!BootNoodle:BGGP 的回文引导加载程序→


原文地址:https://blog.csdn.net/qq_55125921/article/details/136003033

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!