Kernel Linux学习(一)——环境搭建
Kernel Linux学习——环境搭建
2020-08-02 20:14:19 hawkJW
因为最近信息安全竞赛中经常出现Kernel Linux相关方面的习题,因此正好通过疫情这段时间学习一下Kernel Linux相关的知识。
这一此主要介绍Kernel Linux的环境的搭建。分别需要Linux的源代码、Busybox的源代码、以及qemu模拟器
总体分析
实际上,Linux的启动首先一定需要内核程序——其通过Linux的源代码进行下载,编译即可。
除此之外,Linux的启动还需要根文件系统支持,因为当系统启动时,仅仅只有内核程序,需要从磁盘中加载各种模块,而这个过程需要文件系统;如果文件系统放置在磁盘中,这就成为了一个鸡生蛋、蛋生鸡的问题。因此,即在RAM上建立临时文件系统,即根文件系统,当所需模块加载完毕后再将根文件系统转移到磁盘上即可。这里通过Busybox进行构建。
最后,如果在真机上直接进行运行,如果中间出现错误或者异常,则整个系统直接奔溃,对于运行或者调试都不方便。因此,通过模拟器运行并调试。
Linux内核
我们首先需要下载Linux内核源代码,然后进行编译即可,其源代码的镜像文件如下链接所示https://mirrors.tuna.tsinghua.edu.cn/kernel/。我们进行下载即可,这里我选择了V4.x的4.4.72版本。
当然,安装过程中可能会有一些依赖问题,我这里一并包括qemu等更新安装,代码如下所示
sudo apt-get install qemu build-essential libssl-dev kernel-package libncurses5-dev bison flex
ubuntu20.04系统貌似好像还要单独安装qemu-system,方法类似上面的。
这里等待一段时间后,我们将下载的源代码文件进行解压,并进入对应的目录,代码如下所示
tar xf /path/to/linux-src.tar.gz rm -rf /path/to/linux-src.tar.gz mv /path/to/linux-src linux cd linux
然后我们需要进行编译的配置,执行如下命令
make menuconfig
此时会进入编译配置的gui界面,然后我们依次选择如下的配置
——进入kernel hacking ——进入Compile-time checks and compiler options ——选择Compile the kernel with debug info ——选择Compile the kernel with frame pointers ——选中Kernel Debugging ——选中KGDB:Kernel Debugging ——关闭Write protect kernel read-only data structures
退出保存后,执行如下命令
make -j 4
这样子即完成了Kernel Linux的内核编译部分。
根文件系统编译
下面我们将构建根文件系统,我们这里通过BusyBox来快速构建根文件系统。我们首先进行busybox的编译,其源代码的镜像链接如下图所示https://busybox.net/downloads/,这里我们选择(1.27.2版本)。下载完后进行如下的命令
tar -xf /path/to/busybox-1.27.2.tar.bz2
rm -rf /path/to/busybox-1.27.2.tar.bz2
mv /path/to/busybox-1.27.2.tar.bz2 /path/to/busybox
下载并解压完毕后,我们进行编译的设置,命令如下所示
make defconfig make menuconfig
此时进入GUI界面后,我们选择如下配置
进入Busybox Settings
——选择Build BusyBox as a static binary(no shared libs)
退出保存后,执行如下命令
make -j 4
make install
这样子即完成了busybox的编译工作。然后我们继续构建根文件系统。根据一些网络资料,根文件系统至少需要包含所有支持完整Linux系统的结构和程序,目前至少需要
1. 基础文件系统结构 2. 必须的目录——/dev、/bin、/etc等
3. 必须的程序——init等 4. 必须的配置文件——inittab等6. 配置文件所需要的库文件
我们创建一个目录,用来作为根文件系统的雏形,我们需要向目录内部填充数据,下面我们需要向该目录中写入构建根文件目录的内容——/dev、/proc、/etc、/sbin、/bin、/lib、/sys、/mnt以及/usr文件(有一些可以不用),其中,/proc、/mnt文件仅仅需要建立即可,内容可以为空,其构建的命令如下所示
mkdir rootfs
cd rootfs
mkdir proc mkdir mnt
mkdir sys
mkdir tmp
对于/usr、/sbin以及/bin,直接将busybox编译后的文件全部赋值即可,命令如图所示
cp -r ../busybox/_install/* ./
而/dev文件包含所有设备文件,通过mknod命令创建设备文件。这里我们并不尝试创建设备文件,因此将设置为空即可。
ls -al /dev/
/etc文件中包含各种设置文件,这里我们构建inittab、init.d/rcS和fstab文件。
其中inittab文件指挥init进行进行工作,其内容如下
#/etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::shutdown:/bin/umount -a -r
稍微分析一下该文件的含义,所有的/etc/inittab每一行相当于一个脚本,其内容类似于id:runlevel:action:precess
这里第一行表示初始化时执行/etc/init.d/rcS文件内容;第二行表按键后进入shell;第三行表示当关闭时umount所有挂载的文件。
可以看到,其中第一句中执行了/etc/init.d/rcS文件,则我们需要填充完善/etc/init.d/reS文件,其内容如下所示
#!/bin/sh mount -a
注意需要给其可执行权限。这里面的内容很简单,就是挂载所有的文件系统,至于具体如何进行挂载,其按照/etc/fstab文件中所描述的进行挂载,内容如下所示
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
这里我们需要详细说明一下挂载这个概念。实际上如果你并没有再fstab中写这些规则,也就是并没有进行如下的挂载,但是你仍然可以按照下面的流程进行内核的启动,并且仍然可以在linux中看到这两个目录,如下图所示
但是如果您进行了上述的挂载,然后再去观察,结果如图所示
实际上,根据这个实验结果,并且配合上一些相关的网络资料,我们很容易就可以对于挂载这个概念有更深刻的了解。整个文件系统实际上相当于这样一个数据结构
union fileSystem{ memory data; union fileSystem *next; }
如果没有进行挂载,则显示其fileSystem.data中的数据;如果挂载了话,则显示fileSystem.next中指向的数据。所以我们可以对上述现象进行合理解释——首先正如上面分析的,一定会挂载根目录,也就是这里我们创建的这些目录;如果没有挂载,则显示的就是目前信息(空);如果进行了挂载,则显示挂载的信息——这里可能有人会问,那这里挂载的信息是什么?这里一开始我也不清楚,根据我在网络上的资料,实际上其挂载的内容是Linux内核中的一些相关信息,也就是如果你不挂载,这些信息仍然存在,但你无法查看和操作,而挂载之后,你可以直接进行查看和操作。我们可以再做个实验,如果我们在一开始的sys目录下放一个README.md文件,则如果不进行挂载的话,应该会显示该文件,结果如图所示
这样子,我们基本完成了目录中的数据填充,然后我们将其打包为qemu可以直接使用的根目录文件格式,命令如下
find . | cpio -o --format=newc > ../rootfs.img
这里顺便说一句,cpio同样可以解压出来,其命令如下
mkdir rootfs cd rootfs cpio -idmv < ../rootfs.img
这样子,就将前面压缩的文件重新解压到rootfs目录中
最后,就完成了根文件系统的制作
启动内核
下面,我们即利用qemu,模拟Linux内核的启动,我们需要指定一下linux内核、根文件系统以及一些设置即可,-initrd后面跟的就是根文件系统,命令如下
qemu-system-x86_64 -kernel linux/arch/x86_64/boot/bzImage -initrd rootfs.img -append "rdinit=/linuxrc"