admin管理员组

文章数量:1794759

[kernel]linux内核基础: 版本、源码、编译与调试

[kernel]linux内核基础: 版本、源码、编译与调试

linux kernel 安全基础(版本、源码、编译与调试)

文章目录
  • linux kernel 安全基础(版本、源码、编译与调试)
    • 内核基础知识
    • 内核版本号与各发行版版本管理
      • linux内核版本
        • 查看任意commit 所属内核版本
      • ubuntu版本
        • 镜像下载与老镜像下载
        • 版本号查看与含义
        • ubuntu内核和linux 官方内核区别
        • ubuntu 更换内核以及源码下载
        • ubuntu 常见版本对应内核版本
    • kernel 编译
      • 编译准备
        • 查看已有操作系统的编译选项
      • 配置和编译
        • menuconfig 依赖选项
      • 检查编译结果
    • kernel调试
      • qemu 调试
        • 安装qemu(自己编译)
        • 制作启动组件initrd
        • 启动脚本
      • vmware 调试内核
        • 普通调试
        • 双机调试
      • 常用gdb插件
        • pwndbg+pwngdb
        • peda
      • 一些gdb命令
    • 参考

内核基础知识

Linux最早是由芬兰 Linus Torvalds为尝试在英特尔x86架构上提供自由的类Unix操作系统而开发的。该计划开始于1991年,在计划的早期有一些 Minix黑客提供了协助,而如今全球无数程序员正在为该计划无偿提供帮助。

linux 内核官网:www.kernel/

源码下载地址:cdn.kernel/pub/linux/kernel/

内核版本号与各发行版版本管理 linux内核版本

linux 版本号由三个数字组成A.B.C,如5.15.5,分别含义:

A:目前发布的主版本,增长很缓慢,通常后面的数字比较大了的时候该数字会增长。

B:次版本号,表示稳定的版本号。

C:修订版本号,代表改版本补丁次数,在下一个稳定版本发布之前出现补丁和修复会更新该版本号。非长期维护版本一般20多个。

预发布版:很久之前内核通过版本号中的第二个数字即B的奇偶来表示稳定版和预发布版。但现在已经取消这个规则,现在预发布版用-rcX来表示如5.17-rc3,X为数字,一般不超过rc8。

长期维护版:linux 会长期维护几个版本,每次出现重要的错误修复都会对该版本打补丁,无论是否有更新的版本:

VersionMaintainerReleasedProjected EOL
5.15Greg Kroah-Hartman & Sasha Levin2021-10-31Oct, 2023
5.10Greg Kroah-Hartman & Sasha Levin2020-12-13Dec, 2026
5.4Greg Kroah-Hartman & Sasha Levin2019-11-24Dec, 2025
4.19Greg Kroah-Hartman & Sasha Levin2018-10-22Dec, 2024
4.14Greg Kroah-Hartman & Sasha Levin2017-11-12Jan, 2024
4.9Greg Kroah-Hartman & Sasha Levin2016-12-11Jan, 2023

linux发行商也会维护自己的长期维护版内核。不同发行商的内核版本号含义有细微不同,下面介绍一些ubuntu 的。

参考:www.kernel/category/releases.html

查看任意commit 所属内核版本

任意一个kernel commit链接,如:git.kernel/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4ff2980b6bd2aa6b4ded3ce3b7c0ccfab29980af

可以直接查看tree 中Makefile:

文件开头就是版本号:

ubuntu版本 镜像下载与老镜像下载

镜像下载地址:releases.ubuntu/

老镜像下载地址:old-releases.ubuntu/releases

版本号查看与含义

查看ubuntu 本身的版本:

cat /etc/issue # result Ubuntu 20.04.2 LTS \\n \\l # or lsb_release -a # result No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.2 LTS Release: 20.04 Codename: focal

ubuntu 版本代号:

代号版本
trusty (Trusty Tahr 可靠的塔尔羊)14.04
xenial (Xenial Xerus 好客的非洲地松鼠)16.04
bionic (Bionic Beaver仿生海狸)18.04
focal (Focal Fossa 专注狸猫??)20.04
hirsute (Hirsute Hippo 长毛河马)21.04
impish (Impish Indri 顽皮狐猴)21.10

查看ubuntu 内核版本:

uname -r # result 5.13.0-35-generic

ubuntu内核版本号格式形如5.13.0-35-generic,其中:

5.13.0:代表linux 内核稳定版本号5.13,一般ubuntu中最后小修订号都是0,因为ubuntu会自己合入补丁。

35:由ubuntu进行的第35次修订(合入补丁)。

generic:通用版本,除此之外还可能有服务器版server或老式处理器的i386版等。

