QEMU+busybox 搭建Linux内核运行环境

记录一下安装使用QEMU+busybox搭建Linux内核运行环境的过程

参考以下文章来操作的

23R3F’s blog - kernel pwn初探

ZoE’s blog - 核环境搭建和基础知识

编译内核

安装依赖

1
2
3
4
sudo apt-get update
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc

下载linux kernel源码,我选择了4.19.65版本的tar.gz包

1
2
3
tar -zxvf ./linux-4.19.65.tar.gz
cd ./linux-4.19.65/
sudo make menuconfig

进入kernel hacking

1
2
3
4
5
勾选以下项目
Kernel debugging
Compile-time checks and compiler options —> Compile the kernel with debug info和Compile the kernel with frame pointers
KGDB
然后保存退出
1
sudo make bzImage

完成编译, 得到一个bzImage

关于各种类型的内核的各种形式:

  • bzImage是vmlinuz经过gzip压缩后的文件,适用于大内核
  • vmlinux是未压缩的内核
  • vmlinuz是vmlinux的压缩文件。
  • vmlinux 是ELF文件,即编译出来的最原始的文件。
  • vmlinuz应该是由ELF文件vmlinux经过OBJCOPY后,并经过压缩后的文件
  • zImage是vmlinuz经过gzip压缩后的文件,适用于小内核

编译busybox

busybox是Linux上的一个应用程序 它整合了许多Linux上常用的工具和命令 IBM的一篇关于busybox的文章 文章地址,写的很详细。

busyboxz主要有这些功能

  • busybox是Linux上的一个应用程序
  • 它整合了许多Linux上常用的工具和命令

由于启动内核还需要一个简单的文件系统和一些命令,而busybox就是用来完成生成简单文件系统的

先下载busybox,我选择了busybox-1.31.1.tar.bz2

1
2
3
下载好后解压
cd ./busybox-1.31.1/
make menuconfig
1
2
进入 Settings
勾选 Build static binary (no shared libs)
1
make install

目录下就会生成一个_install 文件夹,就是编译结果,进入这个文件夹进行配置

1
2
3
4
5
cd _install
mkdir proc
mkdir sys
touch init
gedit init

编辑init:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
echo "{==DBG==} INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
#mount指令 挂载某个分区到某个文件,这样就将分区与文件建立联系从而访问文件时就可以访问分区。
# insmod /xxx.ko # 加载模块
mdev -s
# We need this to find /dev/sda later
echo -e "{==DBG==} Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack setuidgid 1000 /bin/sh #normal user
# exec /bin/sh #root

几个常见命令

insmod: 指定模块加载到内核中

rmmod: 从内核中卸载指定模块

lsmod: 列出已经加载的模块

在_install目录下find . | cpio -o --format=newc > ./rootfs.img将文件夹里的内容打包成一个文件系统。

安装qemu

建议先把apt源更换成国内的,不然会很慢。清华源: https://mirror.tuna.tsinghua.edu.cn/help/ubuntu/

1
2
3
4
5
安装依赖
sudo apt-get install libncurses5-dev
sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev
安装QEMU
sudo apt-get install qemu

输入qemu + TAB键,如果出现很多补全提示说明安装成功

QEMU启动kernel

将第一步编译出的bzImage文件和第二部打包出来的rootfs.img文件复制进一个新的目录下,并在目录下新建一个boot.sh作为启动脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
qemu-system-x86_64 \
-m 64M \
-kernel ./bzImage \
-initrd ./rootfs.img \
-append "root=/dev/ram rw oops=panic panic=1 kalsr" \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-monitor /dev/null \
-smp cores=2,threads=1 \
-cpu kvm64,+smep \
#-S 启动gdb调试
#-s 相当于 -gdb tcp::1234
#-gdb tcp::1234 等待gdb调试

sh启动脚本中的一些命令解释

-m是指定RAM大小(默认384)

-kernel 是指定的内核镜像,这里是我们编译的镜像路径,也可以是下载好的镜像,如./vmlinuz-4.15.0-22-generic

-initrd 设置刚刚利用 busybox 创建的 rootfs.img ,作为内核启动的文件系统

-append 附加选项,指定no kaslr可以关闭随机偏移

--nographicconsole=ttyS0一起使用,启动的界面就变成当前终端

-s 相当于-gdb tcp::1234的简写,可以直接通过主机的gdb远程连接

-monitor配置用户模式的网络#将监视器重定向到主机设备/dev/null

-smp 用于声明所有可能用到的cpus, i.e. sockets cores threads = maxcpus.

-cpu 设置CPU的安全选项

chmod +x ./boot.sh给启动脚本加权限后,跑起来,如图,启动成功

写一个简单驱动

在kernel源码目录下新建一个目录。并添加两个文件,mydriver.cMakefile

mydriver.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cred.h>

MODULE_LICENSE("Dual BSD/GPL");


static int my_init(void){
printk("Hello Sunxiaokong's baby driver!\n");
printk("Size of struct cred : %ld\n", sizeof(struct cred));
printk("Size of type atomic_t : %ld\n", sizeof(atomic_t));
printk("Size of type void* : %ld\n", sizeof(void*));
printk("Size of type unsigned : %ld\n", sizeof(unsigned));
printk("Size of type kuid_t : %ld\n", sizeof(kuid_t));
return 0;
}

static void my_exit(void){
printk("Goodbye, baby driver!\n");
}

module_init(my_init);
module_exit(my_exit);

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
# at first type on ur terminal that $(uname -r) then u will get the version..
# that is using on ur system

obj-m += mydriver.o

KDIR = /home/sunxiaokong/Desktop/pwn/kernel-pwn/hello_kernel/linux-4.4.72/

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

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

然后执行make,编译得到mydriver.ko

将mydriver.ko拿进busybox的_install目录下,编辑init文件,setuidgid 0 /bin/sh使稍后可以使用insmodrmmod指令装载和卸载驱动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/sh
echo "{==DBG==} INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
#mount指令 挂载某个分区到某个文件,这样就将分区与文件建立联系从而访问文件时就可以访问分区。
# insmod /xxx.ko # 加载模块
#insmod /mydriver.ko
mdev -s
# We need this to find /dev/sda later
echo -e "{==DBG==} Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack
setuidgid 0 /bin/sh #root
#setuidgid 1000 /bin/sh #normal user
#exec /bin/sh
#root

find . | cpio -o --format=newc > ./rootfs.img将文件系统重新打包。将bzImagerootfs.img放到一个目录下,写一个boot.sh用于QEMU启动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
qemu-system-x86_64 \
-m 64M \
-kernel ./bzImage \
-initrd ./rootfs.img \
-append "console=ttyS0 root=/dev/ram rw oops=panic panic=1 kalsr" \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-monitor /dev/null \
-smp cores=2,threads=1 \
-cpu kvm64,+smep \
--nographic
#-S 启动gdb调试
#-s 相当于 -gdb tcp::1234
#-gdb tcp::1234 等待gdb调试

chmod +x ./boot.sh然后./boot.sh跑起来:

可以成功使用insmodrmmod安装和卸载驱动

添加syscall

上手尝试一下添加syscall

###

0%