最近脑子一抽决定看《深入理解 Linux 内核》,后面又抽多了几下想试试 kernel pwn,于是开始痛苦地配环境
目前姑且算是完成了第零步 甚至还不是第一步,过程磕磕绊绊 还留下一堆坑没解决,总之先记录一下 以免后面忘了
先摆上参考的文章
编译内核
先装环境依赖
sudo apt-get update
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils qemu flex libncurses5-dev libssl-dev bc bison libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev libelf-dev
编译内核
获取源码
在 Linux Kernel Archive 下载对应版本的内核源码
以 kernel-5.11 为例
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.11.tar.xz
解压
tar -xvf linux-5.11.tar.xz
编译选项配置
进入源码文件夹,执行如下命令开始配置编译选项并进入配置页面
make menuconfig
配置页面通过上下键移动配置选项,左右键移动功能界面功能选项,y 键选定选项,空格或回车进入次级目录
勾选以下配置:
- Kernel hacking -> Kernel debugging
- Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with debug info
- Kernel hacking -> Generic Kernel Debugging Instruments -> KGDB: kernel debugger
kernel hacking -> Compile the kernel with frame pointers(似乎没有)
也可以根据你的需求手动更改一些编译选项,此是后话
通常保存的路径在当前目录下的 .config
文件中,如果你在生成配置文件后才想起来忘了改某个选项也可以直接编辑这个文件
编译
make -j$(nproc) bzImage
- 用 WSL 编译很慢,中途还崩溃了
- 改用实验室的工作站编译就嘎嘎快,十分解压(?)
编译结果
出现如下信息则说明编译完成
Kernel: arch/x86/boot/bzImage is ready (#1)
主要生成两个文件
当前目录下的 vmlinux 为编译出来的原始内核文件/arch/x86/boot
目录下的 bzImage 为压缩后的内核文件,适用于大内核
下载内核镜像
如果不想花太多时间配置和编译,也可以下载现成的内核镜像文件
搜索可用镜像文件(会比现有的版本滞后些)
sudo apt search linux-image-
下载镜像文件,以 kernel-5.8.0 为例
sudo apt download linux-image-5.8.0-43-generic
使用系统内核镜像
还可以使用/boot
目录下现成的系统内核镜像(原生 WSL 没有 kernel)
制作文件系统
BusyBox 是一个封装了 Linux 下大部分常用命令的软件,具体可以看 JYY 的 OS 课(关注 JYY 谢谢喵)
我们可以利用 BusyBox 为 kernel 制作一个基本的用户环境
获取源码
在 busybox.net 下载对应版本
以 busybox-1.33.0 为例
wget https://busybox.net/downloads/busybox-1.33.0.tar.bz2
解压
tar -jxvf busybox-1.33.0.tar.bz2
编译
进入配置界面配置编译选项
make menuconfig
勾选 Settings
-> Build static binary file(no shared lib)
来静态编译,以免后面还要配置 libc
取消选中Networking Utilities -> inetd
编译
make install
编译完成后生成一个_install
目录,将会用它来构建磁盘镜像
构建文件系统
初始化目录文件
建立一些系统启动所需的目录和文件
cd _install
mkdir -pv {bin,sbin,etc,proc,sys,home,lib64,lib/x86_64-linux-gnu,usr/{bin,sbin}}
touch etc/inittab
mkdir etc/init.d
touch etc/init.d/rcS
chmod +x ./etc/init.d/rcS
配置初始化脚本
配置/etc/inittab
,其指定了系统初始化脚本为/etc/init.d/rcS
::sysinit:/etc/init.d/rcS
::askfirst:/bin/ash
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
配置/etc/init.d/rcS
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
mount -t tmpfs tmpfs /tmp
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
setsid cttyhack setuidgid 1000 sh
poweroff -d 0 -f
也可以在根目录下创建init
文件
touch init
chmod +x ./init
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
poweroff -d 0 -f
配置用户组
echo "root:x:0:0:root:/root:/bin/sh" > etc/passwd
echo "ctf:x:1000:1000:ctf:/home/ctf:/bin/sh" >> etc/passwd
echo "root:x:0:" > etc/group
echo "ctf:x:1000:" >> etc/group
echo "none /dev/pts devpts gid=5,mode=620 0 0" > etc/fstab
配置 glibc
暂时用不上,还没弄
打包 cpio 镜像
find . | cpio -o --format=newc > /path/to/rootfs.cpio
QEMU 运行内核
配置启动脚本
将 bzImage 和 rootfs.cpio 放到同一个目录下
编写启动脚本
touch boot.sh
#!/bin/sh
qemu-system-x86_64 \
-m 128M \
-kernel ./bzImage \
-initrd ./rootfs.cpio \
-monitor /dev/null \
-append "root=/dev/ram rdinit=/sbin/init console=ttyS0 oops=panic panic=1 loglevel=3 quiet kaslr" \
-cpu kvm64,+smep \
-smp cores=2,threads=1 \
-nographic \
-s
部分参数说明如下:
-m
:虚拟机内存大小-kernel
:内存镜像路径-initrd
:磁盘镜像路径-append
:附加参数选项nokalsr
:关闭内核地址随机化,方便我们进行调试rdinit
:指定初始启动进程,/sbin/init
进程会默认以/etc/init.d/rcS
作为启动脚本loglevel=3
&quiet
:不输出 log(loglevel=8
则可以看到比较完整的启动过程)console=ttyS0
:指定终端为/dev/ttyS0
,这样一启动就能进入终端界面
-monitor
:将监视器重定向到主机设备/dev/null
,这里重定向至null主要是防止CTF中被人给偷了qemu拿flag-cpu
:设置CPU安全选项,在这里开启了smep保护-s
:相当于-gdb tcp::1234
的简写(也可以直接这么写),后续我们可以通过gdb连接本地端口进行调试
最后运行脚本即可
emmm……至少我看别人是可以了,但我这死活不行
报错1:启动到clocksource: Switched to clocksource tsc
就卡住不动了
解决办法:似乎是在配置 BusyBox 编译选项时取消选中Networking Utilities ->inetd
后就好了,我也不确定
报错2:No such file or directory
解决办法:似乎是启动脚本的问题,在删掉/etc/inittab
后就没再出现了,删除后/sbin/init
也会默认选择/etc/init.d/rcS
为启动脚本,所以似乎影响不大
报错3:can't open /dev/tty2 3 4: No such file or directory
解决办法:最神必的报错,虽然已经启动完成了但不停的报错十分影响我们正常使用,最后在根目录下的启动脚本init
中加上几行touch /dev/tty2 3 4
就好了
报错4:applet not found
解决办法:不影响使用,先不排查了
启动
./boot.sh
虽然解决报错的手段十分粗暴,而且很可能已经为后面埋下了隐患,但是也算是启动成功了,我哭死 TAT
Comments 1 条评论
博主 LJLsama
强者教教我:)