前言 以4.8.13版本为例,记录一下kernel的编译过程以及文件系统的搭建。
正文 编译环境 GCC 7.4
Ubuntu 16.04
内核编译 源码下载 1 2 $ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.8.13.tar.xz $ tar -xvf linux-4.8.13.tar.xz
编译过程 1 2 3 4 5 $ cd linux-4.8.13/ $ make menuconfig $ make -j4 $ make all $ make modules
编译完成后可以在当前目录下找到vmlinux文件(调试时使用),在arch/x86/boot目录下找到bzImage文件(启动kernel用的)。
1 2 3 4 5 6 Kernel heacking --> Compile-time checks and compiler options --> 选中Compile the kernel with debug info、Reduce debugging information、Debug Filesystem,其他全部取消。 去除Collect scheduler debugging info、Collect scheduler statistics选项。 Processor type and features --> 取消Linux guest support选项。
PS:编译出来的vmlinux几百MB,大佬们说去掉符号表就行了,但感觉去掉符号表的话要vmlinux就没用了呀。。以后有思路了再研究下怎么缩减吧。
报错 编译时发生下列错误:
1 2 3 4 kernel/built-in.o: In function `update_wall_time': /home/ubn/linux/linux-4.8.13/kernel/time/timekeeping.c:2079: undefined reference to `____ilog2_NaN' Makefile:951: recipe for target 'vmlinux' failed make: *** [vmlinux] Error 1
保存下列代码到patch.diff
,然后运行patch -i patch.diff
, 提示输入操作文件时, 先后输入include/linux/log2.h
,tools/include/linux/log2.h
即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 diff --git a/include/linux/log2.h b/include/linux/log2.h index ef3d4f67118c..c373295f359f 100644 @@ -16,12 +16,6 @@ #include <linux/bitops.h> /* - * deal with unrepresentable constant logarithms - */ -extern __attribute__((const, noreturn)) -int ____ilog2_NaN(void); - -/* * non-constant log of base 2 calculators * - the arch may override these in asm/bitops.h if they can be implemented * more efficiently than using fls() and fls64() @@ -85,7 +79,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n) #define ilog2(n) \ ( \ __builtin_constant_p(n) ? ( \ - (n) < 1 ? ____ilog2_NaN() : \ + (n) < 2 ? 0 : \ (n) & (1ULL << 63) ? 63 : \ (n) & (1ULL << 62) ? 62 : \ (n) & (1ULL << 61) ? 61 : \ @@ -148,10 +142,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n) (n) & (1ULL << 4) ? 4 : \ (n) & (1ULL << 3) ? 3 : \ (n) & (1ULL << 2) ? 2 : \ - (n) & (1ULL << 1) ? 1 : \ - (n) & (1ULL << 0) ? 0 : \ - ____ilog2_NaN() \ - ) : \ + 1 ) : \ (sizeof(n) <= 4) ? \ __ilog2_u32(n) : \ __ilog2_u64(n) \ diff --git a/tools/include/linux/log2.h b/tools/include/linux/log2.h index 41446668ccce..d5677d39c1e4 100644 @@ -13,12 +13,6 @@ #define _TOOLS_LINUX_LOG2_H /* - * deal with unrepresentable constant logarithms - */ -extern __attribute__((const, noreturn)) -int ____ilog2_NaN(void); - -/* * non-constant log of base 2 calculators * - the arch may override these in asm/bitops.h if they can be implemented * more efficiently than using fls() and fls64() @@ -78,7 +72,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n) #define ilog2(n) \ ( \ __builtin_constant_p(n) ? ( \ - (n) < 1 ? ____ilog2_NaN() : \ + (n) < 2 ? 0 : \ (n) & (1ULL << 63) ? 63 : \ (n) & (1ULL << 62) ? 62 : \ (n) & (1ULL << 61) ? 61 : \ @@ -141,10 +135,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n) (n) & (1ULL << 4) ? 4 : \ (n) & (1ULL << 3) ? 3 : \ (n) & (1ULL << 2) ? 2 : \ - (n) & (1ULL << 1) ? 1 : \ - (n) & (1ULL << 0) ? 0 : \ - ____ilog2_NaN() \ - ) : \ + 1 ) : \ (sizeof(n) <= 4) ? \ __ilog2_u32(n) : \ __ilog2_u64(n) \
文件系统构建 下载busybox及编译 1 2 3 4 5 wget https://busybox.net/downloads/busybox-1.31.0.tar.bz2 tar -jxvf busybox-1.19.4.tar.bz2 cd busybox-1.19.4make menuconfig make install
make install后在目录下就会发现__install文件夹,里面的东西就可以用来构建文件系统了。
1 2 3 4 5 Busybox Settings -> Build Options -> Build Busybox as a static binary 编译成静态文件 关闭下面两个选项: Linux System Utilities -> [] Support mounting NFS file system 网络文件系统 Networking Utilities -> [] inetd (Internet超级服务器)
构建文件系统 这里需要先创建一些文件夹:
1 $ mkdir proc sys dev etc
下面添加一些东西,以便更好的使用:
添加用户 busybox里面默认是root用户,并且用户配置等东西不齐全,这里直接上星盟平台 扒下kernel的环境。
下载kernel pwn1,解压出来后,将其中的etc/
目录复制过来,这样就有了用户pwn,并且也修复了用户文件,进而可以切换用户等操作了。
修复dpkg dpkg是用来安装deb文件的(linux下一些软件都是提供deb包,可以在各大源网站下载到)。为了方便安装复现用的环境,需要先将dpkg修复
在目录下执行以下命令:
1 2 $ mkdir var\lib\dpkg\info $ touch var\lib\dpkg\status
这样就可以用dpkg -i [packagename]
来安装一些依赖环境了。
初始化文件init init文件是开机后自动运行的脚本,在其中可以执行一些命令,如挂载模块等,它具有root权限,并且需要通过该文件来执行/bin/sh,这样才能进入到命令行中。
这里给个基本的内容,具体的可以根据需要添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/sh mount -t proc none /proc mount -t sysfs none /sys mount -t debugfs none /sys/kernel/debug mkdir /tmp mount -t tmpfs none /tmp mdev -s setsid /bin/cttyhack setuidgid 1000 /bin/sh umount /proc umount /sys poweroff -d 0 -f
直接保存到文件系统根目录的init中即可。
最后用命令find . | cpio -o --format=newc > ../rootfs.img
运行完毕后就可以得到我们的文件系统rootfs.img
了。
启动脚本 紧接着就是用qemu启动我们的kernel了,但是每次都要打一长串才能启动很不方便,所以一般都是将命令保存在shell文件中执行的。类似于下面的脚本:
1 2 3 4 5 6 7 8 9 qemu-system-x86_64 \ -m 256M \ -cpu kvm64 \ -kernel ./bzImage \ -initrd rootfs.img \ -nographic \ -s \ -smp 4,cores=2,threads=2 \ -append "console=ttyS0 quiet nokaslr"
这里qemu-system-x86_64
代表是x86的64位架构
-m 256M
表示分配256M物理内存给该kernel运行
-cpu kvm64
表示采用kvm64的cpu,同时如果要添加保护可以在这里加,如添加smep:-cpu kvm64,smep
、
-kernel ./bzImage
用于使用的内核。
-initrd rootfs.img
用于指定选用的文件系统。
-nographic
表示不使用图形化界面,只使用串口。
-s
表示开启远程gdb调试,端口号为1234.
-smp 4,cores=2,threads=2
表示cpu为双核双线程。
-append "console=ttyS0 quiet nokaslr"
这里代表内核启动参数,不是很明白,不过nokaslr代表不开启内核地址随机化,如果要开启缓存kaslr即可。
参考链接 Linux kernel Exploit 内核漏洞学习(0)-环境安装 - 先知社区
linux内核漏洞利用初探(1):环境配置
从零使用qemu模拟器搭建arm运行环境_海枫的专栏-CSDN博客_如何模拟运行arm镜像文件