ubuntu内核和linux 官方内核区别

ubuntu 会对上游内核的特定稳定版本进行rebase,并对该版本进行补丁管理,但由于上游linux 内核版本过一阵就会进入下一个版本,而ubuntu 通常不会,ubuntu 通常会自己去合入补丁。换句话说,ubuntu 只是松散的机遇上游稳定版本维护ubuntu 版本,必须查看更新日志来确定ubuntu 更新的功能。

参考:wiki.ubuntu/Kernel/FAQ#Kernel.2FFAQ.2FGeneralVersionMeaning.What_does_a_specific_Ubuntu_kernel_version_number_mean.3F

ubuntu 更换内核以及源码下载

更换内核:

apt-get install linux-image-5.11.0-44-generic # 版本号根据需求更改 #下载新版本内核一般直接生效,不生效如下操作: grep menuentry /boot/grub/grub.cfg vim /etc/default/grub #修改 GRUB_DEFAULT 选项为上面结果中想要启动内核的下标 update-grub #如果不生效的话(一般是下载旧版本内核)则直接进入/boot 目录将之前的内核相关文件(带之前内核编号的文件)全部删掉,然后启动时候报找不到内核,然后手动选择内核启动也可以

获得ubuntu内核源码:

可以直接apt source 获得:

apt source linux-image-unsigned-5.11.0-44-generic # 版本号根据需求更改

或前往ubuntu 内核git:kernel.ubuntu/git/ubuntu/

git下载对应版本:

git clone git://kernel.ubuntu/ubuntu/ubuntu-focal.git -b Ubuntu-hwe-5.13-5.13.0-35.40_20.04.1 --depth 1

网很卡的话,使用clash:

clash 订阅&下载:portal.wallless.xyz/

clash 配置TAP虚拟网卡:uzbox/tech/clash-atp.html

ubuntu 常见版本对应内核版本

老镜像下载地址:old-releases.ubuntu/releases/

镜像名默认内核版本md5后6
ubuntu-20.04-desktop-amd64.iso5.4.0-26-generic35f5a0
ubuntu-20.04-live-server-amd64.iso5.4.0-26-generic35f5a0
ubuntu-20.04.1-desktop-amd64.iso5.4.0-42-generic36a5aa
ubuntu-20.04.1-live-server-amd64.iso5.4.0-42-generic36a5aa
ubuntu-20.04.2.0-desktop-amd64.iso5.8.0-43-generic5f0820
ubuntu-20.04.2-live-server-amd64.iso5.4.0-65-genericd388b4
ubuntu-20.04.3-desktop-amd64.iso5.11.0-27-generic
ubuntu-20.04.3-live-server-amd64.iso5.4.0-81-generic33be0a
ubuntu-21.04-beta-desktop-amd64.iso5.11.0-13-generic4687e5
ubuntu-21.04-beta-live-server-amd64.iso5.11.0-13-generic4687e5
ubuntu-21.10-beta-desktop-amd64.iso5.13.0-16-generic4442a0
ubuntu-21.10-beta-live-server-amd64.iso5.13.0-16-generic4442a0
kernel 编译 编译准备

先下载源码,上面已经说过了,不多说。

有很多依赖项,如下命令安装依赖:

apt-get build-dep linux linux-image-5.11.0-44-generic

安装之后也不一定全,make 的时候根据报错依次安装就行。

如下docker 环境 可以编译kernel 5.x 版本内核

registry.hub.docker/r/chenaotian/kernelcompile

docker run -ti --rm -h kc --name kc -v D:/share:/work chenaotian/kernelcompile:latest /bin/bash docker exec -it kc /bin/bash 查看已有操作系统的编译选项 cat /usr/src/linux-headers-`uname -r`/.config #或 cat /boot/config-`uname -r` 配置和编译

debian 体系的内核编译可以参考:wiki.ubuntu/Kernel/BuildYourOwnKernel

改文章的方法是编译内核deb包,也就是跟apt-get 安装的内核同款的编译方式。我们不需要完整编译出他的东西,我们只对内核本身感兴趣。所以按照他提供的部分方法进行就可以(需要按照上面“获得ubuntu内核源码”中的git方法下载代码):

LANG=C fakeroot debian/rules clean # 下面这一步我们只需要构建binary-generic,因为内核在这里,不需要其他的 LANG=C fakeroot debian/rules binary-generic

开始编译之后,我们不需要编译出完整的deb包,只需要一个内核就行,所以看到如下输出可以直接ctrl+c结束:

拷贝图中红框的命令bzImage 前的部分:

