kernel环境配置


记录一下配置kernel环境过程中遇到的一些问题

内核

内核下载

网上一些文章用的清华源,但是现在好像…

<p lang="zh-cn">我们检测到您所在的子网和/或所使用的客户端存在大量下载某些较大二进制文件的行为,为保证用户的正常使用,我们阻断了此类请求。</p>

所以网上找到了其他下载https://cdn.kernel.org/pub/linux/kernel/v5.x/#/,不过因为感觉下载的好慢,直接在`windows`上下载了拖进虚拟机了

curl -O -L https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.98.tar.xz
unxz linux-5.4.98.tar.xz
tar -xf linux-5.4.98.tar

这样就得到了内核源码,因为长期版稳定便于学习所以选择了5.4.98版本的内核

内核编译

直接make报错了

☁  linux-5.4.98  sudo make menuconfig                                                     
[sudo] starrysky 的密码: 
  LEX     scripts/kconfig/lexer.lex.c
/bin/sh: 1: flex: not found
make[1]: *** [scripts/Makefile.host:9:scripts/kconfig/lexer.lex.c] 错误 127
make: *** [Makefile:590:menuconfig] 错误 2

需要先安装flexbison

sudo apt-get install flex
sudo apt-get install bison

进入菜单,在菜单中选择Kernel hacking -> Compile-time checks and compiler options并且勾选Compile the kernel with debug info,全选Kernel debugging中全部内容

☁  linux-5.4.98  sudo make menuconfig       

开始编译内核

sudo make -j 4  bzImage

