一、实验内容
二、环境准备
安装开发工具
sudo apt install build-essential sudo apt install qemu # install QEMU sudo apt install libncurses5-dev bison ?ex libssl-dev libelf-dev
下载内核源代码
sudo apt install axel axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/ linux-5.4.34.tar.xz xz -d linux-5.4.34.tar.xz tar -xvf linux-5.4.34.tar cd linux-5.4.34
配置内核编译选项
make defcon?g # Default con?guration is based on ‘x86_64_defcon?g‘ make menucon?g # 打开debug相关选项 Kernel hacking ---> Compile-time checks and compiler options ---> [*] Compile the kernel with debug info [*] Provide GDB scripts for kernel debugging [*] Kernel debugging # 关闭KASLR,否则会导致打断点失败 Processor type and features ----> [] Randomize the address of the kernel image (KASLR)
编译内核
make -j$(nproc) # nproc gives the number of CPU cores/threads available # 测试?下内核能不能正常加载运?,因为没有?件系统终会kernel panic qemu-system-x86_64 -kernel arch/x86/boot/bzImage # 此时应该不能正常运行
制作根文件系统
#下载 axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 tar -jxvf busybox-1.31.1.tar.bz2 cd busybox-1.31.1
#制作根文件系统 make menucon?g #记得要编译成静态链接,不?动态链接库。 Settings ---> [*] Build static binary (no shared libs) #然后编译安装,默认会安装到源码?录下的 _install ?录中。 make -j$(nproc) && make install
制作内存根文件系统镜像
mkdir rootfs cd rootfs cp ../busybox-1.31.1/_install/* ./ -rf mkdir dev proc sys home sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
准备init脚本文件放在根文件系统跟目录下(rootfs/init),添加如下内容到init文件。
#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo "Wellcome TestOS!" echo "--------------------" cd home /bin/sh #给init脚本添加可执行权限 chmod +x init #打包成内存根文件系统镜像 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz #测试挂载根文件系统,看内核启动完成后是否执行init脚本 qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz
经查询得
学号是24,getuid.
三:查看系统调用,编写调用汇编代码
首先查看要选择进行实验的系统调用--
可知24号系统调用为getuid。
Linux内核启动后,接管系统控制权。本质上操作系统负责资源管控,用户程序要使用任何资源,都需要申请相应的资源。系统调用就是操作系统为用户态进程与硬件设备进行交互提供的一组接口。系统调用通过软中断向内核发出一个明确的请求,使用一个封装例程完成相应的功能,将结果返回给用户进程。
当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。 在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常。内核实现了很多不同的系统调用,进程指明需要哪个系统调用,把系统调用号作参数传入eax寄存器。下面以linux系统调用getuid为例简单分析一下系统调用过程
首先加入汇编函数
make rootfs
可以在qemu中看到之前添加的命令。再去执行新增的命令
四、gdb调试
1. 纯命令行启动qemu
1 qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"
2、设置断点,执行并得到对应的结果
3、将断点设置在sys_getuid16处。
4、发现执行getuid时没有停下来。反而在getuid_asm停下来
5、直接结束若干次单步执行,然后继续往下单步执行,发现出现了进程调度函数,返回了进程调度中的一个当前进程任务的值
6、将断点设置在system_call处,发现是可以停止的,并且刚才的getuid_asm也返回了值。
由于getuid命令直接调用的sys_getuid系统调用例程,所以可以直接中断到相应的函数,但是getuid-asm直接使用的中断int 0x80.所以可以使用break sysenter_do_call。
五、总结
具体的系统调用与系统调用号绑定,然后都记载在一个系统调用表内,每次使用系统调用时都是通过这样的绑定关系,由系统调用号去找系统调用表然后查找到所对应的系统调用的位置。同理,中断处理过程也是一样的,它也是经由中断向量号作为索引去查表,然后执行相应的具体的中断处理程序去处理中断。内核将经常使用的和硬件交互的代码封装为服务例程,并且对用户提供系统调用表,只要知道相应的编号对应什么样的系统功能,就可以通过传入编号给eax寄存器,使用系统调用的中断号int0x80就可以的到想要的结果。进一步,甚至可以将自己的特定代码保存为内核例程,编译在内核中,随时供用户调用。
原文:https://www.cnblogs.com/sy308137/p/12967340.html