> For the complete documentation index, see [llms.txt](https://lightc.gitbook.io/pwn-gitbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lightc.gitbook.io/pwn-gitbook/kpwn/kpwn-setup/nei-he-yuan-ma-bian-yi.md).

# 内核源码编译

在 [Linux Kernel Archive](https://www.kernel.org/) 下载对应版本的内核源码

```bash
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.11.tar.xz
tar -xvf linux-5.11.tar.xz
cd linux-5.11.1/
make menuconfig
```

勾选

* `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`

编译

```bash
make -j$(nproc) bzImage
```

在 `arch/x86/boot/` 目录下提取到 `bzImage`，为压缩后的内核文件

## Busybox 文件系统

再下载 `busybox` 构建文件系统，在 [busybox.net](https://busybox.net/downloads/) 下载版本

```bash
wget https://busybox.net/downloads/busybox-1.33.0.tar.bz2
tar -jxvf busybox-1.33.0.tar.bz2
cd busybox-1.33.0/
make menuconfig
```

勾选 `Settings` —> `Build static file (no shared libs)`

```bash
make install
cd _install
mkdir -pv {bin,tmp,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`

```vim
::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`

```bash
sudo cat <<EOF > etc/init.d/rcS
#!/bin/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
EOF
```

配置用户组

```bash
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
```

打包文件系统

```bash
find . | cpio -o --format=newc > ../rootfs.cpio
```

解包文件系统

```bash
mkdir rootfs
cd rootfs
cpio -idv < ../rootfs.cpio
```

## QEMU 运行内核

`bzImage` 和 `rootfs.cpio` 放到同一个目录下，然后编写 `sh` 脚本

```vim
#!/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`
>
> `console=ttyS0`：指定终端为 `/dev/ttyS0`，这样一启动就能进入终端界面
>
> `-monitor`：将监视器重定向到主机设备 `/dev/null`，这里重定向至 `null` 主要是防止 `CTF` 中被人给偷了 `qemu` 拿 `flag`
>
> `-cpu`：设置 CPU 安全选项，在这里开启了 `smep` 保护（`smep` 保护就不能采用 `ret2usr` 手法了）
>
> `-s`：相当于 `-gdb tcp::1234` 的简写（也可以直接这么写），后续我们可以通过 `gdb` 连接本地端口进行调试
>
> `-S`：与`-s`不同的是，只有连接到`gdb`后才会加载内核
