0%

Linux Kernel :Environment

Kernel环境搭建

内核文件类型

  • bzImage:目前主流的 kernel 镜像格式,即 big zImage(即 bz 不是指 bzip2),适用于较大的(大于 512 KB) Kernel。这个镜像会被加载到内存的高地址,高于 1MB。bzImage 是用 gzip 压缩的,文件的开头部分有 gzip 解压缩的代码,所以我们不能用 gunzip 来解压缩。

  • zImage:比较老的 kernel 镜像格式,适用于较小的(不大于 512KB) Kernel。启动时,这个镜像会被加载到内存的低地址,即内存的前 640 KB。zImage 也不能用 gunzip 来解压缩。

    1
    2
    3
    4
    zImage && bzImage
    ---------------- difference ------------------
    zImage—是vmlinux经过gzip压缩后的文件。
    bzImage—bz表示"big zImage",不是用bzip2压缩的,而是要偏移到一个位置,使用gzip压缩的。两者的不同之处在于,zImage解压缩内核到低端内存(第一个 640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么采用zImage或bzImage都行,如果比较大应该用bzImage。
  • vmlinuz:vmlinuz 不仅包含了压缩后的 vmlinux,还包含了 gzip 解压缩的代码。实际上就是 zImage 或者 bzImage 文件。该文件是 bootable 的。 bootable 是指它能够把内核加载到内存中。对于 Linux 系统而言,该文件位于 /boot 目录下。该目录包含了启动系统时所需要的文件。

  • vmlinux:静态链接的 Linux kernel,以可执行文件的形式存在,尚未经过压缩。该文件往往是在生成 vmlinuz 的过程中产生的。该文件适合于调试。但是该文件不是 bootable 的。

  • vmlinux.bin:也是静态链接的 Linux kernel,只是以一个可启动的 (bootable) 二进制文件存在。所有的符号信息和重定位信息都被删除了。生成命令为:objcopy -O binary vmlinux vmlinux.bin

  • uImage:uImage 是 U-boot 专用的镜像文件,它是在 zImage 之前加上了一个长度为 0x40 的 tag 而构成的。这个 tag 说明了这个镜像文件的类型、加载位置、生成时间、大小等信息。

source code

  • 查看当前内核版本

    注解:

    1. /proc文件系统,它不是普通的文件系统,而是系统内核的映像
    2. 该目录中的文件是存放在系统【内存】之中的,它以【文件系统】的方式为访问系统内核数据的操作提供接口。
    3. 而我们使用命令uname -a的信息就是从该文件获取的,当然用方法二的命令直接查看它的内容也可以达到同等效果.另外,加上参数”a”是获得【详细信息】,如果不加参数为查看系统名称。
    1
    2
    [Method 1] uname -a
    [Method 2] cat /proc/version
  • 查看整个系统剩余磁盘空间

    1
    df -hl
  • 查看[1]当前目录【总大小】,[2]指定目录大小,[3]当前目录下各文件、文件夹的大小

    1
    2
    3
    [1] du -sh
    [2] du -sh [目录名称]
    [3] du -h --max-depth=1 *

recently version

  • 清华源下载内核:https://mirrors.tuna.tsinghua.edu.cn/kernel/

  • 下载某个版本的核

    1
    2
    curl -O -L https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.4.98.tar.xz
    unxz linux-5.4.98.tar.xz

    此时得到的是.tar文件

  • 签名验证

    1
    curl -O -L https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.4.98.tar.sign

    导入Torvalds的公钥

    1
    gpg --locate-keys torvalds@kernel.org gregkh@kernel.org

    使用密钥(我们可以选择使用 TOFU 信任对应的密钥)并验证

    1
    2
    gpg --tofu-policy good 647F28654894E3BD457199BE38DBBDC86092693E
    gpg --trust-model tofu --verify linux-5.4.98.tar.sign

    最终得到验证结果

    1
    2
    3
    4
    5
    6
    gpg: assuming signed data in 'linux-5.4.98.tar'
    gpg: Signature made 2021年02月13日 星期六 20时54分47秒 CST
    gpg: using RSA key 647F28654894E3BD457199BE38DBBDC86092693E
    gpg: Good signature from "Greg Kroah-Hartman <gregkh@kernel.org>" [full]
    gpg: gregkh@kernel.org: Verified 1 signatures in the past 0 seconds. Encrypted
    0 messages.
  • 解压即可得到源码

    1
    tar -xf linux-5.4.98.tar

old version

编译和调试

工具准备

  • 环境

    1
    ubuntu20.04
  • 更新软件源

    1
    sudo apt-get update
  • 安装依赖

    1
    sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils qemu flex libncurses5-dev fakeroot build-essential ncurses-dev xz-utils libssl-dev bc bison libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev libelf-dev
  • 下载linux-5.11.tar.xz

    1
    wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.11.tar.xz
  • 解压

    1
    tar -xvf linux-5.11.tar.xz
  • 进入文件夹内【配置编译选项】

    1
    make menuconfig

    make config

    • 通过空格键进行【选择/取消选择】

    • 开启的(一般已经默认开启了)

      1
      2
      [1 调试] Kernel hacking —-> Compile-time checks and compiler options —-> Compile the kernel with debug info
      [2 KGDB调试内核] Kernel hacking —-> Generic Kernel Debugging Instruments —> KGDB: kernel debugger
    • 关闭的

      1
      [1 关闭KALSR(否则会导致打断点失败)]Processor type and features -> Randomize the address of the kernel image (KASLR)

编译内核

  • 编译

    -j$(nproc)是尽可能多线程的编译,可加速,且可以通过指令nproc查看当前系统所支持的所线程的数量

    1
    2
    3
    make -j$(nproc)
    ...

  • 编译报错解决 1

    1
    No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'.  Stop.

    编辑.config文件

    1
    vim .config

    修改CONFIG_SYSTEM_TRUSTED_KEYS,将其置空。

    1
    2
    3
    4
    # 原本内容
    CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
    # 将该项原有内容删掉即可,如下
    CONFIG_SYSTEM_TRUSTED_KEYS=""
  • 编译报错解决 2

    1
    2
    3
    4
    BTF: .tmp_vmlinux.btf: pahole (pahole) is not available
    Failed to generate BTF for vmlinux
    Try to disable CONFIG_DEBUG_INFO_BTF
    make: *** [Makefile:1165: vmlinux] Error 1

    系统缺少dwarves软件包

    1
    sudo apt-get install dwarves
  • 此时得到的文件有

    1
    2
    arch/x86/boot/bzImage --> 压缩内核镜像
    vmlinux --> 原始内核文件
  • 先用qemu测试一下(没有文件系统会kernel panic

    这时候,qemu会卡住不动,因为现在还没有文件系统,电脑加电启动首先由bootloader加载内核,内核紧接着需要挂载内存根文件系统。

    1
    qemu-system-x86_64 -kernel arch/x86/boot/bzImage

制作根文件系统

  • 获取buzybox源码

    1
    wget https://busybox.net/downloads/busybox-1.33.0.tar.bz2
  • 编译选项

    • Settings -> Build static binary file (no shared lib)
    1
    make menuconfig
  • 编译

    1
    make -j$(nproc) && make install

构建根文件系统镜像

参考使用QEMU和GDB调试Linux内核 | Consen

注意:

  1. rootfs在目录busybox-1.33.0
  2. 最后生成的根文件镜像rootfs.cpiolinux-5.11
  • 制作内存根文件系统镜像

    在目录busybox-1.33.0

    1
    2
    3
    4
    5
    mkdir rootfs 
    cd rootfs
    cp ../_install/* ./ -rf # 注意路径
    mkdir dev proc sys home
    sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
  • 准备init脚本文件放在根文件系统跟目录下rootfs/init,添加如下内容到init文件

    1
    2
    3
    4
    5
    6
    #!/bin/sh 
    mount -t proc none /proc
    mount -t sysfs none /sys
    echo "Wellcome to Linux!"
    echo "--------------------"
    /bin/sh
  • 使用chmod +x init给init脚本添加可执行权限,然后执行下面的命令打包成内存根文件系统镜像

    1
    find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio 

qemu运行内核

  • rootfs.cpiobzImage放到一个目录下,并在该目录下创建脚本boot.sh

  • 测试脚本boot.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    qemu-system-x86_64 \
    -m 128M \
    -kernel ./bzImage \
    -initrd ./rootfs.cpio \
    -monitor /dev/null \
    -cpu kvm64,+smep \
    -append "console=ttyS0 loglevel=3 quiet nokaslr" \
    -nographic \
    -s
  • 部分参数说明如下:

    • -m:虚拟机内存大小

    • -kernel:内存镜像路径

    • -initrd:磁盘镜像路径

    • -append:附加参数选项

      • nokalsr:关闭内核地址随机化,方便我们进行调试
      • loglevel=3 & quiet:不输出log
      • console=ttyS0:指定终端为/dev/ttyS0,这样一启动就能进入终端界面
    • -monitor:将监视器重定向到主机设备/dev/null,这里重定向至null主要是防止CTF中被人给偷了qemu拿flag

    • -cpu:设置CPU安全选项,在这里开启了smep保护

    • -s:相当于-gdb tcp::1234的简写(也可以直接这么写),后续我们可以通过gdb连接本地端口进行调试

  • 添加可执行权限并执行

    1
    2
    chmod +x ./boot.sh
    ./boot.sh
  • 如果存在/etc/inittab文件,Busybox init 程序解析它,然后按照他的指示创建各种子进程,否则使用默认的配置创建子进程.

    • 一般不搞这个

实验结果

Wonderful!

kernel_on_qemu

[废弃]构建磁盘映像

注意busybox文件在linux-5.11

建立文件系统

  • 初始化文件系统

    1
    2
    3
    4
    5
    6
    $ 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
  • 配置初始化脚本

    1. 配置etc/inittab

      1
      2
      3
      4
      5
      6
      ::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

    2. 配置etc/init.d/rcS

      1
      2
      3
      4
      5
      6
      #!/bin/sh
      mount -t proc none /proc
      mount -t sys none /sys
      /bin/mount -n -t sysfs none /sys
      /bin/mount -t ramfs none /dev
      /sbin/mdev -s

      配置各种目录的挂载

      或者:

      根目录下创建init文件,写入如下内容

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      #!/bin/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
    3. 配置用户组

      1
      2
      3
      4
      5
      $ 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

      在这里建立了两个用户组rootctf,以及两个用户rootctf

    4. 配置glibc

    5. 打包文件系统为镜像文件

      busybox

      1
      find . | cpio -o -H newc > ../core.cpio

      (即在linux-5.11下编译出core.cpio根文件系统镜像)

      或者(只是名字不同)

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

qemu运行内核

  • bzImagecore配置启动脚本

    1
    touch boot.sh
  • 注意两个文件

    1
    2
    3
    4
    $ file bzImage    
    bzImage: Linux kernel x86 boot executable bzImage, version 5.11.0 (ganliber@ganliber-virtual-machine) #2 SMP Mon Jul 11 19:16:12 CST 2022, RO-rootFS, swap_dev 0x9, Normal VGA
    $ file rootfs.cpio
    rootfs.cpio: ASCII cpio archive (SVR4 with no CRC)

    放在同一个文件夹下

  • 编写脚本boot.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!/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 nokaslr" \
    -cpu kvm64,+smep \
    -smp cores=2,threads=1 \
    -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
    -nographic \
    -s

    解释:

    部分参数说明如下:

    • -m:虚拟机内存大小

    • -kernel:内存镜像路径

    • -initrd:磁盘镜像路径

    • ```
      -append

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18

      :附加参数选项

      - `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保护

      - `-s`:相当于`-gdb tcp::1234`的简写(也可以直接这么写),后续我们可以通过gdb连接本地端口进行调试

      * 或者

      ```bash
      qemu-system-x86_64 -kernel ./bzImage -initrd ./rootfs.cpio -S -s

    解释:

    • -s:一个是-s,在TCP 1234端口上创建了一个gdb-server
    • -S:-S代表启动时暂停虚拟机,等待 gdb 执行 continue指令(可以简写为c)

下载现有的镜像

列出可下载的镜像

1
sudo apt search linux-image-

拉取5.11版本(例)

1
2
sudo apt download linux-image-5.11.0-43-generic
dpkg -X ./linux-image-5.11.0-43-generic_5.11.0-43.47~20.04.2_amd64.deb extract

其中的./extract/boot/vmlinuz-5.11.0-43-generic便是bzImage内核镜像文件