make ARCH=x86 CROSS_COMPILE= KERNELVERSION=5.13.0-35-generic CONFIG_DEBUG_SECTION_MISMATCH=y KBUILD_BUILD_VERSION="40~20.04.1" LOCALVERSION= localver-extra= CFLAGS_MODULE="-DPKG_ABI=35" PYTHON=/usr/bin/python3 O=/tmp/aa/ubuntu-focal/debian/build/build-generic -j4

接下来使用menuconfig 来编辑我们自定义的编译选项,选项设置为<*>代表编译进内核,设置为<M>代表编译成内核模块,**这里要设置成<*>。**一般要开启调试符号,除此之外根据要分析的漏洞开启必要的编译选项。/ 是搜索编译选项关键字。menuconfig结束之后,通过修改.config文件也可以修改编译选项。如果有互相依赖的情况,后续编译的时候会询问,问题不大,menuconfig 命令如下(上面拷贝的命令后加menuconfig 即可):

make ARCH=x86 CROSS_COMPILE= KERNELVERSION=5.13.0-35-generic CONFIG_DEBUG_SECTION_MISMATCH=y KBUILD_BUILD_VERSION="40~20.04.1" LOCALVERSION= localver-extra= CFLAGS_MODULE="-DPKG_ABI=35" PYTHON=/usr/bin/python3 O=/tmp/aa/ubuntu-focal/debian/build/build-generic -j4 menuconfig

添加调试符号:

Kernel hacking ---> Compile-time checks and compiler options [*] Compile the kernel with debug info

一些可能需要的编译选项(踩过坑的):

# 设置调试符号 CONFIG_DEBUG_INFO=y # fuse 开启,一些漏洞利用会用到 CONFIG_FUSE_FS=y # VIPC 开启,可以使用msg系列 CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_SYSVIPC_COMPAT=y CONFIG_CHECKPOINT_RESTORE=y # 设置这个才能正确调用msg 里的copy 系列函数

最后编译出内核(上面拷贝的命令后加bzImage):

make ARCH=x86 CROSS_COMPILE= KERNELVERSION=5.13.0-35-generic CONFIG_DEBUG_SECTION_MISMATCH=y KBUILD_BUILD_VERSION="40~20.04.1" LOCALVERSION= localver-extra= CFLAGS_MODULE="-DPKG_ABI=35" PYTHON=/usr/bin/python3 O=/tmp/aa/ubuntu-focal/debian/build/build-generic -j4 bzImage

O= 后面的目录是编译结果目录,.config 和编译结果 和System.map 都在这个目录之中。

menuconfig 依赖选项

menuconfig 中如果有的选项无法配置成*,只能配置成M的话,可能是依赖没有满足,如:

depends 代表的是依赖,如果想要将某个编译选项配置成y(而不是m),那么根据这个依赖的逻辑表达式他所有依赖的选项都要配置成y。建议在menuconfig 上操作,如果直接改.config 中为y,大概率会编译失败。

这里我直接把NF_CONNTRACK 取消配置,则直接可以将OPENVSWITCH 配置成y,但问题是我需要NF_CONNTRACK ,所以就要满足整个表达式,也就是后面的所有都要配置成y。而他们自己还是可能有依赖的东西,都要配置成y 才行。

如果这种配置选项,无法通过按数字键跳转:

那么说明现在他是自动配置成m 的,看到Selected by[m],说明下面选项决定了它被配置成m:

一般要把下面的选项改成y 才行,而他们自己可能也有依赖,所以,都一起改成y。

检查编译结果

System.map 文件可以查看一些关键函数有没有

cat System.map |grep function_name

strings 查看一些字符串

strings vmlinux |grep function_name

gdb 打开查看符号,断点或list

gdb vmlinux b function_name list function_name

kernel调试 qemu 调试 安装qemu(自己编译)

qemu 源码 : www.qemu/download/#source

wget download.qemu/qemu-6.2.0.tar.xz tar xvJf qemu-6.2.0.tar.xz cd qemu-6.2.0 ./configure make

可能的一些依赖:

apt-get install ninja-build apt-get install libpixman-1-dev 制作启动组件initrd

可以直接去别人github 拷一个initrd过来用,也可以自己做。做一个简易版initrd的主要工作就是静态编译一个busybox。这种initrd 里面没有lib 啥的,分析漏洞的exp 和poc 只能静态编译来测试,如果想要做一个比较全的initrd 比较麻烦。

建议随便找一个别人分析漏洞的环境把里面的initrd 拷贝过来就行。比如:

github/chenaotian/CVE-2022-0185/tree/main/qemu

解包和打包cpio:

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

如果一定需要动态链接的exp,偷懒方法就是,ldd 查看exp 需要的动态库,然后将ld-linux-x86-64.so.2 和其他依赖的so全部拷贝到文件系统中,qemu 启动后,用LD_LIBRARY_PATH 来运行:

