[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 内核官网:https://www.kernel.org/
源码下载地址:https://cdn.kernel.org/pub/linux/kernel/
内核版本号与各发行版版本管理
linux内核版本
linux 版本号由三个数字组成A.B.C,如5.15.5,分别含义:
A:目前发布的主版本,增长很缓慢,通常后面的数字比较大了的时候该数字会增长。
B:次版本号,表示稳定的版本号。
C:修订版本号,代表改版本补丁次数,在下一个稳定版本发布之前出现补丁和修复会更新该版本号。非长期维护版本一般20多个。
预发布版:很久之前内核通过版本号中的第二个数字即B的奇偶来表示稳定版和预发布版。但现在已经取消这个规则,现在预发布版用-rcX来表示如5.17-rc3,X为数字,一般不超过rc8。
长期维护版:linux 会长期维护几个版本,每次出现重要的错误修复都会对该版本打补丁,无论是否有更新的版本:
Version | Maintainer | Released | Projected EOL |
---|---|---|---|
5.15 | Greg Kroah-Hartman & Sasha Levin | 2021-10-31 | Oct, 2023 |
5.10 | Greg Kroah-Hartman & Sasha Levin | 2020-12-13 | Dec, 2026 |
5.4 | Greg Kroah-Hartman & Sasha Levin | 2019-11-24 | Dec, 2025 |
4.19 | Greg Kroah-Hartman & Sasha Levin | 2018-10-22 | Dec, 2024 |
4.14 | Greg Kroah-Hartman & Sasha Levin | 2017-11-12 | Jan, 2024 |
4.9 | Greg Kroah-Hartman & Sasha Levin | 2016-12-11 | Jan, 2023 |
linux发行商也会维护自己的长期维护版内核。不同发行商的内核版本号含义有细微不同,下面介绍一些ubuntu 的。
参考:https://www.kernel.org/category/releases.html
查看任意commit 所属内核版本
任意一个kernel commit链接,如:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4ff2980b6bd2aa6b4ded3ce3b7c0ccfab29980af
可以直接查看tree 中Makefile:
文件开头就是版本号:
ubuntu版本
镜像下载与老镜像下载
镜像下载地址:https://releases.ubuntu.com/
老镜像下载地址:https://old-releases.ubuntu.com/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 更新的功能。
参考:https://wiki.ubuntu.com/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:https://kernel.ubuntu.com/git/ubuntu/
git下载对应版本:
git clone git://kernel.ubuntu.com/ubuntu/ubuntu-focal.git -b Ubuntu-hwe-5.13-5.13.0-35.40_20.04.1 --depth 1
网很卡的话,使用clash:
clash 订阅&下载:https://portal.wallless.xyz/
clash 配置TAP虚拟网卡:https://uzbox.com/tech/clash-atp.html
ubuntu 常见版本对应内核版本
老镜像下载地址:http://old-releases.ubuntu.com/releases/
镜像名 | 默认内核版本 | md5后6 |
---|---|---|
ubuntu-20.04-desktop-amd64.iso | 5.4.0-26-generic | 35f5a0 |
ubuntu-20.04-live-server-amd64.iso | 5.4.0-26-generic | 35f5a0 |
ubuntu-20.04.1-desktop-amd64.iso | 5.4.0-42-generic | 36a5aa |
ubuntu-20.04.1-live-server-amd64.iso | 5.4.0-42-generic | 36a5aa |
ubuntu-20.04.2.0-desktop-amd64.iso | 5.8.0-43-generic | 5f0820 |
ubuntu-20.04.2-live-server-amd64.iso | 5.4.0-65-generic | d388b4 |
ubuntu-20.04.3-desktop-amd64.iso | 5.11.0-27-generic | |
ubuntu-20.04.3-live-server-amd64.iso | 5.4.0-81-generic | 33be0a |
ubuntu-21.04-beta-desktop-amd64.iso | 5.11.0-13-generic | 4687e5 |
ubuntu-21.04-beta-live-server-amd64.iso | 5.11.0-13-generic | 4687e5 |
ubuntu-21.10-beta-desktop-amd64.iso | 5.13.0-16-generic | 4442a0 |
ubuntu-21.10-beta-live-server-amd64.iso | 5.13.0-16-generic | 4442a0 |
… | … |
kernel 编译
编译准备
先下载源码,上面已经说过了,不多说。
有很多依赖项,如下命令安装依赖:
apt-get build-dep linux linux-image-5.11.0-44-generic
安装之后也不一定全,make 的时候根据报错依次安装就行。
如下docker 环境 可以编译kernel 5.x 版本内核
https://registry.hub.docker.com/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 体系的内核编译可以参考:https://wiki.ubuntu.com/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 源码 : https://www.qemu.org/download/#source
wget https://download.qemu.org/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 拷贝过来就行。比如:
https://github.com/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/shcd ./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挂上,一设置断点就崩溃,有时候还会损坏虚拟机),所以虽然看起来方便,但着实没用。
参考:https://www.cnblogs.com/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
参考:http://taowusheng.cn/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:https://github.com/pwndbg/pwndbg
pwngdb:https://github.com/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.pydefine hook-run
python
import angelheap
angelheap.init_angelheap()
end
end
peda
peda:https://github.com/longld/peda
直接下载执行:
echo "source ~/peda/peda.py" >> ~/.gdbinit
一些gdb命令
#显示xxx 结构体的成员大小和偏移(需要符号)
pt/o struct xxx
#跳过断点1 117次,用来断正好溢出的fsconfig
ignore 1 117
参考
linux kernel官网:https://www.kernel.org/
linux kernel 发行简介:https://www.kernel.org/category/releases.html
ubuntu kernel FAQ:https://wiki.ubuntu.com/Kernel/FAQ#Kernel.2FFAQ.2FGeneralVersionMeaning.What_does_a_specific_Ubuntu_kernel_version_number_mean.3F
内核编译:https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel
普通vmware 调试:https://www.cnblogs.com/yxysuanfa/p/6844459.html
双机调试:http://taowusheng.cn/2020/03/30/20200330%20%E5%8F%8C%E6%9C%BA%E8%B0%83%E8%AF%95Linux%E5%86%85%E6%A0%B8/
问了韬神一堆问题:https://github.com/veritas501
[kernel]linux内核基础: 版本、源码、编译与调试相关推荐
- ubuntu20 下从linux 5.14.0-1045 源码编译 linux-5.15.56 内核
ubuntu20 下从linux 5.14.0-1045 源码编译 linux-5.15.56 内核 原以为会是很简单的事,结果还是颇废一番周折.很多情况是没有遇到过得.所以这里记录一下. 问题记录的 ...
- Linux 内核中RAID5源码详解之守护进程raid5d
Linux 内核中RAID5源码详解之守护进程raid5d 对于一个人,大脑支配着他的一举一动:对于一支部队,指挥中心控制着它的所有活动:同样,对于内核中的RAID5,也需要一个像大脑一样的东西来支配 ...
- Ceph源码编译和调试vstart版本(一)
ceph调试环境及版本 ubuntu18.04 ceph v14.2.22 ceph调试源码部署一个完整集群,使用ceph源码vstart脚本部署. 1.克隆源码仓库 git clone --recu ...
- linux 安装源码网卡包,【linux命令】Linux通过yum 或者源码编译安装vnstat查看网卡流量...
Linux通过vnstat查看网卡流量有两种安装方式: yum 安装或者源码编译安装. 1,yum安装. 直接运行yum install vnstat -y 安装完后测试: [[email prot ...
- 下载AOSP源码编译、调试、刷机
一.准备工作 系统最好是Linux或者mac OS(本文基于Ubuntu). Ubuntu设置永不休眠,在setting中搜索power.blank-screen选择never. 一块大一点儿的硬盘, ...
- Ceph源码编译和调试之vstart方式
存储系统:ceph-14.2.22 操作系统:ubuntu-server-18.04 前言 调试ceph源码需要提前部署好一个完整的集群,部署集群的方法很多,比如:通过ceph源码自带的vstart脚 ...
- OpenCPN + Ubuntu 18.04 源码编译 + Codeblocks 调试 + wxFormBuilder 安装
OpenCPN + Ubuntu 18.04 源码编译 文章目录 一.参考资料 二.源码编译流程 三.利用 IDE 编译 四.利用 IDE 调试 四.测试界面开发工具 一.参考资料 OpenCPN - ...
- Mysql源码编译和调试debug
下载源码 直接从github 上下载了源码.git 地址:https://github.com/mysql/mysql-server 下载路径如:/work/mysql-server 编译 依赖 ma ...
- Win7+VS2010:mysql 源码编译与调试
win7+vs2010源码编译mysql 最近由于在实习,工作重点在于一些数据库的开发,为了更好的理解数据库的实现机制,目前萌生了要研究一下mysql数据库源码的想法.那么好吧,说干就干,首先我们需要 ...
- Linux内核的TCP源码入门(一)
文章目录 前言 一.TCP报文段结构 1.报文段整体结构 2.TCP首部-固定部分 3.TCP首部-选项(options) 二.TCP接收和发送数据 1.TCP的"接口" 2.发送 ...
最新文章
- nssl1487-图
- 怎么恢复oracle的包,【学习笔记】使用dbms_backup_restore包恢复数据库
- 进程(并发,并行) join start 进程池 (同步异步)
- 用java统计任一书名次数_Java入门第三季 借书系统源代码 加入了限制重输次数 欢迎指教交流...
- 成功解决Could not fetch URL https://pypi.tuna.tsinghua.edu.cn/simple/xx/: There was a problem confirming
- CSS学习笔记 -- Position(定位)
- 初始化栈的代码_限定性数据结构-栈
- 理解SpringAOP-菜鸟新手入门
- 使用R包GD实现地理探测器算法
- 史密斯(Smith)圆图
- TP-LINK_841N_V8路由器硬改升级OpenWRT记
- 性能测试实战(五):参数化+关联
- Hive之数据类型、查询操作
- ECSHOP 2.7.2 文件结构及各文件相应功能介绍
- 百度地图添加多个大头针自定义图片
- 第十三届蓝桥杯大赛软件赛省赛(b组c语言)
- 校园生活旅游娱乐vlog篇
- Hadoop之HDFS面试题整理
- 逐步回归选取特征及GAM模型的使用==college数据集(统计学习导论)
- 微服务进阶避坑指南 | 技术头条
热门文章
- 手机开热点但是电脑一直连接不上_电脑连不上wifi,手机可以连上。手机开热点,电脑可以连上。这是怎么回事,电脑就一直循环连接那个w...
- 马步站桩---快速健身法
- 网页中单个页面如何做好SEO优化
- 建文高考成绩查询2021,2021届新高考语文强化模拟卷(三).pdf
- GSMA选举新的董事会成员,宣布Orange董事长兼首席执行官Stéphane Richard出任主席
- 已解决:[emerg] bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a socket in a way forb
- 改进ur_modern_driver包,提供ur_driver/URScript_srv服务
- 网站漏洞修补之苹果cms建站系统
- SQL学习笔记(04)_JOIN
- 【深度学习模型】了解一下Faster RCNN