其中会遇到一些问题,解决方法:

  • .config9868行置空(不删除此行

    CONFIG_SYSTEM_TRUSTED_KEYS=""
  • 安装libelf-devdwarves

    sudo apt-get install libelf-dev
    sudo apt install dwarves

最后显示如下内容表示编译成功

Setup is 18044 bytes (padded to 18432 bytes).
System is 15045 kB
CRC 815d9126
Kernel: arch/x86/boot/bzImage is ready  (#2)

在编译成功后,我们一般主要关注于如下的文件

  • bzImagearch/x86/boot/bzImage
  • vmlinux:源码所在的根目录下。

常见内核文件的介绍:

  • bzImage:目前主流的 kernel 镜像格式,适用于较大的(> 512 KBKernel。这个镜像会被加载到内存的高地址(高于 1MB)。bzImage 是用 gzip 压缩的,不能用 gunzip 来解压
  • zImage:比较老的 kernel 镜像格式,适用于较小的Kernel。启动时,这个镜像会被加载到内存的低地址,即内存的前 640 KBzImage 也不能用 gunzip 来解
  • vmlinuzvmlinuz 不仅包含了压缩后的 vmlinux,还包含了 gzip 解压缩的代码。实际上就是 zImage 或者 bzImage 文件。该文件是 bootable 的,即它能够把内核加载到内存中。对于 Linux 系统而言,该文件位于 /boot 目录下,该目录包含了启动系统时所需要的文件
  • vmlinux:静态链接的 Linux kernel,以可执行文件的形式存在,尚未经过压缩。该文件往往是在生成 vmlinuz 的过程中产生的。该文件适合调试,但不是 bootable
  • vmlinux.bin:也是静态链接的 Linux kernel,只是以一个可启动的 (bootable) 二进制文件存在。所有的符号信息和重定位信息都被删除了。生成命令为:objcopy -O binary vmlinux vmlinux.bin
  • uImageuImageU-boot 专用的镜像文件,它是在 zImage 之前加上了一个长度为 0x40tag 而构成的。这个 tag 说明了这个镜像文件的类型、加载位置、生成时间、大小等信息

编译内核驱动

c语言源码pwn.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL");
static int ko_test_init(void) {
    printk("This is a test ko!\n");
    return 0;
}
static void ko_test_exit(void) {
    printk("Bye Bye~\n");
}
module_init(ko_test_init);
module_exit(ko_test_exit);

Makefile文件

obj-m += pwn.o

KDIR =/home/starrysky/kernel/linux-5.4.98

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	rm -rf *.o *.ko *.mod.* *.symvers *.order

其中obj-m指定了要声称的模块,后面接c源码文件名.oKDIR为内核源码路径

$(MAKE) -C $(KDIR) M=$(PWD) modules

-C 表示进入到指定的内核目录

M 指定驱动源码的环境,M并不是 Makefile 的选项,而是内核根目录下 Makefile 中使用的变量。这会使得该 Makefile 在构造模块之前返回到 M 指定的目录,并在指定的目录中生成驱动模块

最后运行sudo make编译内核驱动

☁  pwn  ls
Makefile  modules.order  Module.symvers  pwn.c  pwn.ko  pwn.mod  pwn.mod.c  pwn.mod.o  pwn.o

虽然正常人不会这样但是要注意文件名不要用make(嗯我就是那个非正常人类

Qemu 模拟环境

准备

安装qemubusybox

sudo apt install qemu
wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2
tar -jxf busybox-1.32.1.tar.bz2

配置busybox,在 Setttings 选中 Build static binary (no shared libs),将 busybox 编译为静态链接的文件;在 Linux System Utilities 中取消选中 Support mounting NFS file systems on Linux < 2.6.23 (NEW);Networking Utilities 中取消选中 inetd,最后编译

make menuconfig
make -j 8

配置文件系统

使用 make install命令,将生成文件夹_install,该目录将成为 rootfs,在该文件夹下创建文件夹

mkdir -p  proc sys dev etc/init.d

再创建一个init文件

#!/bin/sh
echo "INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
echo -e "Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack setuidgid 0 /bin/sh

打包文件系统

find . | cpio -o --format=newc > ../rootfs.img
# 解包命令
# cpio -idmv < rootfs.img

启动内核

脚本如下,bzImage就是之前内核里的bzImage,rootfs.img是打包文件系统时(上一步)创建的,nographic关闭了图形界面,console=ttyS0将输出重定向到了终端

#!/bin/sh
qemu-system-x86_64 \
  -nographic \
  -kernel ../arch/x86/boot/bzImage \
  -initrd ./rootfs.img \
  -append "console=ttyS0 kaslr" \

这样就启动好了

INIT SCRIPT
Boot took 6.24 seconds
/ # ls
bin      etc      linuxrc  root     sys      usr
dev      init     proc     sbin     tmp

加载驱动

将之前写的驱动复制到_install文件夹下,改一下init文件

#!/bin/sh
echo "INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
insmod /1.ko
echo -e "Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack setuidgid 0 /bin/sh

重新打包再运行,可以看到加载成功了,显示了This is a test ko!

INIT SCRIPT
[    6.129377] pwn: loading out-of-tree module taints kernel.
[    6.133147] pwn: module verification failed: signature and/or required key missing - tainting kernel
[    6.147188] This is a test ko!
Boot took 6.13 seconds

调试分析

基本操作

查看装载的驱动

lsmod

获取驱动加载的基地址

grep target_module_name /proc/modules 

启动调试

在启动脚本里加-s,表示-gdb tcp::1234

#!/bin/sh
qemu-system-x86_64 \
  -nographic \
  -kernel ../arch/x86/boot/bzImage \
  -initrd ./rootfs.img \
  -append "console=ttyS0 kaslr" \
  -s

启动之后gdb连接上去调试

gdb -q -ex "target remote localhost:1234"

连接成功

pwndbg: loaded 147 pwndbg commands and 47 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
Remote debugging using localhost:1234
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0xffffffffa1dfea1e in ?? ()
------- tip of the day (disable with set show-tips off) -------
Use GDB's dprintf command to print all calls to given function. E.g. dprintf malloc, "malloc(%p)\n", (void*)$rdi will print all malloc calls
Permission error when attempting to parse page tables with gdb-pt-dump.
Either change the kernel-vmmap setting, re-run GDB as root, or disable `ptrace_scope` (`echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`)
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA

参考文章

https://www.z1r0.top/2021/10/21/%E5%86%85%E6%A0%B8%E4%B8%8B%E8%BD%BD%E4%B8%8E%E7%BC%96%E8%AF%91/#/

https://ctf-wiki.org/pwn/linux/kernel-mode/environment/readme/#/


  目录