Linux内核调试
字数 1091 2025-08-25 22:59:03
Linux内核调试技术详解
0x00 前言
Linux内核调试是二进制安全研究的重要组成部分。由于不同Linux系统版本和内核版本中驱动模块和函数加载地址的差异,直接使用他人提供的exp往往无法成功利用漏洞。掌握内核调试技术对于内核漏洞分析和提权研究至关重要。
0x01 内核编译配置
调试内核首先需要准备特定版本的内核源码,可以从官方仓库获取所有历史版本。编译前需要进行正确的配置:
$ make menuconfig
关键配置项:
-
Kernel Hacking 部分:
Compile the kernel with debug info(必须选中)Compile the kernel with frame pointers(必须选中)KGDB: kernel debugging with remote gdb(选中并启用所有子选项)
-
Processor type and features 部分:
- 取消
Paravirtualized guest support
- 取消
-
Kernel Hacking 部分:
- 取消
Write protect kernel read-only data structures(否则无法使用软件断点)
- 取消
配置完成后执行:
$ make
$ make modules_install
$ make install
0x02 使用KVM和GDB调试内核
环境准备
- 检查CPU是否支持虚拟化:
$ grep vmx /proc/cpuinfo
- 安装必要组件:
$ sudo apt-get install kvm qemu libvirt-bin virtinst virt-manager virt-viewer
- 添加用户到相关组:
$ sudo adduser 用户名 kvm
$ sudo adduser 用户名 libvirtd
$ groups
- 启动服务:
$ sudo service libvirt-bin start
配置虚拟机
- 启动virt-manager:
$ gksudo virt-manager
- 添加GDB调试支持配置:
<qemu:commandline>
<qemu:arg value='-S'/>
<qemu:arg value='-gdb'/>
<qemu:arg value='tcp::1234'/>
</qemu:commandline>
调试步骤
- 主机端启动GDB:
$ gdb vmlinux
(gdb) target remote 127.0.0.1:1234
(gdb) b drv_open # 设置断点
(gdb) c # 继续执行
- 虚拟机中加载驱动模块:
$ insmod drv.ko
0x03 使用QEMU和GDB调试内核
更简单的方法是直接使用QEMU启动内核:
qemu-system-x86_64 -s -S -kernel arch/i386/boot/bzImage \
-hda /boot/initrd.img -append "root=/dev/hda" -gdb tcp::1234
参数说明:
-s:相当于-gdb tcp::1234的简写-S:启动时暂停CPU执行-kernel:指定内核镜像-hda:指定硬盘镜像-append:内核启动参数
无图形界面模式添加:
-nographic
GDB连接方式与KVM相同。
0x04 使用KDB和KGDB调试内核驱动模块
环境准备
-
准备两台VMware虚拟机(一台作为调试机,一台作为目标机)
-
配置串行端口:
- 删除并行端口
- 添加串行端口
- 一台设为客户端,一台设为服务端
-
测试串口连接:
- 客户机:
$ cat /dev/ttyS0- 目标机:
$ echo test > /dev/ttyS0
配置串口调试
修改/etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="... kgdboc=ttyS1,115200 text"
更新配置并重启:
$ update-grub
调试步骤
-
目标机:
- 加载驱动模块:
$ insmod drv.ko- 查看驱动基址:
$ dmesg或
$ cat /proc/modules | grep drv- 进入调试状态:
# echo g > /proc/sysrq-trigger -
客户机:
- 启动GDB并连接:
$ gdb vmlinux (gdb) target remote /dev/ttyS1- 加载符号文件并设置断点:
(gdb) add-symbol-file drv.ko 0xffffffffa0000000 (gdb) b device_ioctl (gdb) b device_open (gdb) c -
目标机运行测试程序触发断点:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drv.h"
#define DEVICE_PATH "/dev/vulndrv"
int main(int argc, char **argv) {
int fd;
struct drv_req req;
req.offset = atoll(argv[1]);
fd = open(DEVICE_PATH, O_RDONLY);
if (fd == -1) {
perror("open");
}
ioctl(fd, 0, &req);
return 0;
}