将上面那些so全部拷贝到一个文件夹内然后放入rootfs中制作成initrd.img,然后启动qemu,按照如下方法运行:

cp ...so ./rootfs/exp #将so 拷贝到制作initrd.img的目录中 cd ./rootfs find . | cpio -o --format=newc > ../rootfs.img #制作initrd.img cd ../ ./boot.sh #启动qemu # qemu 启动后 cd /expdir export LD_LIBRARY_PATH=`pwd` ./ld-linux-x86-64.so.2 ./exploit

kill 命令

ps -ef |grep qemu | grep -v grep | awk '{print $2}' | xargs kill -9 启动脚本

qemu 的启动脚本boot.sh 如下,方便每次修改exp直接启动,直接在boot.sh中生成initrd.img:

#! /bin/sh cd ./rootfs find . | cpio -o --format=newc > ../rootfs.img cd ../ qemu-system-x86_64 \\ -m 512M \\ -kernel ./bzImage \\ -initrd ./rootfs.img \\ -nographic \\ -append "console=ttyS0 root=/dev/sda rw nokaslr quiet" \\ -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \\ -cpu kvm64,+smep,+smap \\ -gdb tcp::10086 vmware 调试内核 普通调试

在虚拟机配置文件(.vmx)后加:

debugStub.listen.guest64="1"

然后直接

gdb target remote :8864

反正我是没成功,据说在开了Hyper-V的机器上会失败,但我关了Hyper-V也没成功(具体表现为,能gdb挂上,一设置断点就崩溃,有时候还会损坏虚拟机),所以虽然看起来方便,但着实没用。

参考:wwwblogs/yxysuanfa/p/6844459.html

双机调试
  • 被调试机:服务机

  • 调试机:客户机

先在虚拟机设备里删除打印机,然后添加串行端口。使用命名串行端口,服务器和客户端都写这个:

//./pipe/com_1

设置波特率和测试串口通信:

#服务端设置波特率 stty -F /dev/ttyS0 115200 #测试 客户端输入,服务端接受 echo "haha" > /dev/ttyS0 #如果ttyS0不行就试试ttyS1啥的

然后服务器配置调试相关参数:

  • 先修改/etc/default/grub:

    GRUB_CMDLINE_LINUX_DEFAULT="quiet 3 kgdbwait kgdboc=ttyS0,115200"
  • 然后更新grub,执行:

    update-grub

    然后重启,之后就可以尝试调试了。

  • gdb挂载命令:

    set arch i386:x86-64:intel set remotebaud 115200 target remote /dev/ttyS0

    如果跑起来需要中断的话,在服务机执行:

    echo g > /proc/sysrq-trigger

    参考:taowusheng/2020/03/30/20200330%20%E5%8F%8C%E6%9C%BA%E8%B0%83%E8%AF%95Linux%E5%86%85%E6%A0%B8/

    常用gdb插件 pwndbg+pwngdb

    pwndbg:github/pwndbg/pwndbg

    pwngdb:github/scwuaptx/Pwngdb

    先安装pwndbg,直接下载之后运行./setup.sh即可,中途可能会因为git 断开,执行git init,然后继续执行就行。

    然后安装pwngdb,直接下载解压,然后编辑~/.gdbinit:

    source /root/pwndbg-dev/gdbinit.py source /root/Pwngdb-master/pwngdb.py source /root/Pwngdb-master/angelheap/gdbinit.py define hook-run python import angelheap angelheap.init_angelheap() end end peda

    peda:github/longld/peda

    直接下载执行:

    echo "source ~/peda/peda.py" >> ~/.gdbinit 一些gdb命令 #显示xxx 结构体的成员大小和偏移(需要符号) pt/o struct xxx #跳过断点1 117次,用来断正好溢出的fsconfig ignore 1 117 参考

    linux kernel官网:www.kernel/

    linux kernel 发行简介:www.kernel/category/releases.html

    ubuntu kernel FAQ:wiki.ubuntu/Kernel/FAQ#Kernel.2FFAQ.2FGeneralVersionMeaning.What_does_a_specific_Ubuntu_kernel_version_number_mean.3F

    内核编译:wiki.ubuntu/Kernel/BuildYourOwnKernel

    普通vmware 调试:wwwblogs/yxysuanfa/p/6844459.html

    双机调试:taowusheng/2020/03/30/20200330%20%E5%8F%8C%E6%9C%BA%E8%B0%83%E8%AF%95Linux%E5%86%85%E6%A0%B8/

    问了韬神一堆问题:github/veritas501

    本文标签: 内核源码版本基础kernel